获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

关于 FCM 消息

Firebase 云消息传递 (FCM) 提供了广泛的消息传递选项和功能。此页面中的信息旨在帮助您了解不同类型的 FCM 消息以及您可以使用它们做什么。

消息类型

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

  • 通知消息,有时被认为是“显示消息”。这些由 FCM SDK 自动处理。
  • 数据消息,由客户端应用程序处理。

通知消息包含一组预定义的用户可见键。相比之下,数据消息仅包含用户定义的自定义键值对。通知消息可以包含可选的数据负载。两种消息类型的最大有效负载均为 4000 字节,但从 Firebase 控制台发送消息时除外,该控制台强制执行 1024 个字符的限制。

使用场景如何发送
通知消息FCM 代表客户端应用程序自动向最终用户设备显示消息。通知消息具有一组预定义的用户可见键和自定义键值对的可选数据有效负载。
  1. Cloud Functions或您的应用服务器等可信环境中,使用Admin SDKFCM 服务器协议:设置notification密钥。可能有可选的数据负载。始终可折叠。

    查看显示通知和发送请求有效负载的一些示例

  2. 使用通知编辑器:输入消息文本、标题等,然后发送。通过提供自定义数据添加可选数据负载。
数据信息客户端应用程序负责处理数据消息。数据消息只有自定义键值对,没有保留键名(见下文)。Cloud Functions或您的应用服务器等可信环境中,使用Admin SDKFCM 服务器协议:仅设置data密钥。

当您希望 FCM 代表您的客户端应用处理显示通知时,请使用通知消息。当您想要处理客户端应用程序上的消息时,请使用数据消息。

FCM 可以发送包含可选数据负载的通知消息。在这种情况下,FCM 处理通知负载的显示,客户端应用程序处理数据负载。

通知消息

对于测试或营销和用户重新参与,您可以使用 Firebase 控制台发送通知消息。 Firebase 控制台提供基于分析的A/B 测试,以帮助您优化和改进营销信息。

要使用 Admin SDK 或 FCM 协议以编程方式发送通知消息,请使用通知消息的用户可见部分的必要预定义键值选项集设置notification键。例如,这是 IM 应用程序中的 JSON 格式的通知消息。用户可能会看到标题为“葡萄牙 vs. 丹麦”和文本“非常匹配!”的消息。在设备上:

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

当应用程序在后台时,通知消息会发送到通知托盘。对于前台应用程序,消息由回调函数处理。

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

数据信息

使用您的自定义键值对设置适当的键,以将数据负载发送到客户端应用程序。

例如,在与上述相同的 IM 应用程序中,这是一条 JSON 格式的消息,其中信息封装在公共data密钥中,客户端应用程序应解释内容:

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

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

数据消息加密

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

带有可选数据负载的通知消息

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

接收包含通知和数据有效负载的消息时,应用程序的行为取决于应用程序是在后台还是前台 - 基本上,它在接收时是否处于活动状态。

  • 在后台时,应用程序在通知托盘中接收通知负载,并且仅在用户点击通知时处理数据负载。
  • 在前台时,您的应用会收到一个消息对象,其中包含两个可用的有效负载。

这是一条 JSON 格式的消息,其中包含notification键和data键:

