FCM 消息简介

Firebase Cloud Messaging (FCM) 提供了众多消息传递选项和功能。本页中的内容旨在帮助您了解不同类型的 FCM 消息以及您可以将其用于哪些目的。

消息类型

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

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

通知消息包含一组用户可见的预定义键。与其相对,数据消息只包含用户定义的自定义键值对。通知消息可以包含可选的数据载荷。两种消息类型的载荷上限均为 4000 个字节,但从 Firebase 控制台发送消息时会强制执行 1024 个字符的限制。

使用情景 如何发送
通知消息 当客户端应用在后台运行时,FCM SDK 会代表客户端应用向最终用户设备显示消息。如果应用在收到通知时正在前台运行,应用的代码会决定行为。通知消息包含一组预定义的用户可见的键和一个由自定义键值对组成的可选的数据载荷。
  1. 在可信环境(例如 Cloud Functions 或应用服务器)中,使用 Admin SDK 或者 FCM 服务器协议:设置 notification 键。可能包含可选的数据载荷。 一律可折叠。

    请参阅一些显示通知示例并发送请求载荷。

  2. 使用 Notifications Composer:输入消息文本、标题等,然后发送。通过提供自定义数据添加可选的数据载荷。
数据消息 客户端应用负责处理数据消息。数据消息仅包含自定义键值对,没有保留键名(请参阅下文)。 在可信环境(例如 Cloud Functions 或应用服务器中),使用 Admin SDK 或者 FCM 服务器协议:仅设置 data 键。

当您的应用在后台运行时,如果您希望 FCM SDK 自动处理通知的显示,请使用通知消息。如果您希望使用自己的客户端应用代码处理消息,请使用数据消息。

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

通知消息

如果要进行测试,或者要开展营销、重新吸引用户,您可以使用 Firebase 控制台发送通知消息。Firebase 控制台提供基于分析的 A/B 测试,可帮助您优化和改进营销消息。

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

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

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

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

数据消息

使用自定义键值对设置适当的键,以将数据载荷发送至客户端应用。

例如,下方所示为上述同一即时通讯应用中的一条 JSON 格式的消息,在此消息中,信息封装在常用的 data 键中,且客户端应用需要解读相应内容:

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

上述示例显示了顶级或通用 data 字段的用法,该字段由接收消息的所有平台上的客户端解读。在每个平台上,客户端应用都会在回调函数中收到数据载荷。

数据消息加密

Android 传输层(请参阅 FCM 架构)使用点到点加密。您可以根据需要决定为数据消息使用端到端加密。FCM 不提供端到端解决方案。不过,您可以使用外部解决方案,例如 CapillaryDTLS

包含可选数据载荷的通知消息

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

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

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

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

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

跨平台自定义消息

Firebase Admin SDK 和 FCM v1 HTTP 协议都允许您的消息请求设置 message 对象中的所有可用字段。包括:

  • 通用字段集,由接收消息的所有应用实例解读。
  • 针对具体平台的字段集,如 AndroidConfigWebpushConfig,仅由在指定平台上运行的应用实例解读。

针对具体平台的字段块可让您灵活地针对不同平台自定义消息,以确保在收到消息后可以正确处理它们。FCM 后端会考虑所有指定参数并针对每个平台自定义消息。

何时使用通用字段

在以下情况下使用通用字段:

  • 面向所有平台(Apple、Android 和 Web)上的应用实例
  • 向主题发送消息

无论是哪个平台,所有应用实例都可以解读以下通用字段:

何时使用针对具体平台的字段

如果需要执行下列操作,请使用针对具体平台的字段:

  • 仅向特定平台发送字段
  • 发送通用字段以及针对具体平台的字段

