关于 FCM 消息

Firebase 云消息传递 (FCM) 提供了众多消息传递选项和功能。本页中的内容旨在帮助您了解不同类型的 FCM 消息以及您可以对其进行哪些操作。

消息类型

使用 FCM,您可以向客户端发送两种类型的消息:

  • 通知消息,有时被视为“显示消息”。此类消息由 FCM SDK 自动处理。
  • 数据消息,由客户端应用处理。

通知消息包含一组预定义的用户可见的键。与其相对,数据消息只包含用户定义的自定义键值对。通知消息可以包含可选数据有效负载。这两种消息类型的有效负载上限均为 4KB,但从 Firebase 控制台发送消息时除外,在那种情况下,系统会强制执行 1024 个字符的限制。

使用情景 如何发送
通知消息 FCM 会代表客户端应用自动向最终用户设备显示消息。通知消息包含一组预定义的用户可见的键和一个由自定义键值对组成的可选数据有效负载。
  1. 在可信环境(例如 Cloud Functions 或您的应用服务器)中,使用 Admin SDKFCM 服务器协议:设置 notification 键。可能包含可选的数据有效负载。一律可折叠。
  2. 使用通知编辑器:输入消息文本、标题等,然后发送。通过提供自定义数据添加可选的数据有效负载。
数据消息 客户端应用负责处理数据消息。数据消息只包含自定义键值对。 在可信环境(例如 Cloud Functions 或您的应用服务器)中,使用 Admin SDKFCM 服务器协议:仅设置 data 键。

如果您需要 FCM 代表您的客户端应用处理通知显示,可使用通知消息。如果您需要代表客户端应用处理消息,可使用数据消息。

FCM 可以发送通知消息(包含可选的数据有效负载)。在此类情况下,FCM 会处理通知有效负载的显示,而客户端应用会处理数据有效负载。

通知消息

如果要进行测试,或要开展营销并重新吸引用户,您可以使用 Firebase 控制台发送通知消息

要使用 Admin SDK 或 FCM 协议以编程方式发送通知消息,可使用通知消息中用户可见部分所必需的预定义键值选项集来设置 notification 键。例如,下方所示为一款即时通讯应用中的 JSON 格式的通知消息。用户可能会在设备上看到标题为“Portugal vs. Denmark”、文本为“great match!”的消息:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"Portugal vs. Denmark",
      "body":"great match!"
    }
  }
}

应用在后台运行时,通知消息将被传递至通知面板。应用在前台运行时,消息由下列回调函数处理:

  • didReceiveRemoteNotification:(在 iOS 上)
  • onMessageReceived()(在 Android 上)。数据包中的 notification 键包含该通知。
  • onMessage()(在网页/JavaScript 上)。

如需可用于构建通知消息的预定义键的完整列表,请参阅参考文档:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "great match!",
      "Room" : "PortugalVSDenmark"
    }
  }
}

以上示例演示了顶级或常用的 data 字段的用法,该字段由收到消息的所有平台上的客户端解读。在每个平台上,客户端应用会在相应的回调中收到数据有效负载:

  • 在 Android 上,客户端应用在 onMessageReceived() 中接收数据消息,并相应地处理键值对。系统可以在用于启动您的 Activity 的 Intent 中检索数据有效负载。请参阅在 Android 应用中接收消息

  • 在 iOS 上,数据有效负载可在 didReceiveRemoteNotification: 中找到。请参阅在 iOS 客户端中接收消息

  • 对于网页/JavaScript 客户端,当网页在前台时,系统会在 onMessage() 中接收数据有效负载。当网页应用在后台时,有效负载将被传送至 Service Worker 的后台消息处理程序。请参阅在 JavaScript 客户端中接收消息

包含可选数据有效负载的通知消息

无论是通过编程方式还是通过 Firebase 控制台发送通知消息,您都可以在消息中包含由自定义键值对组成的可选有效负载。为此,请在通知编辑器中使用高级选项中的自定义数据字段。