{
  "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”这样的可折叠消息到移动应用程序以联系服务器以获取数据。

不可折叠消息的一些典型用例是聊天消息或关键消息。例如,在 IM 应用程序中,您可能希望传递每条消息,因为每条消息都有不同的内容。

对于 Android,最多可以存储 100 条消息而不会折叠。如果达到限制,则丢弃所有存储的消息。当设备重新联机时,它会收到一条特殊消息,指示已达到限制。然后,应用程序可以正确处理这种情况,通常是通过从应用程序服务器请求完全同步。

可折叠消息是可以被新消息替换的消息,如果它还没有被传递到设备。

可折叠消息的常见用例是用于告诉移动应用从服务器同步数据的消息。一个例子是一个体育应用程序,它用最新的分数更新用户。只有最近的消息是相关的。

要在 Android 上将消息标记为可折叠,请在消息负载中包含collapse_key参数。默认情况下,折叠键是在 Firebase 控制台中注册的应用包名称。 FCM 服务器可以同时为每个设备存储四个不同的可折叠消息,每个消息都有一个不同的折叠键。如果超过这个数字,FCM 只保留四个折叠键,不保证保留哪些。

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

我应该使用哪个?

从性能的角度来看,可折叠消息是更好的选择,前提是您的应用不需要使用不可折叠消息。但是,如果您使用可折叠消息,请记住 FCM 仅允许 FCM 在任何给定时间为每个注册令牌使用最多四个不同的折叠密钥。您不得超过此数量,否则可能会导致不可预知的后果。

使用场景如何发送
不可折叠每条消息对客户端应用程序都很重要,需要传递。除通知消息外,默认情况下所有消息都是不可折叠的。
可折叠当有新消息呈现与客户端应用程序无关的旧消息时,FCM 会替换旧消息。例如:用于从服务器启动数据同步的消息,或过时的通知消息。在您的消息请求中设置适当的参数:
  • 安卓上的collapseKey
  • 苹果上apns-collapse-id
  • 网络Topic
  • 旧协议中的collapse_key (所有平台)

设置消息的优先级

为下游消息分配传递优先级有两种选择:正常优先级和高优先级。尽管不同平台的行为略有不同,但正常和高优先级消息的传递方式如下:

  • 正常优先。当应用程序处于前台时,会立即传递普通优先级消息。对于后台应用程序,交付可能会延迟。对于时间敏感度较低的消息,例如新电子邮件通知、保持 UI 同步或在后台同步应用程序数据,请选择正常传递优先级。

  • 高优先级。即使设备处于打盹模式,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 存储和尝试传递消息的最长时间。不包含此字段的请求默认为最长 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 发布消息并接收到消息 ID 时,并不意味着该消息已传递到设备。相反,这意味着它已被接受交付。消息被接受后会发生什么取决于许多因素。

在最好的情况下,如果设备连接到 FCM,屏幕打开并且没有限制限制,则消息会立即传递。

如果设备已连接但处于打盹状态,则 FCM 会存储一条低优先级消息,直到设备处于打盹状态。这就是collapse_key标志发挥作用的地方:如果已经存储了具有相同折叠密钥(和注册令牌)并等待传递的消息,则旧消息将被丢弃,新消息取而代之(即旧消息)消息被新消息折叠)。但是,如果未设置折叠键,则新旧消息都将被存储以供将来传递。

如果设备未连接到 FCM,则将存储消息,直到建立连接(再次遵守折叠密钥规则)。建立连接后,FCM 会将所有未决消息传送到设备。如果设备不再连接(例如,如果它已恢复出厂设置),则消息最终会超时并从 FCM 存储中丢弃。默认超时为四个星期,除非设置了time_to_live标志。

要更深入地了解消息的传递:

    要更深入地了解 Android 或 Apple 平台上的消息传递,请参阅FCM 报告仪表板,它记录了在 Apple 和 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/分钟,以避免上游目标服务器过载。

我们将每台设备的上游消息限制为每分钟 1,000 条,以防止电池因不良应用行为而耗尽。

主题消息限制

主题订阅添加/删除速率限制为每个项目 3,000 QPS。

有关消息发送速率,请参阅Fanout Throttling

扇出节流

消息扇出是将消息发送到多个设备的过程,例如当您定位主题和组时,或者当您使用通知编辑器定位受众或用户细分时。

消息扇出不是即时的,因此有时您会同时进行多个扇出。我们将每个项目的并发消息扇出数限制为 1,000。之后,我们可能会拒绝额外的扇出请求或推迟请求的扇出,直到一些已经在进行中的扇出完成。

实际可实现的扇出率受同时请求扇出的项目数量的影响。单个项目的扇出率 10,000 QPS 并不少见,但这个数字并不是保证,而是系统总负载的结果。需要注意的是,可用的扇出容量在项目之间而不是在扇出请求之间分配。因此,如果您的项目有两个正在进行中的扇出,那么每个扇出只会看到可用扇出率的一半。最大化扇出速度的推荐方法是一次只进行一个活动扇出。

FCM 端口和防火墙

如果您的组织有防火墙来限制进出 Internet 的流量,您需要将其配置为允许移动设备与 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 项目中的以下凭据:

项目编号您的 Firebase 项目的唯一标识符,用于对 FCM v1 HTTP 端点的请求。此值在Firebase 控制台设置窗格中可用。
注册令牌

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

发件人ID创建 Firebase 项目时创建的唯一数值,可在 Firebase 控制台“设置”窗格的“云消息传递”选项卡中找到。发件人 ID 用于标识可以向客户端应用程序发送消息的每个发件人。
访问令牌一种短期 OAuth 2.0 令牌,用于授权对 HTTP v1 API 的请求。此令牌与属于您的 Firebase 项目的服务帐号相关联。要创建和轮换访问令牌,请按照授权发送请求中描述的步骤进行操作。
服务器密钥(用于旧协议)

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

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