使用 Firebase Cloud Messaging 接收消息

本指南介绍了如何在移动和 Web 客户端应用中设置 Firebase Cloud Messaging,以便您能够可靠地接收消息。

如需接收消息,您可以使用扩展 FirebaseMessagingService 的服务。 您的服务应该重写 onMessageReceivedonDeletedMessages 回调方法。如需查看完整示例,请参阅 Firebase Cloud Messaging 快速入门示例

对于大多数消息类型,您都可以使用 onMessageReceived,但以下情况除外:

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

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

总结:

应用状态 通知 数据 两者
前台 onMessageReceived onMessageReceived onMessageReceived
背景 系统托盘 onMessageReceived 通知:系统任务栏;数据:intent 的 extras 属性中。

如需详细了解消息类型,请参阅通知和数据消息

onMessageReceived 回调的执行窗口期较短。许多因素都会影响此时间窗口的长短,包括操作系统延迟、应用启动时间、主线程被其他操作阻止或先前的 onMessageReceived 调用耗时过长。

因此,您应避免在 onMessageReceived 中执行长时间运行的任务(例如从服务器提取图片以在通知中显示),而应使用 WorkManager 调度任务来处理可能需要几秒钟以上才能完成的任务。如需详细了解消息优先级及其对处理的影响,请参阅高优先级和普通优先级消息的消息处理

修改应用清单

如需使用 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 会显示以白色渲染的应用图标。

重写 onMessageReceived

通过重写 FirebaseMessagingService.onMessageReceived 方法,您可以根据收到的 RemoteMessage 对象执行操作并获取消息数据:

Kotlin

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}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // 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 可能不会传递消息。比如说,如果在特定设备连接到 FCM 时,您的应用在该设备上的待处理消息过多(超过 100 条),或者设备超过一个月未连接到 FCM,就会发生这种情况。在这些情况下,您可能会收到对 FirebaseMessagingService.onDeletedMessages() 的回调。当应用实例收到此回调时,应与应用服务器进行一次完全同步操作。如果您在过去 4 周内未向该设备上的应用发送消息,FCM 将不会调用 onDeletedMessages()

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

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

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

如需详细了解发送到您应用的消息,请参阅 FCM 报告信息中心。该信息中心会记录在 Apple 和 Android 设备上发送和打开的消息数量,以及 Android 应用的“展示次数”(用户看到的通知条数)数据。