接收同时包含通知和数据有效负载的消息时的应用行为取决于应用是在后台还是前台运行 - 特别是在接收时应用是否处于活动状态。

  • 在后台运行时,应用会在通知面板中接收通知有效负载,且仅在用户点按通知时处理数据有效负载。
  • 在前台运行时,您的应用将会接收一个消息对象,且两种有效负载都可用。

以下是包含 notification 键和 data 键的 JSON 格式的消息:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"Portugal vs. Denmark",
      "body":"great match!"
    },
    "data" : {
      "Nick" : "Mario",
      "Room" : "PortugalVSDenmark"
    }
  }
}

跨平台自定义消息

由 FCM v1 HTTP 协议发送的消息可以包含两种类型的 JSON 键对:

  • 由接收到消息的所有应用实例解读的一组通用键。
  • 仅由在指定平台上运行的应用实例解读的针对具体平台的键块。

针对具体平台的键块可让您灵活地针对不同平台自定义消息,以确保它们在被收到后得到正确处理。在许多情况下,可以在给定消息中同时使用通用键和针对具体平台的键。

何时使用通用键

  • 每当您定位到所有平台(iOS、Android 和网页)上的应用实例时
  • 当您向主题发送消息时

由所有应用实例(无论平台为何)解读的通用键为 message.notification.titlemessage.notification.bodymessage.data

何时使用针对具体平台的键

  • 当您想只向特定平台发送字段时
  • 要发送针对具体平台的字段以及通用键

每当您想仅向特定平台发送值时,请不要使用通用键,而是使用针对具体平台的键块。例如,要仅向 iOS 和网页(而不向 Android)发送通知,您必须针对 iOS 和网页各使用一个键块。

当您发送包含特定递送选项的消息时,请使用针对具体平台的键进行设置。您可以视需要为每个平台指定不同的值;但即使您想为各种平台设置本质上相同的值,也必须使用针对具体平台的键。这是因为每种平台对值的解读方式可能会略有不同 - 例如,存留时间在 Android 上设置为以秒为单位的到期时间,而在 iOS 上则设置为到期日期。

示例:包含针对具体平台的递送选项的通知消息

以下 v1 发送请求会向所有平台发送通用的通知标题和内容,但也会发送一些针对具体平台的覆盖内容。具体而言,该请求会:

  • 为 Android 和网页平台设置较长的存留时间,同时将 APNs (iOS) 消息设置为低优先级
  • 设置适当的键来定义用户在 Android 和 iOS 上点按相应通知的结果(分别是 click_actioncategory)。
{
  "message":{
     "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
     "notification":{
       "title":"Match update",
       "body":"Arsenal goal in added time, score is now 3-0"
     },
     "android":{
       "ttl":"86400s",
       "notification"{
         "click_action":"OPEN_ACTIVITY_1"
       }
     },
     "apns": {
       "headers": {
         "apns-priority": "5",
       },
       "payload": {
         "aps": {
           "category": "NEW_MESSAGE_CATEGORY"
         }
       }
     },
     "webpush":{
       "headers":{
         "TTL":"86400"
       }
     }
   }
 }

要全面、详细地了解消息正文中针对具体平台的块内提供的键,请参阅 HTTP v1 参考文档。如需详细了解如何构建包含消息正文的发送请求,请参阅构建发送请求

递送选项

FCM 为发送到 Android 设备的消息提供了一组特定的递送选项,并允许在 iOS 和网页上使用类似的选项。例如,“可折叠”消息行为在 Android 上通过 FCM 的 collapse_key 实现,在 iOS 上通过 apns-collapse-id 实现,在 JavaScript/网页上通过 Topic 实现。如需了解详情,请参阅本节和相关参考文档中的说明。

不可折叠消息和可折叠消息

不可折叠消息表示每一条消息都将被传递至设备。不可折叠消息可传递一些有用内容至手机应用,从而联系服务器以获取数据,这与“ping”(与内容无关)之类的可折叠消息相反。

