向多台设备发送消息

Firebase 云消息传递提供两种向多台设备发送消息的方法:

本教程主要介绍如何使用 FCM 的 HTTP 协议或 XMPP 协议从应用服务器发送主题消息,以及如何在 Android 应用中接收和处理此类消息。介绍内容涵盖后台应用和前台应用的消息处理方式。此外,我们还介绍了实现上述目标所需的所有步骤,包括从设置到验证的步骤。

设置 SDK

如果您已针对 FCM 设置 Android 客户端应用,或已经完成发送第一条消息所需的步骤,则本节可能包含了您已经完成的步骤。

前提条件

  • 运行 Android 4.0 (Ice Cream Sandwich) 或更高版本以及 Google Play 服务 12.0.1 或更高版本的设备
  • 最新版本的 Android Studio

如果您还没有 Android Studio 项目,只是想试用一下某项 Firebase 功能,可以下载我们的快速入门示例。如果使用快速入门,请不要忘记从项目模块文件夹(通常是 build.gradle)的 app/ 文件中获取应用 ID;您需要在下一步中使用该软件包名称。

将 Firebase 添加至您的应用

要将 Firebase 添加到您的应用,您需要有一个 Firebase 项目以及适用于您的应用的 Firebase 配置文件。

  1. 如果您还没有 Firebase 项目,请在 Firebase 控制台中创建一个。如果您已经有与自己的移动应用相关联的现有 Google 项目,请点击导入 Google 项目。如果没有,请点击添加项目
  2. 点击将 Firebase 添加到您的 Android 应用,然后按设置步骤操作。如果您是导入现有 Google 项目,系统可能会自动执行这些操作,您只需下载配置文件即可。
  3. 出现提示时,输入应用的软件包名称。请务必输入应用在使用的软件包名称;只有在将应用添加到 Firebase 项目时您才能进行此设置。
  4. 最后,您要下载一个 google-services.json 文件。您可以随时重新下载此文件
  5. 如果尚未将此文件复制到项目的模块文件夹(通常是 app/),请执行此操作。

添加 SDK

如果希望将 Firebase 库集成至自己的某个项目中,您需要执行几项基本操作来准备 Android Studio 项目。您可能已经在将 Firebase 添加至应用时完成了这些操作。

首先,向您的根级 build.gradle 文件添加规则,以纳入 google-services 插件和 Google 的 Maven 代码库:

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:3.2.0' // google-services plugin
    }
}

allprojects {
    // ...
    repositories {
        // ...
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

然后,在您的模块 Gradle 文件(通常是 app/build.gradle)中,在文件的底部添加 apply plugin 代码行,以启用 Gradle 插件:

apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  compile 'com.google.firebase:firebase-core:12.0.1'
  compile 'com.google.firebase:firebase-messaging:12.0.1'
  // Getting a "Could not find" error? Make sure you have
  // added the Google maven respository to your root build.gradle
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

您还应添加您希望使用的 Firebase SDK 的依赖项。建议从 com.google.firebase:firebase-core 开始,它可以提供 Google Analytics for Firebase 功能。请参阅可用库列表

为客户端应用订阅主题

客户端应用可以订阅任何现有主题,也可创建新主题。当客户端应用订阅新的主题名称(您的 Firebase 项目中尚不存在的名称)时,系统会在 FCM 中使用这个名称创建一个新主题,随后任何客户端都可订阅该主题。

若要订阅某个主题,客户端应用需使用 FCM 主题名称调用 Firebase 云消息传递 subscribeToTopic()

FirebaseMessaging.getInstance().subscribeToTopic("news");

若要退订,客户端应用需使用主题名称调用 Firebase 云消息传递 unsubscribeFromTopic()

接收和处理主题消息

FCM 传送主题消息的方式与处理其他下行消息的方式相同。

要接收消息,请使用可扩展 FirebaseMessagingService 的服务。您的服务应该覆盖 onMessageReceivedonDeletedMessages 回调。在收到任何消息后,该服务都应在 10 秒内处理消息。在此之后,Android 不保证执行,且可能随时终止您的进程。如果您的应用需要更多时间来处理消息,请使用 Firebase Job Dispatcher

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

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

  • 同时具备通知和数据负载的消息,无论应用在前台还是后台。在这种情况下,通知将传送至设备的系统任务栏,数据有效负载则传送至启动器 Activity 的 intent 的 extras 参数中。

汇总:

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

修改应用清单文件

要使用 FirebaseMessagingService,您需要将以下内容添加到您的应用清单:

<service
    android:name=".MyFirebaseMessagingService">
    <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 会显示自定义默认图标:

  • 通知编辑器发送的所有通知信息。
  • 在通知负载中未明确设置图标的任何通知消息。

对于以下内容,Android 会使用自定义的默认颜色:

  • 通知编辑器发送的所有通知信息。
  • 在通知负载中未明确设置颜色的任何通知消息。

如果未设置自定义默认图标,而且通知负载中也未设置图标,Android 会显示以白色渲染的应用图标。

覆盖 onMessageReceived

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

@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 Firebase Job Dispatcher.
            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 会将通知消息转发至系统任务栏。默认情况下,用户点按通知时将打开应用启动器。

这包括同时含有通知和数据有效负载的消息(以及从通知控制台发送的所有消息)。在这些情况下,通知将传送至设备的系统任务栏,而数据有效负载则通过启动器 Activity 的 intent 中的 extras 传递。

构建发送请求

向 Firebase 云消息传递主题发送消息与向单台设备或一个用户组发送消息十分类似。应用服务器会将 to 键设为类似 /topics/yourTopic 这样的值。开发者可以选择符合以下正则表达式的任何主题名称:"/topics/[a-zA-Z0-9-_.~%]+"

要向多个主题的组合发送消息,应用服务器必须将 condition 键(而非 to 键)设为用于指定目标主题的布尔型条件。例如,向已订阅 TopicATopicBTopicC 的设备发送消息:

'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)

FCM 首先对括号中的所有条件求值,然后从左至右对表达式求值。在上述表达式中,只订阅某个单一主题的用户将不会接收到消息。同样地,未订阅 TopicA 的用户也不会接收到消息。下列组合将会接收到消息:

  • TopicA 和 TopicB
  • TopicA 和 TopicC

您最多可以在条件表达式中添加五个主题,支持使用括号。支持的运算符包括 &&||!。请注意 ! 的用法:

!('TopicA' in topics)

使用此表达式,任何未订阅 TopicA 的应用实例(包括未订阅任何主题的应用实例)都会收到消息。

如需详细了解应用服务器键,请参阅您所选的连接服务器协议(HTTPXMPP)的参考信息。本页面中的示例演示了如何使用 HTTP 和 XMPP 协议将消息发送至主题。

主题 HTTP POST 请求

发送至一个主题:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

发送至已订阅“dogs”或“cats”主题的设备:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

主题 HTTP 响应

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

主题 XMPP 消息

发送至一个主题:

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

发送至已订阅“dogs”或“cats”主题的设备:

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

主题 XMPP 响应

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

FCM 服务器对主题发送请求返回成功或失败响应前,可能会有长达 30 秒的延迟。请确保在请求中相应地设置应用服务器的超时值。

如需消息选项的完整列表,请参阅您所选的连接服务器协议(HTTPXMPP)的参考信息。

后续步骤

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面