背景
本記事はあまりプログラミングのテクニック的な記述は出てきません。ご了承ください。ブログ的な読み物として見てもいいよ、という方はぜひ最後までお付き合いいただけると幸いです。
Googleが運営しているSNS、Google+が終わると知り、その使いやすさを雰囲気をなんとか再現してユーザーを救うため、開発したものです。
ウェブアプリ本体のサイト
G+Don
G+Donのgithubページです。実装やテクニック的には恥ずかしいものがいっぱいかも・・・
Github
G+Donの紹介用サイトです。
G+Donポータル
流れ:
- コンシューマ向けのGoogle+が閉鎖されることが発表になる。
- フォロワーさんからの流れで、pluspora、meweなどいくつかのSNSを試す
いずれもしっくりこない - その中でマストドンと出会う。マストドンは分散型で、APIの利用はTwitterとは比較にならないくらいゆるくて使いやすそうと知る。
- 個人開発でいくつかのウェブアプリをマテリアルデザインのライブラリ「Materialize」で作っていたこともあり、試しにGoogle+風のタイル表示のページを作成。チラ見せ。
- 意外にも反応あり。スキル的にもそれほど苦ではなかったので開発決定。
開発期間:
2018/10/01 ~ 2019/02/03 (約4ヶ月)
個人的な背景
開発するにあたり、個人的に開発・公開しているものです。
公開
-
PaintMeister
→PointerEventを使った筆圧検知ありのウェブ上のお絵かきアプリ。レイヤー対応・複数のブラシ対応。UWPでも公開。ChromeAppsが終了したりChromeがPointerEventのサポートなかなかしなかったりと苦難続出のため、次期バージョンを開発中だったが現在中断中。 -
ekscii
→今はなきFirefox OS用に作ったニュースアプリ。 -
TweeMeister
→Twitterでツイートすることに特化したアプリ。ウェブ版・ChromeApps版・UWP版があります。当初はTwitterとCroudia(今はなき)の複数アカウントに対応していましたが、Croudia部分を削除した後はマストドンに対応させました。
非公開
-
KakeiboMeister
→GoogleAppsScriptのウェブアプリ機能で作った家計簿アプリ。DBとしてスプレッドシートを使用。 -
Korpo
→GoogleAppsScriptのウェブアプリ機能で作った体重などの入力・分析アプリ。DBとしてスプレッドシートを使用。なにげにマテリアルデザインなウェブ開発初代アプリ。
開発環境の選定
Google+がマテリアルデザインということで、それ以外での実現はあり得ません。マテリアルデザインはMDLから始まり、Materializeにようやくかなり慣れてきていたため、Materializeを使うこと決定。
サーバサイドなどその他、初期の想定は次の通り。
スタイル・見た目: Materialize
サーバサイド: Python+Django
フレームワーク・クライアント: ど素のjavascript+いくつかのライブラリ(!)
初期の段階で恐ろしいのは、素のjavascriptとDOM操作でやろうと"なんとなく"考えていた 点でした。
序盤
出発
Google+は2011年くらいから使っているいわゆる古参でヘビーユーザーです。最新のGoogle+は好きになれない表示もあったのでいつの時点のGoogle+を再現するかを考えましたが、正直なところGoogle先生は細かくいろいろ変え過ぎなので、覚えていませんでした。
というわけでひとまず最新のGoogle+を目指すことに。
とはいえ完全にそっくりにしないでも、嫌いな部分は独自の表示にすればよいと判断しました。
見た目のサンプルを作るために調べたのは、Google+のあの敷き詰められたタイル風のストリーム(タイムライン)をどう実現するか。
検索キーワード:
javascript ライブラリ タイル
javascript ライブラリ グリッド
いくつかドンピシャリなライブラリを見つけました。しかしライブラリを使うと、Google+のようなSNSを実現するにあたり動的に変化する投稿の量を果たして捌ききれるのか不安がよぎりました。どのライブラリも、予め決められた数の内容をタイル風・グリッド風にするというものばかりでした。
それに依存しすぎるのもどうかと感じ、何か良い方法がないかさらに調べました。
CSS display:grid との出会い
まさかCSS標準で実現できる設定があるとは思いませんでした。素のCSSで実現できるならSNSとしての速度も犠牲になることはないと判断に至りました。
display:gridに関してMDNなどを見て試行錯誤し、サンプルを作り上げました。パッと見た目の雰囲気はGoogle+そのものと思えるものが実現できたので、これはイケると確信。
開発を本格的に進めることにしました。
Google+とマストドンの違いを知る
土台の実装が現実的になったとわかり、次はGoogle+の各機能をマストドンで果たして実現できるのかを調べることでした。
もともとマストドンは少し前から使い始めていました。(Twitterがいろいろ制限や制約が厳しくなってきており、移行先としてmstdn.jpを考えていたので)
マストドンは文字数が500文字まで、公開範囲がある、インスタンスと呼ばれる運営者(団体)のサーバが複数あり、どこに登録しても他のインスタンスのユーザーの投稿は見られるなど、違いはかなりわかりやすいです。
実際の印象としてはTwitterに似ているというよりもむしろGoogle+に近いでしょう。(特に投稿の公開範囲などの仕様)
公開範囲というのは、Twitterしかやったことのない人は新鮮でしょう。あちらも一応ロックを掛けてフォローを承認制にすることで公開範囲を絞れます。ダイレクトメッセージもありますが、いずれもあまりにも極端です。
Google+は「一般公開」、サークルのみ(フォローしている人をグルーピングする機能)、あなたの友達の友達、個別のユーザー指定と、細かくできました。
一方でマストドンは一般公開、未収載、フォロワー限定、ダイレクトメッセージと4種類です。(詳細は専用の解説をしているサイトに譲ります)
投稿に添付できる内容として写真や動画などのメディアファイルがあります。これは今どきのSNSであれば当然の存在です。Google+では他にもGoogleドライブからファイル、位置情報、アンケートと様々です。Twitterにも位置情報やアンケートはあります。
しかし、マストドンにはメディアファイルしかありません。最低限のものしかありませんが、改めて考えるとむしろこれで十分でしょう。
それからGoogle+にはサークルというフォローした人のグルーピング機能があります。サークルというのは公開範囲としても使えるし、サークル内のユーザーのみの投稿を見られるストリーム(タイムライン)としても使えます。
これはTwitterにもマストドンにもありません。絞ったユーザーのみのタイムラインという点では両者にはリストという機能があります。しかしこれは公開範囲としては使えません。
この点も、これから開発を進める上で考慮しなければならない点でした。
Google+にはコミュニティという機能もあります。同じ趣味目的で集まって交流できる機能です。さすがにこれはTwitter・マストドンには近い機能すらありません。これはマストドンの公式に期待するのは無理でしょうし、特に必須な機能でもないのでおいおい独自機能として実装すればいいと考えました。
マストドンのAPIを知る
マストドンのAPIを知ることもかかせません。これは上記違いを知る作業と同時並行で進めていました。APIに関しては「TweeMeister」の開発でTwitter、CroudiaそれぞれのAPIを調べていたのでマストドンのAPIについてもそれほど苦はなく調べ始めることができました。
Using the API - tootesuite/documentation
APIに関しては正直、Google+、Twitterいずれよりはるかに制限がゆるく扱いやすいという印象でした。開発者としてはすごく助かります。
ただ、マストドンはインスタンス(サーバー)が存在します。Twitterと同じ感覚であるインスタンスでアプリの作成をして普通に使っても、よそのインスタンスではまったく意味がありません。
そういうときのためにAPIではインスタンスに応じてアプリの作成をユーザー側で自動的にできるものが揃っています。
これにより、複数のインスタンス(サーバー)を利用する場合でも同じアプリを使用してもらうことが可能だとわかりました。わざわざ自分が複数のインスタンス(サーバー)にアプリを登録して・・・という面倒くさいことはしなくて済みます。
ユーザーの認証についてはOAuth2です。Twitterが未だにOAuthが主流なのに比べると、しっかり最近の主流に則っています。
いざAPIを使うとしても、素のFetch APIやjQuery.ajaxなどで通信するのは馬鹿らしいものです。素直に各言語用のAPIのライブラリを使いましょう。これもまた、APIのドキュメントに乗っています。
List of libraries - document/Libraries
APIをどこで実行するかは重要でした。サーバ側で実行するとなると、それは運用環境の決定にも大きく影響します。当初はサーバサイドはPython/Djangoを使おうとしていましたが環境への依存の影響を考え、APIの実行はクライアント側でさせることにしました。
よってJavaScript (Browser)のmastodon.jsを使用することに決めました。
運用環境の決定
いくつか候補がありました。
- Microsoft Azure
- Firebase
- Heroku
- etc...
個人的にMicrosoft Azureに加入していたため、そこを使おうと考えました。他には皆さんおなじみのFirebaseもかなり深く考えていましたが、Pythonでやろうとしていたために候補からは外れました。
AzureにはAppServiceで無料枠のF1がありますが、さすがにそれを運用環境として使うのはまずいなと思いました。一つ上のD1は制限がゆるくなりますがそれでもクォーターがあり、何人使うかわからないウェブアプリとしては不適切なプランと判断。
最終的に、運用環境としてはB1を目指すことにしました。これならAシリーズと同等の性能だし、独自ドメインとSSLも取れるし他にも諸々盛りだくさんです。
価格はD1の1100円付近から大きく膨れ上がって6800~7000円台とすごいことになります。価格の面ではFirebaseやHerokuのほうが、3000~4000円台というまさに欲しい価格帯がどうやらありそうだということがわかりました。
でも結局は自分が一番長く使っていてわかってるAzureから離れる気はありませんでした。
ということで、最終的にはB1を目指しまずはF1で環境を作り、そこをテスト環境として活用することに決めました。
中盤
ひたすらGoogle+とマストドンを比べる(+Twitter)
Google+の特徴でもあるタイル風のストリーム(タイムライン)の現実味が高まったので、後はひたすら必要な画面と機能を作り込んでいきます。
- タイムラインを表示する画面
- プロフィールを表示する画面(ページ)
- フォロー・フォロワーを表示する画面
- 投稿する画面
最大のポイントであるタイムラインのベースは作りましたが、Google+のストリームを細かく見ていくと、実装しなければならない機能や表示のポイントが沢山あります。
- 本文
- 投稿者の名前とアバター画像
- 投稿日付
- 画像や動画
- リンク先のプレビュー
- 投稿への返信(コメント)
Google+で もう一つポイントなのが返信 です。これを実現する条件は次の3つでした。
- 元の投稿のぶら下がって表示される
- 返信は単独でストリームに流れてこない(再共有された場合は別)
- 常に何件か見えている(クリックすると全部表示される)
Twitterではツイートをクリックして開くと表示が切り替わり、初めて見られるものです。マストドンもまた、似たような挙動です。ただマストドンの場合、TweetDeckというTwitterのアプリに似た表示のため、元のタイムラインを隠すことなくその投稿と返信が見られるのが特徴です。
Google+はストリームがタイル風に敷き詰められ、各投稿にコメントがぶら下がっていることで、まるでそこかしこに人の集まりがあり、会話が弾んでいる感じに見えます。(個人的に)
きっとそういう見た目からくる雰囲気・居心地の良さがSNSとしてGoogle+を選択した人たちが感じる魅力なのでしょう。
そう確信し、実装を進めました。
見た目と機能の限界
ここまで、素のHTML+javascript+DOMで作っていました。サーバサイドはPython/Djangoのため、Djangoのテンプレートを活用していました。
サーバサイド:Python/Django
↓
テンプレート言語(base.html + [各ページのHTML].html)
↓
クライアントサイド:HTML/CSS/javascript + Materialize
Materializeで表示と一部コントロールは楽に実装できているものの、これまで document.body.appendChild だの replaceChild だの insertだの素のDOM操作を使って非常に泥臭い実装をしていました。
ある時気づきました。投稿の表示部分一つ作るにしてもDOM操作のコードがガンガン増えて収拾がつかないと。(実は createDocumentFragment すら知らなかったので)
つまりメンテしきれなくなったのです。
Vue.js, Vuetify.jsとの出会い
フレームワークを使わないとこれはダメだという結論にいたり、いざ探し始めました。すぐに見つかったのはもはや有名すぎるこれらです。
- React
- Angular
- Vue.js
サーバ側は引き続きPython/Djangoで行くため、クライアント側のフレームワークの選定に入りました。
いずれも便利そうなのですが、中でもポイントとして気に入ったのは Vue.js でした。
- 既存のコードを排除することなく溶け込ませて使うことができる
Vue.js以外はどうやら一から作り込む必要があるくらいフレームワークとして強く一体化しているとのことで、残念ながら利用を諦めました。
早速Vue.jsを試し始めました。
加速する実装
Vue.jsは「双方向データバインディング」に特化したものらしく、なおかつ仕組みがシンプルで学習コストが低いのが特徴とのことです。公式サイトのドキュメントだけでも十分らしいのですが、自分は念の為解説本を買って勉強し始めした。
今までDOM操作で例えば次のようにしていたものが置き換えられていきます。
<!-- 今まで -->
<div class="toot-timeline">
<!-- ここにトゥート(投稿)のカード(要素)を入れる -->
</div>
<!-- Vue.js導入後 -->
<div class="toot-timeline">
<div class="tootcard" v-for="item in toot" v-key="item.id">
<img v-bind:src="imgpath" class="avatar-img">
<span>{{username}}</span>
...
</div>
</div>
//---今まで
var timeline = document.querySelector("div.toot-timeline");
for (var i = 0; i < toot.length; i++) {
var div = GEN("div");
//GENはdocument.createElementへのショートカットとして別に用意
var img = GEN("img");
img.src = "hoge/pic.jpg";
var username = GEN("span");
username.textContent = "hoge";
...
timeline.appendChild(div);
}
//---Vue.jsを導入後
var vue_timelnie = new Vue({
el : ".toot-timeline",
data : function () {
return {
toot : [],
};
},
methods : {
generate_timeline : generate_timeline,
}
});
/*
API呼び出しで取得
*/
function generate_timeline(option) {
callAPI("hoge")
.then(result => {
this.toot = result;
});
}
本格的な解説はVue.jsを扱う別の記事にお願いするとして、便利なポイントは次のものです。
- DOM操作をコーディングしないでも、変数に値を挿れたらHTMLの内容が書き換わる
- HTML上で条件分岐や繰り返しが使える
この2つが使えるだけで、今までのDOM操作のコードは一気に消滅しました。その結果、初期に作っていた画面を制御するためのコードはスッキリしました。
- javascriptのコードは純粋にアプリの機能に関するコードのみになった
- 画面で条件別に表示が変わる内容についてはHTML側にコードが移った
Vue.jsを導入したことで画面要素に関わる定義はHTMLに集約され、javascriptはアプリとして実現したい機能に集中できるようになりました。
イベントハンドラもHTML側に記述することになります。賛否両論あるらしいですが、自分はVue.jsの作法、好きです。
Vue.jsを導入したおかげで、アプリとしての構造が今までの泥臭い独自クラスやグローバルオブジェクトによるものから、Vueオブジェクトに変わっていきました。
とはいってもすべて変わったわけではありません。各画面共通の画面パーツや各画面固有の画面パーツがVueオブジェクトに変わりましたが、それらを管理する独自のクラスはそのまま活用できました。
マテリアルデザインも変わる
Vue.jsを導入してもしばらくは見た目まわりはMaterializeで作成していました。しかし、Vue.jsのライフタイムサイクルとMaterializeのjavascriptコントロールのタイミングが合わないことがわかり、その調整に四苦八苦し始めました。
そこで出会ったのが Vuetify です。 Vue.jsで使える見た目周りのライブラリは他にもElementsなど見つけたのですが、次のポイントで惹かれて導入しました。
- ドキュメントが充実している(日本語)
- Codepen等によるサンプル実行環境が充実している
特にサンプルが一番気に入った点です。
Vue.jsによるアプリの基本構造を見た時、あまりにも素のHTML/javascriptとはかけ離れて独自のものに感じ一度はやめようと思ったものの、Vuetifyのサンプルを見ると従来のHTML・javascriptな記述でも利用できるということがわかりました。古いWebの手法からなかなか抜け出せない自分にとってはこれはすごく大きなポイントです。
VuetifyとMaterializeを併用してしまうことに
ここで完全にVuetifyに切り替えられればよかったのですが、開発も中盤に差し掛かり、だいぶMaterializeの影響下にありました。そのため、いざVuetifyを使おうとしても、すべて切り替えるのはとても無理でした。
その結果併用が進み画面が次の状態になりました。
Materialize影響下のコントロール → ページ表示とともに瞬時に描画完了
Vuetify影響下のコントロール → ワンテンポ遅れて描画完了
VuetifyのUIコンポーネント等の描画の遅れが異常に目立つようになってしまったのです。これは独自のタグを使い、実際には置き換え(≒コンパイル)しているVuetifyの関係上、どうも回避できないもののようでした。
すべてVuetifyでページを作ることができれば、描画の遅さは実際にはあれど統一されているためにうっかり見せなくて済むのでしょう。
併用した結果、Vuetifyの本来の描画の遅さを知ってしまったため、この回避のための工夫は公開からだいぶ経った現在でも続いています。
サーバ側、Node.jsへの変更を決断
アプリの必要な画面はほぼできあがりつつある段階でそろそろ本番運用用のサーバにアップしてテストを始める段階に差し掛かったと判断しました。
使うのはAzureのAppServiceで、一度非公開のアプリ開発で使ったこともあり、Python/Djangoによる構築は慣れたものでした。しかし世間を見るとNode.js/express+αがどうも多いということを知りました。
URLのルーティングやテンプレートが標準でワンセットで利用できるDjangoは大変魅力的でしたが、もし将来Azureをやめて別のホスティング先にするとなった時にPython/Djangoを安定して利用可能なサービスがあるのか不安になってきました。
Node.jsに切り替えれば選択肢は多すぎるという意味で悩むことができる。そう考えて保険のためにもNode.js/expressでも作ることを決めました。
Node.js/expressでプロジェクトを作り直す
一から作るもアホらしいので、Visual Studioのプロジェクトで、Express製のウェブアプリプロジェクトを選び、再出発です。
Python/Djangoの頃と比べ、ようは次のことができればよいと整理をはじめました。
- URLのルーティング
- 独自のREST APIをそのまま再現できるか
- テンプレートエンジンはDjangoと同じものが使えるか
ルーティングはDjangoの巧妙な手法が結構気に入っていました。それはexpressの標準的な機能と記述方法で満足できるレベルで実現・移行できることがわかりました。
独自のAPI処理についても、Node.js/expressでのjavascriptのコーディングの標準の範疇でできることがわかったため、ロジックの組み方のみ少々Pythonから変更することで事なきを得ます。
特に問題だったのは、3つ目のテンプレートです。
テンプレートエンジン探し
せっかくDjango標準のテンプレートでかなり作り込んだのに、それを活かせないのは辛いものです。しかしNode.js界隈のテンプレートの流儀に従い作り直すことも視野に含めました。
こちらのページなどを参考にし、テンプレートエンジンを評価し始めました。
- ejs
- Hogan.js
- Mustache
- Handlebars
最初はejsにしようと思い、すでに作成済みのテンプレートHTMLを置き換えてみました。問題なくイケることはイケましたが、どうにもしっくりこない。そしていまさらすべてのページのテンプレートを変えるには、テンプレートエンジンの仕様も考えて作り直さなければならないことがわかりました。
上記で上がった候補はいずれも条件的に厳しいものがありました。そこで出会ったのが次のテンプレートエンジンです。
こいつはPythonのテンプレートエンジンJinja2を参考したものらしく、Djangoのテンプレートエンジンの記述とまったく同じ利用ができることがわかりました。
それもそのはず。だって大本が同じなんだから!
というわけで、テンプレートエンジンはNunjucksに即決。今まで作り込んだテンプレートHTMLを一切変更することなくそのまま利用して開発続行しました。
Node.js/expressにした結果、アプリのホスティング先の選択肢がグンと増えたとともに嬉しいのは、サーバ側の速度が明らかに向上したことでした。さすが開発スピードが早いNode.jsやで・・・と感心と感謝を感じます。
終盤
AzureのAppServiceの設定を始める
サーバ側をPythonからNode.js/expressに切り替えたことで、AppServiceの方もPythonを一旦無効化しました。そうしないとPython/Djangoの枠組みが生きてしまい、Node.jsなど他のものが利用できなくなるためです。
Node.jsを使うためには、AppServiceの「アプリケーション設定」の「アプリケーション設定」の欄で次の定義を追加する必要があります。
WEBSITE_NODE_DEFAULT_VERSION = 10.6.0
実際にこのように記述できるわけではありません。あくまでこの記事的に見やすく表記しています。
「アプリ設定名」の欄に"WEBSITE_NODE_DEFAULT_VERSION"を、
「値」の欄に"10.6.0"を指定します。
これによりAppServiceで可動させるNode.jsのバージョンを指定することができます。このバージョンは開発で使っているNode.jsのバージョンと極力同じにする必要があります。最初から開発していれば、AppServiceで指定可能なバージョンを見据えてローカルのNode.jsのバージョンを固定して進めるやり方がよいのでしょう。
自分の場合、特にNode.jsで最新すぎるECMSscriptの仕様を使っているわけではないので問題ありませんでした。
AppService上での動作を確認する
AzureのAppServiceをホスティング先として利用する場合、Visual Studioでリリースするようにすると非常に楽です。同ツールの「発行」を選び、AppServiceの実際の利用アプリ(プラン)を選べば、新規の場合はソース全部、更新の場合は前回の更新と比べてアップロードが必要なソースのみ自動的に判別してアップロードしてくれるのです。
Visual Studioの発行機能を使い、サクッとアップロードしました。
動作速度としては、FreeのF1でも意外と思ったほど遅くありませんでした。ただし、制限がきつすぎる。クォーターが厳しすぎるのです。一つ上のD1にすると有料にはなりますがゆるくなります。そして動作速度もやや向上。
この分であればB1は間違いなく速度には問題ないだろうと踏みました。
マストドンの認証情報をクラウドに保存する
ここで別に進行していた開発に戻ります。付加価値的な機能として、G+Donではマストドンサーバーの認証情報をGoogleドライブに保存し、別の端末ですぐに復元できる機能が実装されています。
その機能を開発するため、Google DriveのREST APIの資料を見つつ、実装を進めていました。
他に参考にしたのは次の記事等です。
Google Drive Apiでファイル取得する(Javascriptで)
JavaScript で Google Drive を読み書き
Googleドライブが使えれば、アプリをさらに便利に活用してもらうことができます。実装自体は特に問題なく進めることができました。
ここで問題になるのは、ユーザーに安心してGoogle認証してもらうため、 ドメインを取得 しなおかつGoogle Cloud ConsoleからAPIのスコープを使用するドメイン確認と承認をしてもらう必要がある点です。
これをしないと、Google認証時にユーザーには「Googleから認証されていない」アプリとして表示されてしまいます。信頼してもらえません。
ドメインを取得する
ドメインの取得は初めてなので、何をどうすればいいのかまったくわかりませんでした。
いろいろドメイン取得サービスを検討しましたが、AzureではAppServiceのプランを上げることで、ドメイン取得から管理までやってくれることがわかりました。
AppServiceの設定項目内の「カスタムドメイン」がそれです。
ドメイン取得に関しては次の記事などを参照しました。
Azure Active Directory ポータルを使用してカスタム ドメイン名を追加する
Azureでドメインを購入する
どのみちドメインは取得する予定のため、規定の開発スケジュール路線でした。この時点で12月中旬でした。
SSLを設定する
ドメインと合わせてやらなければいけないことが、SSLの設定です。
これに関しては次の記事などを参考にしました。
Azure App Service の SSL 証明書を購入して構成する
Let's Encriptも考えて試しましたが、そのいくつかの記事通りにやっても最後の最後でエラーになってしまい、結局できずじまいでした。
変に無料に固執してわからないまま設定を破壊してしまうくらいなら、年間7000円ほどかかっても開発者として・ユーザーとしても安心を金で買って楽をしようと決めました。Azureの標準サービスで購入できる証明書なら、いろいろ安心できるというものです。
これをする前にLet's EncryptのためにAzure Active Directoryなどいろいろいじってしまったため、一旦各設定を戻してから正規にSSLを購入・設定と進めて事なきを得ました。
ドメイン稼働確認
Azureでは ****.azurewebsites.netというURLが標準で割り当てられます。しかもhttpsです。独自ドメインにこだわらないのであれば、この標準のURLでいいのでしょう。しかしこの世の中のウェブアプリで、そうしたサービス標準のURL丸出しのウェブアプリがあるだろうか?いやない。(反語)
やはりドメインはとっておいたほうが何かとよいのでしょう。自分の場合も世間の例にもれず無事ドメインを取得しました。AzureのAppServiceのURLの欄には、「gplusdon.net」が「gplusdon.azurewebsites.net」の代わりに表示されるようになりました。
ドメインを取得し、Azure AppService上でも書き換えが確認できたので、いよいよ今度はGoogleへのドメイン確認の申請です。この時点で年末、アプリの機能はほぼ出来上がり、ひとまず使う分には問題ないレベルでした。
GoogleにOAuth画面のためのドメイン確認を依頼する
G+DonではGoogle DriveのAPIとスコープを使うようにしてます。
GoogleAPIを使い、ユーザーにログインしてもらうための権限の許可や同意画面を表示できるようにしなければなりません。
※これには承認が必要なAPIとスコープがあり、それらが不要なAPIとスコープを使う場合、この申請は簡潔に済むものと思われます。
これはGoogle Cloud Platformの自分のプロジェクトで「APIとサービス」の「認証情報」から申請することができます。
メニューをたどっていったら、「OAuth同意画面」を開きます。
- アプリケーション名
- Google APIのスコープ
- 承認済みドメイン
- アプリケーションプライバシーポリシーのリンクなど各リンク
これらを入力して、よければ最後に送信します。
特に問題ないだろうと軽い気持ちで考えていましたが、この申請と確認、想像だにしないやりとりが待っていたのです。
Google Cloud Platformとの英文でのやりとり
しばらくしてGoogleからメールが届きました。OAuth同意画面の申請についてあれこれ
プライバシーポリシーのリンクに関する指摘でした。当初はGoogleドキュメントに記載し、そのリンクを使おうとしていたのです、それはダメだと怒られました。
公開するアプリケーションのドメイン内に プライバシーポリシーや規約のページを作り、URLを用意しないといけないことがわかりました。
この指摘を皮切りに、計17通ものやりとりに至りました。その指摘と対応方法は次のとおりです。
プライバシーポリシーはあなたのサイトのドメインと違う場所に置いたらダメ!
GoogleドキュメントからHTMLにエクスポートし、そのページを自ドメインのURLで用意して解決。
ドメインの確認:APIで指定しているドメインはすべて書け!
APIキーでHTTPリファラとしてドメインを指定している場合、それらをすべて「承認済みドメイン」に記載することで解決。
一貫性のないブランディング:アプリケーション名が違う!
プロジェクト作成時に指定した名前とは違う名前をアプリケーション名にしようとかんがえていました。(もともとが仮でつけた適当な名前)
しかし、アプリケーション名はプロジェクト名と完全に一致する必要がありました。結果、G+Donなのに、当初適当につけた「gplus-mastodon-webclient」という名前で通さざるを得ませんでした。
これがなかなか理解と納得できず、ここで何度かやり取りしました。
ユーザーがアクセスしたときの理由がきちんと書かれていない
これは申請時の「スコープの理由」が問題でした。申請のための文章ではなく、ユーザーが見る可能性を考えてスコープと機能と権限を懇切丁寧な説明文章で書かなければいけませんでした。
ようは、箇条書きなどではダメということ。
あなたのドメイン配下でのアプリで、GoogleAPIを使うシーンをビデオに録ってYouTubeに掲載しろ
テスト用のGoogleアカウントとアプリ内で使うアカウントがあればそのユーザーIDとパスワードを教えろ
アプリでGoogleにOAuth認証をするためのテスト用のGoogleアカウントをこちらで作り、Googleにパスワードとともに教える必要がありました。そしてさらにOAuth認証や実際にAPIを使っているシーンを動画に記録し、YouTubeにアップロードするがありました。
凄まじく面倒臭かったです。Googleアカウントくらい、自分たちで用意してほしかったです。
そしてG+Donはマストドンを使うアプリです。さすがにこればっかりはこちらが用意しないといけないことくらいはわかります。マストドンのテストアカウントも作成し、そのユーザーIDとパスワードもGoogleに教えました。
ビデオは英語で録画しろ
凄まじくよけいなお世話です。口頭で英語のナレーションなんか無理だったので、字幕で対応しました。
高解像度で録画しろ
凄まじくよけいなお世話です。
アプリケーションのクライアントIDをきちんと写せ
GoogleへのOAUth認証画面のウィンドウのURL部分にあるクライアントIDを、高解像度できちんと動画に写し込む必要がありました。
順次対応していき、ようやくGoogleからOKがもらえました。OAuth認証画面で、確認されていない云々という表示は消え、正式な確認という後ろ盾がついたので一安心です。
ただ、このやり取りは本当に苦労しました。どうも半分自動的になっているようで、日本語で教えてくれなどと書いても一切反応ありませんでした。英語しか受け付けない・余計な質問は受け付けない、淡々としたやりとりが求められるようです。
今後Google Cloud PlatformでOAuth同意画面のドメイン確認の申請をされる方がいらっしゃった場合、この章がお役に立てることを切に願うばかりです。
公開
Googleとのやりとりで1/20付近~2/2まで費やしました。GoogleからのOKを待ってから公開と決めていたため、それまでに本アプリとしての必要機能はすべて確認取れていたため、後は実際に公開する日を定めて各SNSで告知するのみとなりました。
告知
2/3 19:10、Google+で公開しました。
単純な新SNSというわけではなく、マストドンのアカウントが必要なアプリという立ち位置のため、慣れない人にとっては利用開始までの敷居があったようで、いくつか問い合わせ等を受けることとなりましたが、幸いにも問題なく利用できた方々の暗なるサポートがありなんとか船出としては事なきを得ました。
あとは宣伝や今後のメンテナンスをどうするかをしっかり考えて行動に移すだけです。
公開後の問題点
公開後、想定せぬ使い方による不具合や、フレームワークを過信しすぎたために起きかけた問題がありました。元々のマストドンユーザーでこっそりと教えてくださった方もいて、なんとか問題が広がらずに修正対応をすることができました。
また、あまりにGoogle+を目指しすぎ、元々のマストドンユーザーに優しくない実装もあったため、それらの解決も課題として上がり、対応に迫られました。盲目的になっていた点は反省すべき点でした。
現状と今後
Google+からの移行はMeWeやTwitter、人によってはSNS自体やめるという選択肢を取ることもあったようで、マストドン、しかもマストドンを利用するための一アプリに過ぎないG+Donを使い続けてくれる人はほとんどいませんでした。
単純に自分の宣伝不足、人脈のなさもあるのでしょうが、利用の手間があるのも問題でしょう。
しかし何よりも問題なのは、ツールとしてのSNSではなく、人の流れを見極められるかどうかでした。
結局ツールとしてGoogle+を再現できても、マストドンの各サーバーにGoogle+ユーザーを引き込めなければ、Google+の雰囲気と交流の様子を再現できたとは言えません。
結果として人づてに広まり自然な流れでMeWeが選ばれたようです。そうなるとそれはそれで肩の荷が下りた思いです。
終わりに
一度開発し公開した以上、そして少なからず使ってくれている人がいる以上はやめる気はありません。
Google+の雰囲気と全体的な使い勝手の再現という名目ではありますが、不満があった点の解消や独自実装による今後の拡張も方針としてあります。タイムラインの完全な再現だけでは全体のユーザー体験を統一できません。完全を目指すよりも、G+が終わった後のアプリとしての使い勝手の向上も踏まえてほどほどの再現とG+を超える使いやすさを目指すべきだと考えています。
完全な再現だけを目指すと、その先にあるのはそれを達成してしまったらモチベーションが保てずアプリの将来の展開も見込めぬプロジェクトになるのは明白です。
G+DonはGoogle+に目指してほしかったSNSとしての形を目指す方向性で、今後も開発とメンテを続けていきたいと考えています。
○ヶ月でサービスを公開したという記事を見たことはありますがまさか自分が体験するとこれだけいろいろ必要なことがあるのかと思い知ったので、いろいろ収穫のあった4ヶ月でした。
技術ブログではなくなってしまいましたが、最後までお読みいただけて光栄です。個々のテクニックや技術は別記事で今後まとめることも考えています。