Google Cloud MessagingでAndroidとiOSにプッシュ通知 前編

スマホアプリがWebアプリに対して持つ比類なきアドバンテージ、それはプッシュ通知です。
アプリが起動していないときでも、何かが起こったことをユーザーに知らせることができるプッシュ通知。まさに情報へのキャッチアップをいつでもどこでも可能とする仕掛けですが、これはスマホのOSとバックエンドのなかだちなしには実現ができません。
これはセキュリティの観点からも当然のことです。アプリを動かすスマホにアプリサーバーから直接通知を送信できてしまうと、その仕組みを悪用するアプリが必ず出てくるのが世のさだめ。その間にOSのバックエンドを介在させて、アプリサーバーから通知できる情報を制限し、そんな悪用を防ぐことができます。また、アプリ側としても、サーバーに保持するユーザーの端末情報を最小限に留めることができます。
そしてこのメリットは、逆に、プッシュ通知を送信する仕組みはOSに依存するというデメリットにもなるわけです。そもそもAndroidとiOSとでは開発言語からして異なるので、アプリ側の実装が変わるのは仕方がないのですが、通知を送るアプリサーバー側も、ユーザーが使う端末のOSによってプログラムを変えなければなりませんでした。

しかしこの話はもはや過去形です。既に、AmazonやニフティなどがMBaaS(Mobile Backend as a Service)として、アプリサーバーからの通知を適切に両OSのバックエンドに振り分けてくれる仕組みを提供していますし、また今年になってからGoogleが本気を出してきました。それが、新しいGCM(Google Clouod Messaging)です。

新しいGCM

新しいGCMは、これまでのAndroid専用の通知の仕組みをそのまま流用し、iOSへも通知を送ることができるようになりました。

これがかなり画期的なサービスなのです。

  1. AndroidとiOSとで異なる通知の表示の仕組みの両方にほぼ完全に対応
  2. 国際化対応も完全
  3. 通知を表示するコードをアプリ内に一切書く必要がない

特に3番目が重要です。iOSでは元々、通知の表示を行うロジックはデフォルトで不要です(自力で書くこともできます)が、Androidでは逆に、通知の表示はアプリが自力で行うことがデフォルトでした。その分きめ細かな表示の制御もできますが、アプリによって通知の出し方がまちまちになるという状況は、場合によってはOSの統一感を損なわせることにもなります。もちろん、「それがAndroid」という考え方もありますが、プログラマーにとっては、そういう部分はできるだけOS側に任せ、アプリ独自の工夫が必要なところに手をかけたいところです。

だがしかし、のAndroidクォリティー大炸裂を乗り越える

Android開発というと、厳しい審査を課されるiOSに対して、「作りたいものを自由に作れる」ようなイメージがあります。その点だけ見れば確かにそのとおりです。
しかし、Android開発には、それはそれは大変な苦労が、山ほどある、というのが実情です。
それを具体的に挙げていくとキリがないためここでは割愛しますが、今回の新しいGCMにおいても、理不尽な導入手順、ドキュメント化されていない諸々の仕様、ビルド設定を間違えたため古いiOSに対応できていないライブラリー、等々の問題に、頭を抱えざるを得ませんでした。
が、それらをすべて解決できた現在、新しいGCMはやっぱり使いやすい、と喜んでいるところです。

この便利さをみなさんと共有すべく、マイトで試行錯誤しつつたどりついたノウハウを、今回と次回の2回に分けて紹介します。

新しいGCMのここが罠 1) サービス設定

導入の手順はもちろん、公式に出ているとおりです(AndroidiOS swift)。

が、この通りに進めてもつまづくことがあります。
アプリの登録画面に情報を登録すると、AndroidではJSONファイルが、iOSではplistファイルがダウンロードできるようになりますが、その際に画面に表示されるAPIキーが、両OSで異なる場合があります。このAPIキーは、アプリサーバーからGCMサーバーへと通知要求を送る際の鍵になるものです。それがOSによって2種類出力されてくるのです。

gcm-register

このままではOSごとにキーを切り替えなければならなくなり、プッシュ通知を一本化できるという最大のメリットが失われてしまう! と焦りますが、なんのことはありません。最初に入力した App Name さえ合致していれば、2つのAPIキーのうちどちらを使っても、GCMサーバーは認証してくれます

なお、Android package name と iOS Bundle ID は、全く別のものでもかまいません。また、Android用JSONとiOS用plistは、それぞれ、別のAPIキーとともに出力されたファイルがそのまま利用できます。ご安心ください。

新しいGCMのここが罠 2) アプリサーバーのIPアドレス制限

さて、APIキーが発行されたら、できれば、そのキーが有効となるIPアドレス、すなわちアプリサーバーのIPアドレスで、呼び出し元制限をかけておきたいところです。

ですが、そのやり方がわかりません。

Google Developer Consoleでこれが設定できるのでは、と考え、認証情報の一覧画面を開きます。すると確かに、上で登録したAPIキーが一覧表示されています。
しかし、この画面から一歩も先に進めないのです。

google-console-1

理由は、上で登録したAPIキーに名前がつけられていないから。
実はAPIキーにはそれぞれ、人間が読みやすい名前をつけることができます。そしてそれをつけると、この画面の「名前」のところに、そのつけた名前とともに、個別の設定画面へのリンクが表示されるのです。そして、上で登録したAPIキーには名前がないため、リンクが存在しない扱いとなってしまいます。

これを解決するには、インデックス番号で直接、個別の設定画面を開きます。
https://console.developers.google.com/(中略)/apiui/credential が一覧画面のURLで、これに
/key/<index> をつけてアクセスしてください。1項目の場合は /key/0 、2項目ある場合は /key/0 と /key/1 になります。

google-console-2

これで、設定画面が開きますので、まずは名前をつけて、さらにアプリサーバーのIPアドレスを設定してください。

新しいGCMのここが罠 3) iOSライブラリーが設定ミス状態

新しいGCMは、iOS 7以降をサポート対象にしています。最新のサンプルコードでも、OSバージョンが8以上か7かで、変わったAPIを呼び分けるようになっています。
しかし、現在、CocoaPodsで配布されているライブラリーがさらに内部で呼び出しているモジュールがiOS 8.3向けにビルドされており、アプリに組み込むと大量のウォーニングが出力されます。このまま対象をiOS 7.1以上(Xcode 7での最低指定)として配布した場合に何が起こるか怖いため、現状、新しいGCMを使ったアプリはiOS8.3以上で配布するしかないという状況です。
Googleの開発陣はこの問題を認識しているようで、「次期リリース時に改修します」と宣言されていますが、そんなのんびりできることなのでしょうかこれは…。

私見ですが、Android開発陣には、とにかく新しい機能を提供することが最優先で、後方互換性は後から考えりゃいいや、的なノリをしばしば感じます。その分アプリ開発者は右往左往、七転八倒させられる、それがAndroid開発です(愚痴)。
というか、この件はAndroid開発ではなくiOS開発なんですが…。言語が違っても同じノリが繰り返されるというこれはもう、Googleの社風なのかもしれませんね。

次回は、実際に共通のプッシュ通知を両OSに送出するためのデータ構造、またアプリ側の実装についてまとめたいと思います。

Scalaエンジニアの求人