Firebase 通知は、受信アプリのフォアグラウンド/バックグラウンド状態に応じて異なる動作をします。フォアグラウンド アプリで通知メッセージまたはデータ メッセージを受信する場合は、 onMessageReceived
コールバックを処理するコードを記述する必要があります。通知メッセージとデータ メッセージの違いについては、「メッセージ タイプ」を参照してください。
メッセージの処理
メッセージを受信するには、 FirebaseMessagingServiceを拡張するサービスを使用します。サービスはonMessageReceived
およびonDeletedMessages
コールバックをオーバーライドする必要があります。受信から 20 秒以内 (Android Marshmallow では 10 秒) 以内にメッセージを処理する必要があります。 onMessageReceived
を呼び出す前に発生した OS の遅延によっては、時間枠が短くなる場合があります。それ以降は、Android O のバックグラウンド実行制限など、さまざまな OS の動作により、作業を完了する能力が妨げられる可能性があります。詳細については、メッセージの優先度に関する概要を参照してください。
onMessageReceived
は、次の例外を除いて、ほとんどのメッセージ タイプに提供されます。
アプリがバックグラウンドにあるときに配信される通知メッセージ。この場合、通知はデバイスのシステム トレイに配信されます。ユーザーが通知をタップすると、デフォルトでアプリ ランチャーが開きます。
バックグラウンドで受信した場合、通知とデータ ペイロードの両方を含むメッセージ。この場合、通知はデバイスのシステム トレイに配信され、データ ペイロードはランチャー アクティビティのインテントのエクストラで配信されます。
要約すれば:
アプリの状態 | 通知 | データ | 両方 |
---|---|---|---|
前景 | onMessageReceived | onMessageReceived | onMessageReceived |
バックグラウンド | システムトレイ | onMessageReceived | 通知: システム トレイ データ: インテントのエクストラ。 |
アプリ マニフェストを編集する
FirebaseMessagingService
を使用するには、アプリ マニフェストに以下を追加する必要があります。
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
また、デフォルト値を設定して、通知の外観をカスタマイズすることをお勧めします。通知ペイロードに同等の値が設定されていない場合に適用されるカスタム デフォルト アイコンとカスタム デフォルト カラーを指定できます。
application
タグ内に次の行を追加して、カスタムのデフォルト アイコンとカスタム カラーを設定します。
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_stat_ic_notification" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
Android では、カスタムのデフォルト アイコンが表示されます。
- Notifications composerから送信されたすべての通知メッセージ。
- 通知ペイロードに明示的にアイコンを設定しない通知メッセージ。
Android ではカスタムのデフォルト カラーを使用します。
- Notifications composerから送信されたすべての通知メッセージ。
- 通知ペイロードで明示的に色を設定しない通知メッセージ。
カスタムのデフォルト アイコンが設定されておらず、通知ペイロードにアイコンが設定されていない場合、Android は白でレンダリングされたアプリケーション アイコンを表示します。
onMessageReceived
オーバーライドする
メソッドFirebaseMessagingService.onMessageReceived
をオーバーライドすることで、受信したRemoteMessageオブジェクトに基づいてアクションを実行し、メッセージ データを取得できます。
Kotlin+KTX
override fun onMessageReceived(remoteMessage: RemoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: ${remoteMessage.from}") // Check if message contains a data payload. if (remoteMessage.data.isNotEmpty()) { Log.d(TAG, "Message data payload: ${remoteMessage.data}") if (/* Check if data needs to be processed by long running job */ true) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob() } else { // Handle message within 10 seconds handleNow() } } // Check if message contains a notification payload. remoteMessage.notification?.let { Log.d(TAG, "Message Notification Body: ${it.body}") } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
Java
@Override public void onMessageReceived(RemoteMessage remoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: " + remoteMessage.getFrom()); // Check if message contains a data payload. if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); if (/* Check if data needs to be processed by long running job */ true) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob(); } else { // Handle message within 10 seconds handleNow(); } } // Check if message contains a notification payload. if (remoteMessage.getNotification() != null) { Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody()); } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
onDeletedMessages
オーバーライドする
状況によっては、FCM がメッセージを配信しないことがあります。これは、接続時に特定のデバイス上のアプリに対して保留中のメッセージが多すぎる (>100) 場合、またはデバイスが 1 か月以上 FCM に接続されていない場合に発生します。このような場合、 FirebaseMessagingService.onDeletedMessages()
へのコールバックを受け取ることがあります。アプリ インスタンスがこのコールバックを受け取ると、アプリ サーバーとの完全な同期を実行する必要があります。過去 4 週間以内にそのデバイスのアプリにメッセージを送信していない場合、FCM はonDeletedMessages()
を呼び出しません。バックグラウンド アプリで通知メッセージを処理する
アプリがバックグラウンドにある場合、Android は通知メッセージをシステム トレイに送信します。ユーザーが通知をタップすると、デフォルトでアプリ ランチャーが開きます。
これには、通知とデータ ペイロードの両方を含むメッセージ (および Notifications コンソールから送信されたすべてのメッセージ) が含まれます。このような場合、通知はデバイスのシステム トレイに配信され、データ ペイロードはランチャー アクティビティのインテントのエクストラで配信されます。
アプリへのメッセージ配信について詳しくは、 FCM レポート ダッシュボードを参照してください。このダッシュボードには、Apple および Android デバイスで送信および開封されたメッセージの数と、Android アプリの「インプレッション」(ユーザーが表示した通知) のデータが記録されています。
バックグラウンドで制限されたアプリ (Android P 以降)
FCM は、ユーザーによってバックグラウンドで制限されたアプリにメッセージを配信しない場合があります (設定 -> アプリと通知 -> [アプリ名] -> バッテリーなど)。アプリがバックグラウンド制限から削除されると、アプリへの新しいメッセージは以前と同じように配信されます。メッセージの紛失やその他のバックグラウンド制限の影響を防ぐために、 Android Vitalsの取り組みで挙げられている悪い動作を避けるようにしてください。これらの動作により、アプリのバックグラウンドを制限することを Android デバイスがユーザーに推奨する可能性があります。 isBackgroundRestricted()を使用して、アプリがバックグラウンドで制限されているかどうかを確認できます。ダイレクト ブート モードで FCM メッセージを受信する
デバイスのロックが解除される前でも FCM メッセージをアプリに送信したい開発者は、デバイスがダイレクト ブート モードのときに Android アプリがメッセージを受信できるようにすることができます。たとえば、デバイスがロックされていても、アプリのユーザーにアラーム通知を受信させたい場合があります。
このユースケースを構築するときは、ダイレクト ブート モードの一般的なベスト プラクティスと制限事項に従ってください。ダイレクト ブート対応メッセージの可視性を考慮することは特に重要です。デバイスにアクセスできるすべてのユーザーは、ユーザー資格情報を入力せずにこれらのメッセージを表示できます。
前提条件
- デバイスは、ダイレクト ブート モードに設定する必要があります。
- デバイスには、Google Play サービスの最新バージョン (19.0.54 以降) がインストールされている必要があります。
- FCM メッセージを受信するには、アプリが FCM SDK (
com.google.firebase:firebase-messaging
) を使用している必要があります。
アプリでダイレクト ブート モードのメッセージ処理を有効にする
アプリ レベルの Gradle ファイルで、FCM ダイレクト ブート サポート ライブラリへの依存関係を追加します。
implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
アプリ マニフェストに
android:directBootAware="true"
属性を追加して、アプリのFirebaseMessagingService
ダイレクト ブート対応にします。<service android:name=".java.MyFirebaseMessagingService" android:exported="false" android:directBootAware="true"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
このFirebaseMessagingService
がダイレクト ブート モードで実行できることを確認することが重要です。次の要件を確認します。
- サービスは、ダイレクト ブート モードで実行されている間は、資格情報で保護されたストレージにアクセスしてはなりません。
- サービスは、ダイレクト ブート モードでの実行中に、
Activities
、BroadcastReceivers
、またはダイレクト ブート対応としてマークされていないその他のServices
などのコンポーネントを使用しようとしないでください。 - サービスが使用するライブラリは、資格情報で保護されたストレージにアクセスしたり、ダイレクト ブート モードで実行中に directBootAware 以外のコンポーネントを呼び出したりしてはなりません。これは、サービスから呼び出されるアプリが使用するすべてのライブラリが、ダイレクト ブート対応である必要があるか、アプリがダイレクト ブート モードで実行されているかどうかを確認し、そのモードでは呼び出さない必要があることを意味します。たとえば、Firebase SDK はダイレクト ブートで動作します (ダイレクト ブート モードでクラッシュすることなくアプリに含めることができます) が、多くの Firebase API はダイレクト ブート モードでの呼び出しをサポートしていません。
- アプリがカスタム
Application
を使用している場合、Application
もダイレクト ブート対応である必要があります (ダイレクト ブート モードでは資格情報で保護されたストレージにアクセスできません)。
ダイレクト ブート モードでデバイスにメッセージを送信する方法については、 「ダイレクト ブート対応メッセージを送信する」を参照してください。