聊天消息或关键消息都是典型的不可折叠消息。例如,在 IM 应用中,您可能想要传递每一条消息,因为它们的内容各不相同。

对于 Android,在不折叠的情况下,最多可存储 100 条消息。达到此限值后,所有存储的消息都将被舍弃。设备在重新联网后将收到一条特殊消息,提示已达到此上限。之后,应用可以正常处理该状况,一般情况下会请求与应用服务器完全同步。

可折叠消息在还未被传递至设备的情况下可能会被新消息替代。

可折叠消息的常见使用情形包括告知移动应用从服务器同步数据。为用户更新最新比分的体育应用就属于这种消息。只有最新的消息是相关的。

要在 Android 上将消息标记为可折叠,请在消息有效负载中添加 collapse_key 参数。FCM 允许应用服务器在任意指定时间内为每台 Android 设备使用最多 4 个不同的折叠键。也就是说,FCM 服务器可以为每台设备同时存储 4 条不同的可折叠消息,每一条都含有不同的折叠键。如果超出此限值,FCM 将仅保留 4 个折叠键,具体保留哪几个不一定。

我应该使用哪种消息?

从性能的角度来看,可折叠消息是更好的选择,但前提是您的应用不需要使用不可折叠消息。但是,如果您使用可折叠消息,则须切记:FCM 仅允许 FCM 连接服务器在任意指定时间内为每个注册令牌使用最多 4 个不同的折叠键。您不得超出此限值,否则将导致出现意外后果。

使用情景 如何发送
不可折叠 每一条消息对客户端应用都很重要,都需要传递。 默认情况下,除了通知消息外的所有消息都是不可折叠消息。
可折叠 当新消息使得相关的旧消息对客户端应用不再有用时,FCM 将替换掉旧消息。例如:用于从服务器启动数据同步的消息或过期的通知消息。 在消息请求中设置适当的参数:
  • collapseKey(在 Android 上)
  • apns-collapse-id(在 iOS 上)
  • Topic(在网页上)
  • collapse_key(在旧版协议中)(所有平台)

设置消息的优先级

Android 上下行消息的传递优先级有两种:普通优先级和高优先级。普通优先级和高优先级的消息传递方式如下:

  • 普通优先级。 这是数据消息的默认优先级。应用在前台运行时,普通优先级消息会被立即传递。当设备处于低电耗模式或应用处于待机模式时,此类消息可能会被延迟传递以节省电量。如果是对时间不太敏感的消息(例如新电子邮件通知、使界面保持同步或在后台同步应用数据),建议您选择普通传递优先级。

    如果在 Android 上收到请求在后台同步应用数据的普通优先级消息,您应该安排 FJD 作业JobIntentService 在网络可用时处理它。

  • 高优先级。FCM 会立即尝试传递高优先级消息,允许 FCM 服务在必要时唤醒休眠设备并运行一些有限的处理(包括非常有限的网络访问)。高优先级消息通常应该会使得用户与您的应用进行互动。如果 FCM 检测到未产生此行为,系统可能会降低您的消息的优先级。

    由于一小部分 Android 移动用户使用的是高延迟网络,因此请避免在显示通知之前打开与服务器的连接。在允许的处理时间结束之前回调服务器可能会让使用高延迟网络的用户面临风险。请在 FCM 消息中添加通知内容并立即显示该内容。如果您需要同步 Android 上的其他应用内内容,则可以安排 FJD 作业JobIntentService 在后台处理该内容。

以下示例示范的是一条普通优先级消息,该消息通过 FCM HTTP v1 协议发送,用于通知杂志订阅者有新内容可以下载:

{
  "message":{
    "topic":"subscriber-updates",
    "notification":{
      "body" : "This week's edition is now available.",
      "title" : "NewsMagazine.com",
    },
    "data" : {
      "volume" : "3.21.15",
      "contents" : "http://www.news-magazine.com/world-week/21659772"
    },
    "android":{
      "priority":"normal"
    },
    "apns":{
      "headers":{
        "apns-priority":"5"
      }
    },
    "webpush": {
      "headers": {
        "Urgency": "high"
      }
    }
  }
}