当您仅希望向特定平台发送值时,请勿使用通用字段,而应使用针对具体平台的字段。例如,如需仅向 Apple 平台和 Web 发送通知,而不向 Android 发送通知,您必须针对 Apple 和 Web 各使用一组字段。

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

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

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

  • 为 Android 和 Web 平台设置较长的存留时间,同时将 APNs(Apple 平台)消息设置为低优先级
  • 设置相应的键来定义 Android 和 Apple 上的用户点按通知的结果,分别为 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 设备的消息提供了一组特定的递送选项,并允许在 Apple 平台和 Web 上使用类似的选项。例如,Android 通过 FCM 的 collapse_key 来支持“可折叠”消息行为,而 Apple 通过 apns-collapse-id,JavaScript/Web 通过 Topic 来支持该行为。如需了解详情,请参阅本节和相关参考文档中的说明。

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

“不可折叠”消息表示每一条消息都将被传递至设备。与无内容的“ping”之类的可折叠消息不同,不可折叠消息能传递一些有用内容至移动应用,从而联系服务器以获取数据。

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

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

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

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

如需在 Android 上将一条消息标记为可折叠,请在消息载荷中加入 collapse_key 参数。默认情况下,折叠键是在 Firebase 控制台中注册的应用软件包名称。FCM 服务器可以为每台设备同时存储 4 条不同的可折叠消息,每一条都含有不同的折叠键。如果超出此限值,FCM 将仅保留 4 个折叠键,具体保留哪几个不一定。

默认情况下,没有载荷的主题消息是可折叠消息。通知消息都可折叠,并且会忽略 collapse_key 参数。

我应该使用哪种消息?

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

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

设置消息的优先级

下行消息传递优先级有两种:普通优先级和高优先级。普通优先级和高优先级的消息传递方式如下(具体行为在不同的平台中略有差异):

  • 普通优先级。 应用在前台运行时,普通优先级消息会被立即传递。当应用在后台运行时,消息传递可能会延迟。如果是对时间不太敏感的消息(例如新电子邮件通知、使界面保持同步或在后台同步应用数据),建议您选择普通传递优先级。

  • 高优先级。即使设备处于低电耗模式,FCM 也会立即尝试传递高优先级消息。 高优先级消息适用于对时间敏感的用户可见内容。

以下是一条普通优先级消息的示例,该消息通过 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 和 Web/JavaScript 上,您可以指定消息的最长有效期。此值必须是介于 0 至 2,419,200 秒(28 天)之间的一段持续时间,其对应于 FCM 存储并尝试传递消息的最长时间期限。不含此字段的请求默认为最长期限(四周)。

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

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

指定消息有效期的另一个好处是 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 发布消息并收到返回的消息 ID 时,并不意味着消息已传递至设备,而是表示其获准传递。消息在获准传递后的行为取决于很多因素。

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

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

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

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

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

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

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

限制和扩缩

我们的目标是始终传递通过 FCM 发送的每条消息。但是,传递每条消息有时会导致整体用户体验不佳。在其他情况下,我们需要设定限制,以确保 FCM 为所有发送者提供可扩缩的服务。

可折叠的消息限制

如上所述,可折叠的消息是设计为可在彼此之上折叠的无内容通知。如果开发者过于频繁地向应用重复相同的消息,我们会延迟(限制)消息以减少对用户电池的影响。

例如,如果您向单个设备发送大量新电子邮件同步请求,我们可能会将下一个电子邮件同步请求延迟几分钟,以便设备可以以较低的平均速度进行同步。严格执行这种限制是为了限制对用户的电池的影响。

如果您的用例需要高突发发送模式,那么不可折叠的消息可能是正确的选择。请确保在此类消息中包含内容以降低电池损耗。

我们将可折叠的消息限制为每台设备每个应用突发 20 条消息,每 3 分钟补充 1 条消息。

XMPP 服务器限制

我们将连接到 FCM XMPP 服务器的速率限制为每个项目每分钟 400 次连接。这不会给消息传递带来问题,但对于确保我们系统的稳定性非常重要。

针对每个项目,FCM 允许存在 2500 个并行连接。

向单一设备发送消息的最大速率

