Firebase Notificationでアプリの状態による挙動の違いについて

問題

Firebase Notificationを使ってメッセージの送信を行うと、Androidの場合、アプリがフォアグラウンドにあるかバックグラウンドにあるかによってその挙動が異なります。

まずFirebase Notificationを実装するためには、FirebaseMessagingServiceを拡張したServiceを用意する必要があります。そしてアプリがフォアグラウンドにある場合、このServiceのonMessageReceived()が呼び出されることになります。

一方、アプリがバックグラウンドにある場合はこのonMessageReceived()は呼ばれることはなく、システム側で自動的にシステムトレイに通知を表示します。

ある意味では便利なのでしょうが、通知のスタイルをカスタマイズしたりできませんし、受信したメッセージを自分でハンドリングできないのは困ります。

回避策

アプリがバックグラウンドの状態でも、メッセージ受信時にonMessageReceived()が呼び出されれば、アプリがフォアグラウンドにあるかバックグラウンドにあるかを気にする必要がなくなります。

送信されたメッセージにnotificationブロックが含まれず、dataブロックだけしかないものであれば、アプリの状態にかかわらずonMessageReceived()でメッセージを受け取ることができます。しかし、Firebase Consoleから送るメッセージでは、notificationブロックを省略することができません。

そのため、Firebase Consoleを使わずにCLIでメッセージを送信するしかないようです。

具体的にはこんな感じでメッセージを送信します。

curl https://fcm.googleapis.com/fcm/send -X POST \
--header "Authorization: key=FirebaseConsoleのプロジェクトの設定、クラウドメッセージングのタブにあるサーバーキー" \
--Header "Content-Type: application/json" \
 -d '
 {
   "to":"/topics/all",
   "data":{
     "title":"New Notification!",
     "body":"Test"
   },
   "priority":"high"
 }'

"to":"/topics/all"はご自分の環境に合わせて調整してください。私のサンプルプロジェクトではallというトピックをすべての端末で購読するように設定するようにしたのでこうなっています。

Firebase Consoleからメッセージを送信する場合、ユーザーセグメントを選択して自分のアプリパッケージを対象にメッセージを送信することができますが、CLIを使ってメッセージを送信する場合にはこれはできません。

ConsoleのNotificationとFCMの違い

NotificationsがFirebase Consoleから送るNotificationsで、Cloud MessagingがCLIで送るメッセージのことです。

Notifications: What's the difference between Notifications and Cloud Messaging?のところを見ていただければわかりますが、CLIの方ではユーザセグメントがサポートされていません。

そのためtopicsを使ってメッセージの送信を行っています。

dataブロックについて

"data"ブロックはConsoleからも含めることはできます(詳細オプションのカスタムデータで指定できる)。しかし、Consoleでは"notification"ブロックを省略することができません(メッセージ文を入力しないと送信できない)。

送信したメッセージに"data"ブロックがあっても、"notification"ブロックが存在する限り、アプリがバックグラウンドにある状態ではFirebaseMessagingServiceonMessageReceived()は呼ばれません。

システムによる自動ハンドリングが行われた場合、"data"ブロックの内容を受け取れないわけではありません。通知をクリックして起動したActivityのintentに含まれることになります。

しかしそれでは、"data"ブロックの内容の処理が、フォアグラウンド時に受け取ったときはFirebaseMessagingServiceで、バックグラウンドのときにはActivityでとなってしまって煩雑です。

アプリのプロセスが動いていないと受信できない問題

ちなみにメッセージが送信され端末に配信されたタイミングで、アプリのプロセスが動いていない場合にはメッセージを受信できません。その後にアプリを起動したとしても再配信もされません。メッセージが配信された際に、アプリのプロセスを起こしたりはしてくれないということです。

アプリのプロセスを強制終了したら、確実に受け取ることができません。例えば、端末の設定→アプリ→自分のアプリ→強制停止のボタンで終了するとか、Android StudioのメニューからRun→Stopするとか。

どうもこれはこういう仕様で諦めるしかないみたいです。

あくまでサーバを用意しなくてもpush通知ができるだけであって、メッセージが必ず端末に到達することを保証はできないということです。

参考

サンプルリポジトリ
https://github.com/gen0083/SampleFirebaseNotification

Mastering Firebase Notifications
https://medium.com/@Miqubel/mastering-firebase-notifications-36a3ffe57c41

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.