cordova-plugin-firebaseを使用したプッシュ通知
IonicのプロジェクトでFirebaseを利用したプッシュ通知周りを一通りやったのでまとめます。
今回プッシュ通知はFirebase NotificationでiOS/Androidともに実装するつもりだったのでいくつかあるfirebaseのcordovaプラグインを検討した結果、一番活発そうなcordova-plugin-firebaseを採用しました。
プッシュ通知はそれぞれGoogle/Appleのサーバが関係するためプッシュ通知の実装経験がない場合はFCM(Firebase Cloud Messaging)とAPNs(Apple Push Notification Service)について概要を調べてからcordovaでの実装を試したほうがわかりやすいです。FCMに関してはクロスプラットフォームになっているので以前のGCM(Google Cloude Messaing)のほうがわかりやすいかもしれません。
最初に機能実装として下記を見込んでます。
- サーバからスケジュールでプッシュ通知したい
- アプリの設定から各通知のON/OFFを設定したい
- ユーザの複数端末に対応したい
アプリ環境情報。サーバはRuby on Rails(5.2)です。
$ ionic info
Ionic:
ionic (Ionic CLI) : 4.1.1
Ionic Framework : ionic-angular 3.9.2
@ionic/app-scripts : 3.1.8
Cordova:
cordova (Cordova CLI) : 8.0.0
Cordova Platforms : android 7.1.1, ios 4.5.5
Cordova Plugins : cordova-plugin-ionic-keyboard 2.1.2, cordova-plugin-ionic-webview 1.2.1, (and 17 other plugins)
System:
Android SDK Tools : 26.1.1
ios-deploy : 1.9.2
ios-sim : 5.0.6
NodeJS : v8.9.4
npm : 5.6.0
OS : macOS High Sierra
Xcode : Xcode 9.4.1 Build version 9F2000Firebaseにプロジェクトを作ったあと各OSにアプリを登録します。
[Project Overviewの歯車] -> [プロジェクトの設定] -> [全般] -> [iOS|AndroidアプリにFirebaseを追加]追加後それぞれGoogleService-Info.plistとgoogle-services.jsonをダウンロードします。あとで証明書のフィンガープリントやStore IDを追加した場合は再ダウンロードしましょう。
プロジェクトのルートに各ファイルを配置します。ここでようやくcordova pluginコマンドでpluginを追加します。pluginの設定でcordova platformの追加時にplistとjsonファイルがiOSとAndroidプロジェクトにコピーされるようになっているので注意してください。経験上プラグインで困った場合はplatform rm後にplatform addしてエラーが再現するか確認したほうがいいです。
$ ionic cordova plugin add cordova-plugin-firebase
$ npm install --save @ionic-native/firebase
$ ionic cordova build ios
$ ionic cordova build android※厳密にはcordova prepare後にファイルコピー処理が走っています。cordova pluginは各プラグインがスクリプトで補完してることがあるのでビルドで問題が起きた場合はプラグインフォルダ内のplugin.xmlを読んで何をしているか調べると原因解明しやすいです
クライアント処理を書いていきます。クライアントでやることは以下の項目です。
- プッシュ通知の権限を取得
- プッシュ通知に利用するトークンを取得
- サーバから各端末にプッシュ通知できるようトークンをサーバに保存
- Firebaseのトピック機能で購読する
全体的にcordovaのFirebaseプラグインを利用する箇所になります。Firebaseのトピック機能は指定した文字列(サンプルではnews)を購読している端末全てに配信してくれるものになります。Firebaseのトピックは条件式のように複数指定(and|or|not)をできるので便利です。トピック機能を利用することでシンプルなものであればアプリのプッシュ通知設定はアプリだけで完結できます。
実際はデバイストークン/Registration IDはアプリアップデート時などのタイミングで更新されるのためトークン更新処理が追加で必要です。
アプリ側は以上になります。残りはサーバからプッシュ通知の配信です。なお、この時点でFirebaseのコンソール画面からCloud Messagingを使用して手動のプッシュ通知を行えます。アプリで受け取れるか確認しましょう。
次はサーバでの実装です。昔はFirebaseコンソールで表示されるトークンをつけてAPIにリクエストすれば利用できたようですが今はレガシーAPIとされているためFCM HTTP v1 APIを利用します。
まずiOSに配信するためにApple DeveloperからAPNs Auth Keyを生成してFirebaseに登録する必要があります。こちらはドキュメントにまとめられているので参照してください。記事によっては証明書でのやり方を紹介されてる場合がありますが証明書の更新が1年毎に必要になるのでプロダクションはAuth Keyを利用したほうがいいです。
Keyをダウンロード後にFirebaseコンソールからKeyを追加します。
[Project Overviewの歯車] -> [プロジェクトの設定] -> [クラウドメッセージング] iOSアプリの設定でダウンロードしたAPNs Auth Keyを追加しましょう。
その後サーバからFCMにリクエストするためにサービスアカウントの秘密鍵を取得します。サービスアカウントとは人が利用する目的ではなくアプリケーションのためのアカウントになります。サービスアカウント情報を使用してOAuth2の形式でGoogle API用のアクセストークンを取得します。概要を把握するのに下記記事が良かったです。
Firebaseコンソールでサーバ用の鍵をダウンロードします。
[Project Overviewの歯車] -> [プロジェクトの設定] -> [サービスアカウント] -> [新しい秘密鍵の生成]JSONファイルをダウンロードできます。JSON内の情報を利用してOAuth2認証をすることでFirebase APIのためのトークンを取得できます。
サーバコードに移る前にGoogle ConsoleでFirebase Cloud Messaging APIを有効なっているか確認しましょう。なっていなかったら有効にしましょう。
サーバの実装はFirebase Admin SDKを使うのが一番簡単です。SDKの言語で実装できる場合はそちらを使いましょう。Node.js/Java/Python/Goが用意されています。
それ以外の場合自前でOAuth2を利用した認証を書く形になります。GoogleでOAuth2用のクライアントは用意されています。Rubyはアルファなんですけどね…
今回はgoogle/google-auth-library-rubyを利用しました。以下RoRのサンプルコードです。faradayはAPIリクエストに使ってるだけなのでNet::HTTPでもなんでもいいです。
request_bodyがFirebaseに送るJSONです。本来アプリは開発とプロダクションでアプリIDを分けたほうがいいのでしょうが、面倒なので開発中はアプリでdebugトピックを購読しているものをプッシュ通知受け取るようにしてます(condition部分)。
コード上では先程ダウンロードした秘密鍵のJSONを利用していないのですが、各値を環境変数に登録しています。利用しているプロパティはtype/client_id/client_email/private_keyの4つです。これらをGOOGLE_ACCOUNT_TYPE/GOOGLE_CLIENT_ID/GOOGLE_CLIENT_EMAIL/GOOGLE_PRIVATE_KEYの環境変数名として登録することで暗黙的にgoogle-auth-library-rubyが利用してくれます。
request_bodyの部分で使用できるJSONキーと設定値はFirebaseドキュメントを参照してください。
またGoogleへのアクセストークン取得をgemなしでやる場合下記が参考になります。
https://gist.github.com/kenjij/a0f5ef5ad9c6beb74568da139b291480
この記事は実装終わってから思い出して書いているので抜けてることがあったらごめんなさい。
cordovaで考えられるトラブル
cordova-plugin-firebaseではAndroidプロジェクトにネイテイブのFirebaseライブラリを追加します。その際にFirebaseのライブラリバージョンで他プラグインと競合する場合があります(例: cordova-plugin-googleplus)。
cordovaのAndroidプロジェクトで他プラグインでも同じライブラリを利用しておりバージョン指定の違いによってビルドエラーが発生する、ということはよくあります。その場合自分でpluginをフォークしてバージョンを直したり、直接Androidプロジェクトでファイルを編集するまたはdpa99c/cordova-android-firebase-gradle-releaseプラグインを利用してバージョンを強制的に揃えるといった対応があります。開発体制で合わせて検証してみてください。
