Firebase 通知的行为因接收应用程序的前台/后台状态而异。如果您希望前台应用程序接收通知消息或数据消息,则需要编写代码来处理onMessageReceived
回调。有关通知消息和数据消息之间差异的说明,请参阅消息类型。
处理消息
要接收消息,请使用扩展FirebaseMessagingService的服务。您的服务应该覆盖onMessageReceived
和onDeletedMessages
回调。它应该在收到消息后的 20 秒内处理任何消息(在 Android Marshmallow 上为 10 秒)。时间窗口可能会更短,具体取决于调用onMessageReceived
之前发生的操作系统延迟。在那之后,各种操作系统行为(例如 Android O 的后台执行限制)可能会干扰您完成工作的能力。有关详细信息,请参阅我们对消息优先级的概述。
onMessageReceived
为大多数消息类型提供,但以下情况除外:
当您的应用程序处于后台时发送的通知消息。在这种情况下,通知将传送到设备的系统托盘。默认情况下,用户点击通知会打开应用程序启动器。
在后台接收时同时具有通知和数据负载的消息。在这种情况下,通知会传送到设备的系统托盘,数据负载会在启动器 Activity 的 intent 的附加项中传送。
总之:
应用状态 | 通知 | 数据 | 两个都 |
---|---|---|---|
前景 | 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),或者如果该设备超过一个月未连接到 FCM,就会发生这种情况。在这些情况下,您可能会收到FirebaseMessagingService.onDeletedMessages()
的回调当应用实例收到此回调时,它应该与您的应用服务器执行完全同步。如果您在过去 4 周内没有向该设备上的应用发送消息,FCM 将不会调用onDeletedMessages()
。在后台应用程序中处理通知消息
当您的应用程序处于后台时,Android 会将通知消息定向到系统托盘。默认情况下,用户点击通知会打开应用程序启动器。
这包括包含通知和数据负载的消息(以及从通知控制台发送的所有消息)。在这些情况下,通知会传送到设备的系统托盘,并且数据负载会在启动器 Activity 的 intent 的附加项中传送。
要深入了解向您的应用程序发送的消息,请参阅FCM 报告仪表板,它记录了在 Apple 和 Android 设备上发送和打开的消息数量,以及 Android 应用程序的“印象”(用户看到的通知)数据。
后台受限应用程序(Android P 或更新版本)
FCM 可能不会向用户设置后台限制的应用程序发送消息(例如通过:设置 -> 应用程序和通知 -> [应用程序名称] -> 电池)。一旦您的应用程序从后台限制中删除,到该应用程序的新消息将像以前一样传递。为了防止丢失消息和其他后台限制影响,请确保避免Android Vitals工作列出的不良行为。这些行为可能会导致 Android 设备向用户推荐您的应用受到后台限制。您的应用可以使用isBackgroundRestricted()检查它是否受背景限制。在直接引导模式下接收 FCM 消息
想要在设备解锁之前向应用发送 FCM 消息的开发人员可以让 Android 应用在设备处于直接启动模式时接收消息。例如,您可能希望您的应用程序的用户即使在锁定的设备上也能收到警报通知。
构建此用例时,请遵守直接启动模式的一般最佳实践和限制。考虑直接启动消息的可见性尤为重要;任何有权访问该设备的用户都可以在不输入用户凭据的情况下查看这些消息。
先决条件
- 设备必须设置为直接启动模式。
- 设备必须安装最新版本的 Google Play 服务(19.0.54 或更高版本)。
- 该应用必须使用 FCM SDK (
com.google.firebase:firebase-messaging
) 来接收 FCM 消息。
在您的应用中启用直接启动模式消息处理
在app级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
还需要能够直接启动(在直接启动模式下无法访问受凭证保护的存储)。
有关在直接启动模式下向设备发送消息的指南,请参阅发送启用直接启动的消息。