こんにちは。Android アプリ開発担当の nagayama(@nagayan_dev)です。
この記事は Gunosy Advent Calendar 2024 の 4 日目の記事です。 3 日目の記事は takuji さんの 広告キャンペーン単位で A/B テストを行った話 でした。
今回は Android の Push 通知の Tips をまとめましたので、その内容をお伝えします。
はじめに
Android アプリでは、ユーザーとのコミュニケーション手段として「Push通知」が広く利用されています。この機能はAndroidの初期から存在し、現在でも多くのアプリで欠かせないものとなっています。弊社が提供しているキュレーションアプリ「グノシー」や「auサービスToday」でも、朝昼等の定時通知や速報通知といった形で活用しています。
今回は、Push 通知に関する分かりにくいパラメータの解説や、実践で役立つノウハウをまとめた Tips をご紹介します。
配信時の Tips
Firebase Cloud Messaging ( 以下 FCM ) を用いて Push 通知を送っています。FCM では「通知メッセージ」と「データメッセージ」の 2 タイプのメッセージがあります。弊社では「データメッセージ」で送信をしています。
メッセージの優先度(priority)
FCM のメッセージ配信の優先度を設定するパラメータ priority があります。アプリ実装で言えば、FirebaseMessagingService
を継承した Service クラスの onMessageReceived
メソッドに「いつ通知されるか」の設定になります。設定値は下記の 2 種類があります。
種別 | 概要 |
---|---|
標準(normal) | 端末がスリープになっていない場合または、スリープ解除時に通知を配信する。 |
高(high) | スリープ状態に関わらず、即時配信する。 |
通常であれば 標準
の設定にしますが、緊急性の高い通知を送る場合は 高
に設定します。
またメッセージの優先度を 高
に設定している場合、その優先度を下げられる場合があります。その 1 つが「アプリスタンバイバケット」です。
アプリスタンバイバケット
アプリスタンバイバケットは Android 9 以降に入った機能です。システムがアプリの利用頻度に応じて、自動的に 5 段階で評価を付けます。以下がその 5 段階の評価です。
評価値 | 概要 | FCM 制限 |
---|---|---|
アクティブ(active) | 使用中であるか最近使用されたアプリ | 制限なし |
ワーキング セット(working set) | 定期的に使用されているアプリ | 制限なし |
高頻度(frequent) | 毎日ではないが、よく使用されているアプリ | 高い優先度 10 件/日 |
低頻度(rare) | あまり使用されていないアプリ | 高い優先度 5 件/日 |
制限付き(restricted) | システム リソースを大量に消費するか、望ましくない動作を引き起こす可能性があるアプリ | 高い優先度 5 件/日 |
※ 制限付き(restricted)
は Android 12 で追加されたため、それ未満では設定されません。
自分のアプリがどの設定状態になっているかは、「開発者向けオプション > スタンバイ状態のアプリ」 から確認が可能です。
メッセージの優先度はアプリスタンバイバケットの状態に応じて制限が掛けられます。 高頻度(frequent)
から 制限付き(restricted)
の低い設定になっている場合、 1 日に高
で通知できる件数が制限がされます。上限を超えた場合は 通常
の設定で配信されるようになります。
アプリで通知する時の Tips
通知チャンネル
Android 8.0 以降では全ての通知をチャンネルごとに設定します。表示や通知音の設定ができ、そのチャンネルを利用すれば全て同じ設定で通知することができます。通知チャンネルの必須パラメータは、「チャンネルID」「チャンネルの説明文」「メッセージの重要度」の 3 つになります。
メッセージの重要度(importance)
メッセージの重要度(importance)とは「ユーザーにどう通知を表示するか」の設定です。5 つの値から選択するものになります。
設定値 | ステータスバーに表示 | 音 | 備考 |
---|---|---|---|
緊急(IMPORTANCE_HIGH) | ○ | ○ | ヘッドアップ通知あり |
高(IMPORTANCE_DEFAULT) | ○ | ○ | |
中(IMPORTANCE_LOW) | ○ | × | |
低(IMPORTANCE_MIN) | × | × | |
なし(IMPORTANCE_NONE) | × | × | 通知シェードにも表示なし。通知設定OFF時の値。 |
「通知表現の強さ」を設定するパラメータとも言えます。高ければそれだけユーザーの目につきやすい反面、嫌悪感を感じて通知を OFF にされてしまうリスクもあります。
余談ですが、この importance と同様なパラメータとして、Android 8.0 未満には priority がありました[参考]。昔から Android アプリを開発していると未だに importance のことを priority と呼んでしまうことがあるため、先ほどのメッセージの優先度と混同してしまう人もいます。
通知設定
端末で通知を受け取るかどうかの設定は「設定 > アプリ」より対象のアプリを選択し、「通知」から確認ができます。通知設定は、そもそも通知自体を受け取るかどうかの「すべての通知」の設定(①)と、各通知チャンネルごとの設定(②)があります。
それぞれの通知設定を取得する方法は下記になります。
① すべての通知設定
Android 4.4 以上から取得が可能です。
val manager = NotificationManagerCompat.from(context) val isEnabled = manager.areNotificationsEnabled()
② 通知チャンネルごとの設定
Android 8.0 以上から取得が可能です。設定が OFF の状態で「メッセージの重要度(importance)」を取得すると IMPORTANCE_NONE
が返却されます。設定しているかどうかはこの値と比較をします。
val manager = NotificationManagerCompat.from(context) val importance = manager.getNotificationChannel(channelIdStr)?.importance ?: return false val isEnabled = importance != NotificationManager.IMPORTANCE_NONE
残念ながら設定が切り替わったタイミングは検知することができません。設定状態が知りたい場合は、アプリを起動・操作をしているタイミングでこれらの設定を読み取る必要があります。
メッセージの最大の表示件数を設定する
違う通知 ID でメッセージをたくさん送信してしまうと通知シェードに大量のメッセージが表示されてしまい、ユーザーに悪い印象を与えます。メッセージの最大表示件数を設定する場合は、アプリの実装が必要になります。
実装例はこちらです。
val targetGroupKey = "target_group_key" val notificationManager = this.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val targetGroupNotifications = notificationManager .activeNotifications .filter { it.notification.group != null && targetGroupKey.contains(it.notification.group) } val size = targetGroupNotifications.size if (size >= MAX_DISPLAY_COUNT) { targetGroupNotifications .sortedByDescending { it.postTime } // 古い順に並べる .subList(MAX_DISPLAY_COUNT - 1, size) .forEach { // 上限を超えたものを削除する notificationManager.cancel(it.id) } }
NotificationManager から表示をしている通知のリスト activeNotifications
を取得し、その中から対象の通知グループをキーを用いて探します。対象の通知グループのメッセージが上限数を超えていた場合、古い順に並べた上で上限を超えたものを NotificationManager の cancel
で削除をします。これにより例えば上限数を 3 と設定した場合、4 つ目の通知の前にこの処理を実行すると 1 番古い通知が削除されて 3 つ目の通知として通知できるようになります。
通知
最後に簡単ですが通知に関するパラメータです。主な設定パラメータは下記になります。
概要 | メソッド |
---|---|
1 行目のテキスト | setContentTitle(CharSequence title) |
2 行目のテキスト | setContentText(CharSequence text) |
小さいアイコン | setSmallIcon(IconCompat icon) 又は setSmallIcon(int icon) |
大きいアイコン | setLargeIcon(Bitmap icon) ※1 又は setLargeIcon(Icon icon) |
通知押下時のIntent | setContentIntent(PendingIntent intent) |
通知グループ | setGroup(String groupKey) |
表示時間 | setTimeoutAfter(long durationMs) ※2 |
※1. setLargeIcon(Bitmap icon)
では大きい画像は 320dp x 320dp にリサイズされます
※2. Android 8.0 以上
まとめ
Push 通知に関する Tips をご紹介をしました。Push 通知単体だけの設定パラメータだけでなく、デバイスの状態や設定に影響されるパラメータもあるため、注意が必要です。長い歴史があるだけに難易度が高くなってきていますが、しっかり理解をして上手く活用しましょう。
明日は koki さんが LLMでの業務支援 についてお話します。お楽しみに!