Android

Androidで端末にPushメッセージ(FCM)が届かない問題

今、自分が会社で作っているアプリはPush通知が届かないとサービスが成り立たない重要な通知となっております。
基本的にFirebase Cloud Messaging(FCM)を使っています。
定期的にというわけではないのですが、Push通知が届かないという問い合わせが何度かあり調査しました。

Firebase Cloud Messagingの詳細

Androidアプリを使っているアプリで通知を実装する場合、ほとんどFCMを使うと思います。
こちらのページに詳細が記載されています。
FCM メッセージについて

よく使う設定を簡単に説明したいと思います。

通知の種類

FCMのメッセージは2つあってデータメッセージしか使っていません。
データメッセージはアプリで通知を受けて、メッセージに含まれる内容を元に端末にNotification(通知)を出すとかそういう用途に使うと思われます。

優先度

優先度も現在2つあります。
使い分けは極論になりますが、遅延してよいかどうかで決めると思われます。
特徴として、優先度をにすると端末がDozeモードの場合もPush通知が行われます。

  • 優先度:通常
    • 遅延してもよい
    • お知らせなど少し遅延しても問題ない場合に使う
  • 優先度:高
    • 遅延してはいけない
    • スケジュールの通知など遅延すると意味がない場合に使う

ここで注意が必要なのは、大は小を兼ねる的な感覚で常に優先度:高にしとけばいいじゃない?と思わないことです。
Android9以降導入されたアプリ・スタンバイ・バケットの設定により、優先度:高のメッセージを受信できる回数に制限が行われる場合があります。
Power management restrictions

遅延しても良いものは遅延させるように適切に優先度を設定する必要があります。

有効期限

メッセージの有効期限です。
例えば有効期限を1日にしていた場合、メッセージ送信時に端末が電源を落としていたなどでPush通知を受け取れない場合も有効期限内に受け取れる環境になれば再送されます。

有効期限を0にした場合

有効期限を0にした場合ですが、FCM内で遅延が最小(ベストエフォート)になるという優遇があります。
その代わり再送は行われません。
Push通知を送信したその瞬間しか意味がないもの、遅延して受信しても意味がないものは有効期限を0にするとよいと思います。
逆に遅延させても受信させたい場合は0を指定してはいけません。

Push通知が届かない・・・

開発時はそれほどではないのですが、実運用を行うとPush通知が届かないということが発生すると思います。
特に厄介なのが、FCMは端末に送信しているのにアプリに通知されない場合です。

完全にというわけではないのですが、問題の切り分け方法について記載したいと思います。
まず、Push通知はFCMから端末に送信されるので非常に追跡が難しいです。この部分でアプリが関与出来る部分はほとんどないと思われます。
切り分けの方法ですが、最初にFCMのメッセージ配信ログを確認します。
FCMのログはFirebaseのプロジェクトごとにBigQueryにエクスポートすることができます。
非常に残念なことにBigQueryにエクスポートする場合Firebaseのプランを従量課金のBlazeに変更する必要があります。
ただ、BigQueryには毎月の無料枠があり、相当数のメッセージを送信していない、定期的にデータを廃棄している場合は課金対象になることはないのではないかと思います。

BigQueryでメッセージの配信状況を見る

エクスポートは時差の関係もあり、日本時間の場合2日後くらいにデータがエクスポートされていると思います(環境によって異なるかも)
エクスポートされたレコードには大まかにメッセージID(特定のメッセージ)、インスタンスID(誰に送ったか)、イベントが含まれます。
その他、優先度や有効期限などの情報も含まれますが大変残念なことにデータの中身は含まれません・・・。
この情報で最も大事なのがイベントの項目です。
このイベントを確認することでFCM上でメッセージがどのように処理されたかわかります。
通常メッセージが配信されると

  • メッセージを受け付けた(MESSAGE_ACCEPTED)
  • メッセージを配信した(MESSAGE_DELIVERED)

