Google 致力于为黑人社区推动种族平等。查看具体举措

在 Android 应用中接收消息

根据接收消息的应用的状态(前台/后台),Firebase 通知的行为会有所不同。如果您希望前台应用接收通知消息或数据消息,则需要编写代码来处理 onMessageReceived 回调。如需详细了解通知消息与数据消息之间的区别,请参阅消息类型

处理消息

如需接收消息,请使用继承 FirebaseMessagingService 的服务。您的服务应该重写 onMessageReceivedonDeletedMessages 回调方法。该服务应在收到消息后 20 秒内对其进行处理(Android Marshmallow 上为 10 秒)。这个时长可能会更短,具体取决于调用 onMessageReceived 之前发生的操作系统延迟。这个时间段过后,各种操作系统行为(如 Android O 的后台执行限制)可能会影响您完成工作的能力。如需了解详情,请参阅我们的消息优先级概述。

大多数类型的消息都会提供 onMessageReceived,但以下情况例外:

  • 当应用在后台时送达的通知消息。在这种情况下,通知将传送至设备的系统任务栏。默认情况下,用户点按通知即可打开应用启动器。

  • 在后台所接收的同时具备通知和数据载荷的消息。 在这种情况下,通知将传送至设备的系统任务栏,数据载荷则传送至启动器 Activity 的 intent 的 extras 属性中。

总结:

应用状态 通知 数据 两者皆有
前台 onMessageReceived onMessageReceived onMessageReceived
后台 系统任务栏 onMessageReceived 通知:系统任务栏
数据:intent 的 extras 属性中。
如需了解消息类型的详细信息,请参阅通知和数据消息

修改应用清单

如需使用 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 对象执行操作并获取消息数据:

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.
}

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.
}

重写 onDeletedMessages

在某些情况下,FCM 可能不会传递消息。如果在特定设备连接 FCM 时,您的应用在该设备上的待处理消息过多(超过 100 条),或者如果设备超过一个月未连接到 FCM,就会发生这种情况。在这些情况下,您可能会收到对 FirebaseMessagingService.onDeletedMessages() 的回调。当应用实例收到此回调时,应该执行一次与应用服务器的完全同步。如果您在过去 4 周内未向该设备上的应用发送消息,FCM 将不会调用 onDeletedMessages()

在后台应用中处理通知消息

当您的应用位于后台时,Android 会将通知消息转发至系统任务栏。默认情况下,用户点按通知即可打开应用启动器。

此类消息包括既具有通知也具有数据载荷的消息(以及所有从通知控制台发送的消息)。 在这些情况下,通知将传送至设备的系统任务栏,数据载荷则传送至启动器 Activity 的 intent 的 extras 属性。

有关发送到您应用的消息的详细情况,请参阅 FCM 报告信息中心,该信息中心记录了在 iOS 和 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 消息。

在应用中启用直接启动模式消息处理

  1. 在应用级 Gradle 文件中,在 FCM 直接启动支持库上添加依赖项:

    implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
    
  2. 通过在应用清单中添加 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 服务可以在直接启动模式下运行。检查是否满足以下要求:

  • 在直接启动模式下运行时,服务不应访问由凭据保护的存储空间。
  • 在直接启动模式下运行时,服务不应尝试使用并非标记为感知直接启动的组件(例如 ActivitiesBroadcastReceivers 或其他 Services)。
  • 在直接启动模式下运行时,该服务使用的任何库还不得访问由凭据保护的存储空间,也不得调用 non-directBootAware 组件。也就是说,该应用通过此服务调用所使用的库要么需要能够感知直接启动,要么应用需要检查它是否在直接启动模式下运行并且不在该模式下调用它们。例如,Firebase SDK 支持直接启动(它们可以包含在应用中,而不会在直接启动模式下导致应用崩溃),但许多 Firebase API 不支持在直接启动模式下调用。
  • 如果应用使用自定义 Application,则 Application 也需要能够感知直接启动(不能在直接启动模式下访问由凭据保护的存储空间)。

如需了解在直接启动模式下向设备发送消息的指南,请参阅发送支持直接启动的消息