Open2

Flutter プッシュ通知についてのscrap

mashmash

Flutterアプリのプッシュ通知について、仕組みを理解しながら知見を広げるためのスクラップ

不具合に対応していく中で、自身が調べたものと共有してもらった情報の備忘録として📕

まずは仕組みから

プッシュ通知の仕組み
Androidとiosでは③のメッセージを送信するプラットフォームが異なる。

Android
・FCM(Firebase Cloud Messaging)でプッシュ通知が送られる。FCMではユーザーが通知の許可を端末で行うと情報が登録され、IDが発行される仕組み。
・アプリをダウンロードすると自動的にプッシュ通知を受け取る設定となる。

iOS
・APNsからプッシュ通知が送られる。ユーザーが通知を許可するとトークン(端末識別用のID)がAPNsに届き、アプリの運営側(今回はFCM)がトークンを読み取ってプッシュ通知を送信する仕組み。
・iOSのプッシュ通知はユーザーがアプリをダウンロードした後で通知を受け取るかどうか自分で判断して設定する。(ここで通知を受け取らない設定をした場合はユーザーに変更してもらう必要がある)

プッシュ通知について

  • json形式
    以下は例)
ファイル名
{
  "apns": {
     "headers": {
       "apns-priority": "5",
     },
     "payload": {
        "aps": {
          "alert": {
            "title": data.chat_title,
             "body": data.chat_msg,
          },
          "badge": 1,
          "sound": "default"
        }
     }
  },
  "data": {
    "title": data.chat_title,
    "body": data.chat_msg,
    "chat_id": data.chat_id
  },
  "token": registrationToken
};
  • ペイロードサイズは4kBまで(Firebase コンソールからメッセージを送信する場合は1,024 文字まで)
  • Apple デバイスにデータ メッセージを送信する場合は、優先度(apns-priority)を 5(標準の優先度)に設定する。高優先度でメッセージを送信するとエラー INVALID_ARGUMENT が発生し、FCM バックエンドで拒否される。

など。
詳しくはこちら↓
https://firebase.google.com/docs/cloud-messaging/concept-options?hl=ja

OSの文字数制限

Android

  • 全角で20~22文字程度ならプッシュ通知のメッセージ本文は省略されずに表示できる。それ以上は「...」と省略される。

iOS

  • コントロールセンターで表示できるメッセージ本文は全角で20~22文字程度。それ以上は「...」と省略される。
    ⭐️ (3Dタッチが可能な場合)256文字まで表示。←コントロールセンターの文字数上限値(実機確認XsMax)👀
    ※OSのバージョンやiPhoneの世代にもよる
mashmash

不具合事象①

ケース:
運営側から一部/全ユーザーに対して、個別メッセージ・一斉送信即時/一斉送信予約メッセージを送信した際にプッシュ通知を表示する
ユーザー数は3,500くらい

運用:
1000文字程度のメッセージ、画像、テキストリンクの送信

操作:
一部または全ユーザーに対して、1000文字程度のメッセージを以下の方法で送信。
個別メッセージ
一斉送信予約メッセージ
一斉送信即時メッセージ

問題:
メッセージを送信してもプッシュ通知が届く場合と届かない場合がある

考えられうる原因

①送信するメッセージ量にもよるが、ペイロードが大きすぎるという可能性
②1件ずつリクエストを送信する仕様だったため、対象のユーザー数が多い場合にFCMからのリクエスト以降の処理で大量のリクエストを捌ききれなかった可能性(APNsの場合はリクエスト間にsleepを入れた方が良いと記事がちらほらあった)

対応

①に対して
ペイロードのbody(メッセージ本文)の値をiOSのコントロールセンターの表示可能な文字数上限の「256」文字まで、それ以降を「...」の文字列に置き換えてプッシュ通知のリクエストを送信する。

②に対して
プッシュ通知のリクエスト送信処理がforループ処理だったため、送信完了時にsleep()処理を追記する。間隔は1.0秒にした。
※1件1件リクエストしている仕様を、例えば500件ずつにまとめてリクエストするなどした方が好ましいと思う

結果

①の結果
Androidのプッシュ通知の見た目は変わらず、iOSのプッシュ通知の見た目は最小限にしてユーザーに送信できた。

②の結果
sleep()を入れたことで多少の改善は見られた。

本番環境では問題なくプッシュ通知が届いている様子。
しかし、dev環境では「一斉送信即時」の場合のプッシュ通知が届かない課題が解決まで至れず。sleepの間隔を広げたり狭くしたりしたが、間隔にそこまでの大きな影響はなさそう。
ただ、sleepを入れない場合はプッシュ通知が届かない現象は発生した。(これは環境によるユーザー数の違いがあるから?な気がしてる)
加えて、dev環境の一斉送信予約メッセージのプッシュ通知は処理が走ってから7~8分後にプッシュ通知が届いた。(何度試しても即座に届きはしなかった)

気づき

  • ペイロードはAndroid、iOSの両方のメッセージの容量を含む(最初は別々かと思っていた)
  • Android、iOSどちらもバージョンによってプッシュ通知の見え方が異なるが、コントロールセンターで確認できる最低限のメッセージ本文をbodyに格納して(ペイロードサイズを小さくして)も違和感はない
  • 今の仕様でdev環境でプッシュ通知が届くペイロードサイズの閾値は781文字だった。今後はこの値を基準の一つにして改善ができれば良いと思う。
    (個人的にこの文字数は少ない気がするが、一般的にはどの程度の文字数を送れているのだろうか。)

追記

誤った知識、確認してみるべき箇所、プッシュ通知のリクエストを送信する際の工夫等あれば随時訂正・更新する予定です。