在 Android 平台上,您每分钟最多可以向单一设备发送 240 条消息,每小时最多可以发送 5,000 条消息。这一高阈值是为了满足短时间的流量突发,例如当用户通过聊天快速互动时。此限制可防止发送逻辑中的错误无意中耗尽设备上的电池电量。

在 iOS 平台上,当发送消息的速率超过 APNs 限制时,系统会返回错误。

上行消息限额

我们将每个项目的上行消息限制为 1,500,000 条/分钟,以避免上行目标服务器过载。

我们将每台设备的上行消息限制为 1000 条/分钟,以防止因不良应用行为导致电池电量耗尽。

主题消息限额

主题订阅添加/移除率限制为每个项目 3000 QPS。

有关消息发送速率的信息,请参阅扇出限制

扇出限制

消息扇出是指向多台设备发送消息的过程,例如当您定位主题和群组,或使用 Notifications Composer 定位目标设备或细分用户群时。

消息扇出不是瞬时间完成的,因此有时候您会同时运行多个扇出。我们将每个项目中并发进行的消息扇出数量限制为 1000。超出此值之后,我们可能会拒绝其他扇出请求,或者推迟请求中的扇出,直到某些正在进行的扇出完成为止。

实际可实现的扇出率受同时请求扇出的项目数量的影响。单个项目的扇出率为 10,000 QPS 并不罕见,但该数字与系统的总负载密切相关,并无保证。值得注意的是,可用的扇出容量在项目之间而不是在扇出请求之间分配。因此,如果您的项目有两个正在进行的扇出,那么每个扇出只能使用可用扇出率的一半。最大化扇出速度的推荐方法是一次只有一个进行中的活跃扇出。

FCM 端口和防火墙

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

对于通过网络连接的设备,FCM 不会提供具体 IP 地址,因为我们的 IP 地址范围更改非常频繁,您的防火墙规则可能会过时,从而影响用户的体验。理想情况下,您可以将端口 5228-5230 和 443 加入许可名单,并且不施加任何 IP 限制。但是,如果您必须设置 IP 限制,则应将 goog.json 中列出的所有 IP 地址列入许可名单。此大型列表会定期更新,因此建议您每月更新规则。防火墙 IP 限制导致的问题往往是间歇性的,并且难以诊断。

我们提供了一组可以列入许可名单的域名,而不是 IP 地址。这些主机名如下所示。如果我们开始使用其他主机名,则会在此处更新列表。“针对您的防火墙使用域名”规则不一定能在防火墙设备中正常运行。

要打开的 TCP 端口

  • 5228
  • 5229
  • 5230
  • 443

要打开的主机名

  • mtalk.google.com
  • mtalk4.google.com
  • mtalk-staging.google.com
  • mtalk-dev.google.com
  • alt1-mtalk.google.com
  • alt2-mtalk.google.com
  • alt3-mtalk.google.com
  • alt4-mtalk.google.com
  • alt5-mtalk.google.com
  • alt6-mtalk.google.com
  • alt7-mtalk.google.com
  • alt8-mtalk.google.com
  • android.apis.google.com
  • device-provisioning.googleapis.com
  • firebaseinstallations.googleapis.com

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

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

凭据

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

项目 ID 您的 Firebase 项目的唯一标识符,用于向 FCM v1 HTTP 端点发出请求。您可以在 Firebase 控制台设置窗格中找到该值。
注册令牌

用于标识每个客户端应用实例的唯一令牌字符串。 单一设备消息传递和设备组消息传递需要注册令牌。请注意,注册令牌必须保密。

发送者 ID 您在创建 Firebase 项目时系统创建的唯一数字值,可在 Firebase 控制台设置窗格的 Cloud Messaging 标签页找到。发送者 ID 用于标识可以向客户端应用发送消息的每个发送者。
访问令牌 一个只在短时间内有效的 OAuth 2.0 令牌,用于对发送到 HTTP v1 API 的请求进行授权。此令牌与属于您的 Firebase 项目的服务帐号相关联。如需创建和轮替访问令牌,请按照向发送请求提供授权中所述的步骤操作。
服务器密钥(用于旧版协议)

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

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