要了解有关设置消息优先级的针对具体平台的详细信息,请参阅以下文章:

设置消息的有效期

FCM 通常会在消息发出之后马上进行传递。但是,也有一些例外情况。例如,如果在 Android 平台上,设备有可能处于关闭、离线或不可用状态。FCM 可能会有意延迟消息传递,以防止应用消耗过多资源和对电池续航时间产生不良影响。

在这种情况下,FCM 会存储消息,等到可行时立即发送。尽管大多数情况下这样做都没什么问题,但有些应用可能永远不会传递延迟消息。举例来说,如果消息是来电或视频聊天通知,则它仅在通话终止之前的这段较短时间内有意义。或者,如果消息是活动邀请,那么如果在活动结束后才收到消息,它将毫无用处。

在 Android 和网页/JavaScript 上,您可以指定消息的最长有效期。此值必须是介于 0 至 2419200 秒(28 天)之间的一段持续时间,其对应于 FCM 存储并尝试传递消息的最长时间期限。不含此字段的请求默认为最长期限(4 周)。

以下是此功能的一些可能用途:

  • 视频聊天来电
  • 即将到期的邀请事件
  • 日历活动

指定消息有效期的另一个好处是 FCM 绝不会限制存留时间值为 0 秒的消息。也就是说,FCM 将尽全力保证必须现在传递、过时无效的消息得到传递。请注意,time_to_live 值为 0 表示消息在无法立即传递的情况下将被舍弃。不过,由于此类消息不会被存储,因此可以为发送通知消息提供最佳延时。

以下是包含 TTL 的请求示例:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "great match!",
      "Room" : "PortugalVSDenmark"
    },
    "apns":{
      "headers":{
        "apns-expiration":"1604750400"
      }
    },
    "android":{
      "ttl":"4500s"
    },
    "webpush":{
      "headers":{
        "TTL":"4500"
      }
    }
  }
}

接收多个发送者发送的消息

FCM 允许多方向同一客户端应用发送消息。例如,假设客户端应用是拥有多位撰稿者的文章聚合器,且每位撰稿者都应该能够在发布新文章时发送消息。此消息可能包含一个网址,供客户端应用下载该文章。利用 FCM,您可以让每一位撰稿者都能发送自己的消息,而不必将所有发送活动集中在一个位置。

要启用此功能,请确保您有每个发送者的发送者 ID。在申请注册时,客户端应用会多次提取令牌,每一次在受众群体字段中都有不同的发送者 ID,并使用与指定平台对应的令牌检索方法:

最后,与对应的发送者共享注册令牌,发送者将能够通过自己的身份验证密钥向客户端应用发送消息。

请注意,最多只能有 100 个发送者。

消息的有效期

当应用服务器向 FCM 发布消息并收到返回的消息 ID 时,并不意味着消息已传送至设备,而是表示其获准传递。消息在获准传递后的行为取决于很多因素。

在最佳的情况下,如果设备已连接至 FCM,屏幕处于开启状态且没有节流限制,那么消息将被立即传递。

如果设备已连接但是处于低电耗模式,则 FCM 将存储低优先级的消息,直到设备不再处于低电耗模式为止。此时 collapse_key 标记就有用武之地了:如果已存储一条含有相同折叠键(和注册令牌)的消息,且该消息正等待传递,则旧消息将被舍弃,新消息将取代其位置(即,旧消息将被新消息折叠起来)。但是,如果未设置折叠键,则新消息和旧消息都将被存储下来供以后传递。

如果设备未连接至 FCM,则消息将被存储,直至建立连接(再次遵循折叠键规则)。建立连接后,FCM 会将所有待处理消息传递到设备。如果设备不再建立连接(例如恢复出厂设置),则消息最终会超时,且将被从存储中舍弃。默认超时时间为四个星期,除非设置了 time_to_live 标记。