の2レコードできます。
さらに、端末が再接続後配信した(MESSAGE_DELIVERED_ON_RECONNECT)、Dozeモード中で遅延(MESSAGE_DELAYED_DOZE)、有効期限ぎれ(MESSAGE_EXPIRED)などがわかります。
メッセージがどのような状態になっているかということがわかるのでPushメッセージが届かない原因がどこにあるのか送信元と送信先に切り分けることができます。
そもそもMESSAGE_DELIVEREDがなければ配信されていませんしMESSAGE_EXPIREDの場合は有効期限が切れたので配信されることはありません。
詳細はこちらをご参照ください。
メッセージ配信について

これで、問題解決・・・とならないところがPush通知の深いところだと思います。
FCMのイベントがMESSAGE_DELIVEREDになっているのにアプリにPush通知が届かないことがあります。

Push通知を拒む要因など

Dozeモードについて(問題ないと思われる)

Android 6以降に搭載されたDozeモードに関しては、メッセージの優先度を高にしている限りは問題があるとは思えませんでした。
Dozeに入っていても受信してアプリが起動します。
とはいえ、完璧ではないので受信できない場合もあると思います。
自分が試した感じでは優先度が高のメッセージがDoze中に顕著に受信できないということはなかったので別の原因があると思われます。

モバイルネットワーク回線時

開発時はWiFiを使うことが多いと思うので気が付きにくい部分があります。
これは公式なドキュメントを見つけられないのですが、端末が常時FCMのサーバーと接続しています。
端末がFCMサーバーと切断されている場合、当然ですがメッセージを配信することができません。

DoCoMoやAUやSoftBankなどのキャリアは問題なかったのですが、MVNOで問題がある機種がありました。
恐らく色々な原因等でFCMとの接続が切断されているものと思われます。
(bigqueryのログもMESSAGE_DELIVEREDがない)
機種固有の問題は色々問題(語弊)がありそうなので詳細は記載しません(お問い合わせいただければ期待に添えるかはわかりませんがお伝えするかもしれません。)
MVNOでも動作確認することをおすすめします。

broadcast intent callback: result=CANCELLED forIntent

原因はわからなかったのですがPushメッセージの受信時にbroadcast intent callback: result=CANCELLED forIntent package nameとログが表示されることがありました。
こちらにも同様の記載があります。
Error broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.flagg327.guicomaipu (has extras) }

たしかにデバッグ中のアプリをタスクから削除したあと、プッシュメッセージを送るとこのログが表示されたことがあります。
しかしリリースビルドでも同様の現象が発生したような記憶があります。
QA中に発生してQAは基本的リリースビルドで行っております。うる覚えなのですがAndroid9か10で省電力から対象アプリを除外をすることで正しくプッシュが届くようになりました。
なのでApp Standby Bucketで制限された影響かと思っておりましたが確証はありません。

原因No1

端末に搭載されている省電力モードです。
例えば、ASUSやHUAWEIの機種にはアプリの自動起動させるかを設定できます。
自動起動が無効になっている場合、Push通知を受信してもアプリが起動できないためアプリから通知を出すなどのアクションを起こすことはできません。
また、この場合ですがBigQueryのfcmのイベントを見てみるとMESSAGE_DELIVEREDになっていると思われます。

ほとんどがメーカーが実装している省電力モードが関係している場合が多いと思われます。

それでもPushが届かない・・・

それでもPushが届かないことがありました。
力不足で原因はわかりませんでした。
ログを見る限りではイベントがMESSAGE_DELIVEREDになっているのですが、端末からアプリにメッセージが配信された形跡がありませんでした。
この部分は引き続き調査を行っています。

まとめ

特にPushメッセージは届かないとユーザーにストレスを与える要因になります。
BigQueryにデータを流すことである程度特定は可能になります。
Dozeモードは失礼ながら疑っていたいたのですが、自分の検証結果では問題がありませんでした。
それよりもMVNO使用時のほうがより顕著に現象が発生しました。
Push通知が届かない問題は非常に追跡が難しい部分もあるのですが、この記事がお役にたてると幸いです。

-Android

© 2025 ビー鉄のブログ Powered by AFFINGER5