概要
ローカル通知について結構前に勉強したことがあった(リモート通知はどうすればいいのか知らなかった)のだが、
だいぶ忘れた状態で、リモート通知のコード見ててどういうことなの・・・・となって、
なるほどねとなるまでにかなり時間がかかったのでメモ
PUSH通知とは?
- PUSH通知はその発火トリガーによってローカル通知とリモート通知に分類されている。
- ローカル通知:発火トリガーがローカルのなにかの処理
- リモート通知:発火トリガーがFCMからのメッセージ受信
- PUSH通知の本質的な処理・・・すなわち「通知領域への表示」〜「通知タップ時の画面遷移処理」のやり方は全く同じ ←ここがわかってなかった
- なお、単純にPUSH通知という場合はリモート通知のことを指すことが多い。 ←さらにここでやられた
- FCMメッセージ送信=PUSH通知と捉えている記事が世にめちゃくちゃ多いが、コレ多分嘘で、ここが理解を妨げていたんだと思う。
Qiita記事とかでFirebaseからPUSH通知を送信!みたいな図をよく見かけてたせいで、完全にだまされた。 ←こいつが主原因!!!
Firebase公式でPUSH通知なんていう言葉出てこないもの。送るのはあくまでFCMメッセージだっていってるもの。
リモート通知の実装
デバイストークンの発行〜FCMメッセージが端末に届くまでの大まかなイメージ
AndroidのPush通知(FCM)をサーバー知識無しで試してみようのPush通知の「大体の仕組み」を参照。
※本記事では、上記の図で「固有ID」と呼ばれているものを「デバイストークン」、
「サーバー」と呼んでいるものを「アプリサーバー」と呼ぶことにする。
なお、公式ではデバイストークンは「registration token」と呼んでいる模様。
1. デバイストークンの取得とアプリサーバーへの登録処理
実装すべきこと
- アプリ側: FirebaseMessagingServiceを継承したクラスを定義し、このクラスにonNewToken(token: String)をオーバーライド(★)して、このメソッド内でアプリサーバーへデバイストークンを送信する処理を実装する
- アプリサーバー側: アプリから受け取ったデバイストークンを保存する処理(本記事はアプリ側を扱うので説明は割愛)
説明
FCM SDKをFCMメッセージを送信したい対象のアプリに導入すると、アプリ初回起動時に、FCM SDKがデバイストークンを発行し、Firebaseにアップロードしてくれる。
なお、これに限らずFirebaseはネット側との通信処理が走るため、FCM SDKのメソッドを叩く際には非同期であるべきらしい。
デバイストークンはアプリ初回起動時以外に以下のケースで新規発行されることもある。
- アプリが新しい端末上に復元された
- アプリがアンインストール/再インストールされた
- アプリ上のデータを削除した
上記のように「FCM SDKがデバイストークンを発行した時」には、FCM SDKによって★のメソッドがコールされるようになっている。
また、★のメソッドの引数tokenにはデバイストークンの文字列が格納されているので、★のメソッド内でアプリサーバーへ送信する処理を実装してやればよい。
なお、デバイストークンはonNewToken(token)メソッド内以外でも、FirebaseMessaging.getInstance().getToken()を実行することでアクセスできる。なお、存在しない場合は新規発行される。
・・・とはいえ、アプリ内でデバイストークンが必要になるタイミングは、デバイストークンが新規発行されてアプリサーバーへ送信したいときだけなので、onNewToken()内の実装だけで事足りそうだが・・・?
2. FCMメッセージが届いた後の処理
アプリがフォアグラウンドにあるときには、FirebaseMessagingServiceを継承したクラスのonMessageReceived()メソッドが呼ばれる。
アプリがバックグラウンド、または起動していない場合は、onMessageReceived()メソッドは呼ばれない。代わりに、通知センターにメッセージが表示され、この通知をタップしたときに起動されるインテントにFCMメッセージが渡される。
実装すべきこと
- アプリ側: FirebaseMessagingServiceを継承したクラスに以下メソッドをオーバーライドして実装
- onMessageReceived(remoteMessage: RemoteMessage) : FCMメッセージを受け取ったときの処理
- onMessageDeleted() : 「端末に配信されていないFCMメッセージが100件たまっているとき」「1ヶ月以上FCMとの接続がないとき」にコールされる。これを受けて何らかの処理をしたい場合には実装する。いらないならいらないでOK。
説明
onMessageReceived() については、
https://github.com/firebase/quickstart-android/blob/d20b5b4a7e226ff49bef2c20fe0cc01ff23b171a/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/kotlin/MyFirebaseMessagingService.kt#L26-L61
のコメントに実装すべきことが書いてある。
翻訳すると、
FCMメッセージに対する処理をonMessageReceived()で実装する。
onMessageReceived内でメッセージが取得できていないならば、その理由は
https://goo.gl/39bRNJ
にあるかもしれない。
メッセージがデータペイロード(※)を含むかチェック
長時間動くジョブによって処理される必要があるデータであるかチェック
長時間実行タスク(10秒以上)の場合はワークマネージャーを使う
そうでない場合は、10秒以内にメッセージを処理する
メッセージが通知ペイロードを含むかチェック
また、受け取ったFCMメッセージの結果として自身の通知の生成を意図する場合は、ここから始めるべきだ。
以下のsendNotificationメソッドを参照しろ。
remoteMesage.getData() で、FCMメッセージに含まれていたペイロードデータ(Map)を取得できる
※データペイロード
ヘッダを抜いたデータ本体のこと。httpレスポンスでいうところのbody。