如需更深入地了解消息的传递情况:

  • 对于 Android:如果您希望在应用成功接收到消息时收到通知,可以按照相关指南使用 delivery_receipt_requested 功能。为此,您必须先设置 XMPP 服务器
  • 对于 Android、iOS 和网页:您可以使用 InstanceID API 来查看通过 FCM 注册令牌定位的设备与 FCM 建立连接的最近日期。

如果设备已有一个月未连接到 FCM,FCM 仍然会接受消息,但会立即将其舍弃。如果设备在您向其发送最后一条数据消息后的四个星期内建立连接,您的客户端会收到 onDeletedMessages() 回调。之后,应用可以正常处理该状况,一般情况下会请求与应用服务器完全同步。

最后,当 FCM 尝试向设备传递消息,而应用已被卸载时,FCM 将立刻舍弃该消息并使注册令牌无效。继续尝试向该设备发送消息将导致 NotRegistered 错误。

FCM 端口和防火墙

如果贵组织设有限制互联网上传/下载流量的防火墙,则您需要将其配置为允许移动设备连接 FCM 才能让网络上的设备接收消息。FCM 通常使用端口 5228,有时也使用 5229 和 5230。

对于传出连接,FCM 不会提供具体 IP,因为我们的 IP 范围更改频率过高,并且您的防火墙规则可能会过期,从而影响用户的体验。理想情况下,您可以将没有 IP 限制的端口 5228-5230 加入白名单。但是,如果您必须有 IP 限制,则应将 Google 15169 ASN 中列出的 IPv4 和 IPv6 列表中的所有 IP 地址列入白名单。这个列表很大,您应该计划每月更新一次自己的规则。防火墙 IP 限制导致的问题往往是间歇性的,并且难以诊断。

要为传入消息打开的端口:

  • 5228
  • 5229
  • 5230

要允许传出连接的端口:

以下选项之一(首选第一个选项):

  1. 没有 IP 限制
  2. Google 15169 ASN 中列出的 IP 列表内包含的所有 IP 地址。请务必每月至少更新一次此列表。

网络地址转换和/或有状态数据包检测防火墙:

如果您的网络实现了网络地址转换 (NAT) 或有状态数据包检测 (SPI),请通过端口 5228-5230 为我们的连接实现 30 分钟或更长时间的超时。这样,我们就能够提供可靠的连接,同时减少用户移动设备的电池消耗。

凭据

根据要实现的 FCM 功能的不同,您可能需要下列来自 Firebase 项目的凭据:

项目 ID 您的 Firebase 项目的唯一标识符,用在向 FCM v1 HTTP 端点发出的请求中。您可以在 Firebase 控制台的设置窗格中找到该值。
注册令牌 FCM SDK 为每个客户端应用实例生成的 ID。单一设备消息传递和设备组消息传递需要该令牌。请注意,注册令牌必须保密。
发送者 ID 您在创建 Firebase 项目时创建的唯一数字值,可在 Firebase 控制台设置窗格的云消息传递标签中找到。发送者 ID 用于标识可以向客户端应用发送消息的每个发送者。
访问令牌 一个只在短时间内有效的 OAuth 2.0 令牌,用于向对 HTTP v1 API 的请求进行授权。此令牌与属于您的 Firebase 项目的服务帐号相关联。要创建和轮替访问令牌,请按照向发送请求提供授权中所述的步骤操作。
服务器密钥(用于旧版协议)

用于授权您的应用服务器访问 Google 服务(包括通过 Firebase 云消息传递旧版协议发送消息)的服务器密钥。您可以在创建 Firebase 项目时获取服务器密钥。您可以在 Firebase 控制台设置窗格的云消息传递标签中查看此密钥。

重要提示:切勿在客户端代码中的任何位置包含服务器密钥。另外,请确保仅使用服务器密钥授权您的应用服务器。Android 密钥、iOS 密钥和浏览器密钥会被 FCM 拒绝。

发送以下问题的反馈:

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