Firebase Cloud Messaging (FCM) 提供了众多消息传递选项和功能。本页中的内容旨在帮助您了解不同类型的 FCM 消息以及您可以将其用于哪些目的。
消息类型
您可以使用 FCM 向客户端发送两种类型的消息:
- 通知消息,有时被称为“显示消息”。此类消息由 FCM SDK 自动处理。
- 数据消息,由客户端应用处理。
通知消息包含一组用户可见的预定义键。与其相对,数据消息只包含用户定义的自定义键值对。通知消息可以包含可选的数据载荷。两种消息类型的载荷上限均为 4096 个字节,但从 Firebase 控制台发送消息时会强制执行 1000 个字符的限制。
使用情景 | 如何发送 | |
---|---|---|
通知消息 | 当客户端应用在后台运行时,FCM SDK 会代表客户端应用向最终用户设备显示消息。如果应用在收到通知时正在前台运行,应用的代码会决定行为。通知消息包含一组预定义的用户可见的键和一个由自定义键值对组成的可选的数据载荷。 |
|
数据消息 | 客户端应用负责处理数据消息。数据消息仅包含自定义键值对,没有保留键名(请参阅下文)。 | 在可信环境(例如 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!" } } }
应用在后台运行时,通知消息将被传递至通知面板。应用在前台运行时,消息由回调函数处理。
如需可用于构建通知消息的预定义键的完整列表,请参阅 HTTP v1 协议通知对象参考文档。
数据消息
使用自定义键值对设置适当的键,以将数据载荷发送至客户端应用。
例如,下方所示为上述同一即时通讯应用中的一条 JSON 格式的消息,在此消息中,信息封装在常用的 data
键中,且客户端应用需要解读相应内容:
{ "message":{ "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...", "data":{ "Nick" : "Mario", "body" : "great match!", "Room" : "PortugalVSDenmark" } } }
上述示例显示了顶级或通用 data
字段的用法,该字段由接收消息的所有平台上的客户端解读。在每个平台上,客户端应用都会在回调函数中收到数据载荷。
数据消息加密
Android 传输层(请参阅 FCM 架构)使用点到点加密。您可以根据需要决定为数据消息使用端到端加密。FCM 不提供端到端解决方案。不过,您可以使用外部解决方案,例如 Capillary 或 DTLS。
包含可选数据载荷的通知消息
无论是通过编程方式还是通过 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
对象中的所有可用字段。包括:
- 通用字段集,由接收消息的所有应用实例解读。
- 针对具体平台的字段集,如
AndroidConfig
和WebpushConfig
,仅由在指定平台上运行的应用实例解读。
针对具体平台的字段块可让您灵活地针对不同平台自定义消息,以确保在收到消息后可以正确处理它们。FCM 后端会考虑所有指定参数并针对每个平台自定义消息。
何时使用通用字段
在以下情况下使用通用字段:
- 面向所有平台(Apple、Android 和 Web)上的应用实例
- 向主题发送消息
无论是哪个平台,所有应用实例都可以解读以下通用字段:
何时使用针对具体平台的字段
如果需要执行下列操作,请使用针对具体平台的字段:
- 仅向特定平台发送字段
- 发送通用字段以及针对具体平台的字段
当您仅希望向特定平台发送值时,请勿使用通用字段,而应使用针对具体平台的字段。例如,如需仅向 Apple 平台和 Web 发送通知,而不向 Android 发送通知,您必须针对 Apple 和 Web 各使用一组字段。
当您发送包含特定递送选项的消息时,请使用针对具体平台的字段进行设置。 您可以根据需要为每个平台指定不同的值。即使您想为各平台设置的值实质上是相同的,也必须使用针对具体平台的字段。这是因为每种平台对值的解读方式可能会略有不同,例如,存留时间在 Android 上设置为以秒为单位的到期时间,而在 Apple 上则设置为到期日期。
示例:包含针对具体平台的递送选项的通知消息
以下 v1 发送请求会向所有平台发送通用的通知标题和内容,但也会发送一些针对具体平台的覆盖内容。 具体而言,该请求会:
- 为 Android 和 Web 平台设置较长的存留时间,同时将 APNs(Apple 平台)消息设置为低优先级
- 设置相应的键来定义 Android 和 Apple 上的用户点按通知的结果,分别为
click_action
和category
。
{ "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 将替换掉旧消息。例如:用于从服务器启动数据同步的消息或过期的通知消息。 | 在消息请求中设置适当的参数:
|
设置消息的优先级
下行消息传递优先级有两种:普通优先级和高优先级。普通优先级和高优先级的消息传递方式如下(具体行为在不同的平台中略有差异):
普通优先级。 应用在前台运行时,普通优先级消息会被立即传递。当应用在后台运行时,消息传递可能会延迟。如果是对时间不太敏感的消息(例如新电子邮件通知、使界面保持同步或在后台同步应用数据),建议您选择普通传递优先级。
高优先级。即使设备处于低电耗模式,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" } } } }
如需了解有关设置消息优先级的针对具体平台的详细信息,请参阅以下文章:
- APNs 文档
- 设置和管理消息优先级 (Android)
- Web 推送消息的紧急程度
生命攸关的应用场景
FCM API 并非专为紧急警报或其他高风险活动而设计,在这类活动中,这些 API 的使用或故障可能会导致死亡、人身伤害或环境破坏(例如核设施运营、空中交通管制或生命维持系统)。《服务条款》的第 4 条 a.7 款明确禁止这类使用。您需要自行负责管理应用是否遵守这些条款,并对因违反这些条款而造成的任何损害负责。Google“按原样”提供 API,并保留以任何理由随时停止提供 API 或其任何部分或功能,或是停止您对其的访问权限的权利,而不对您或您的用户承担任何责任或其他义务。
设置消息的有效期
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 会将所有待处理消息传递到设备。如果设备不再建立连接(例如使用了恢复出厂设置),则消息最终会超时,且将被从 FCM 存储中舍弃。除非设置了 time_to_live
标志,否则默认的超时时间为四个星期。
如需更深入地了解消息的传递情况:
如需详细了解 Android 或 Apple 平台上的消息传递,请参阅 FCM 报告信息中心,其中记录了在 Apple 和 Android 设备上发送和打开的消息数量,以及 Android 应用的“展示次数”(用户看到的通知条数)数据。
对于启用了直接通道消息传递的 Android 设备,如果设备已有一个多月未连接到 FCM,FCM 仍然会接受消息,但会立即将其舍弃。如果设备在您向其发送最后一条数据消息后的四个星期内建立连接,您的客户端会收到 onDeletedMessages() 回调。之后,应用可以正常处理该状况,一般情况下会请求与应用服务器进行一次完全同步。
最后,当 FCM 尝试向设备传递消息,而应用已被卸载时,FCM 将立刻舍弃该消息并废弃注册令牌。其后尝试向该设备发送消息将导致 NotRegistered
错误。
节流和配额
我们的目标是始终传递通过 FCM 发送的每条消息。但是,传递每条消息有时会导致整体用户体验不佳。在其他情况下,我们需要设定限制,以确保 FCM 为所有发送者提供可扩缩的服务。 本部分所述的限制和配额类型有助于我们平衡这些重要因素。
下行消息节流
HTTP v1 API 为下行消息传递引入了每项目每分钟配额。默认配额为每分钟 60 万条消息,可覆盖超过 99% 的 FCM 开发者,同时保护系统稳定性并最大限度地减少项目激增的影响。
流量激增模式可能会导致超出配额的错误。在超出配额的情况下,系统会响应 HTTP 状态代码 429 (QUOTA_EXCEEDED),直到配额在下一分钟内得到重新补充。在过载情况下,系统也可能会返回 429 响应,因此强烈建议您根据发布的建议处理 429 响应。
请注意:
- 下行配额用于衡量消息数,而非请求数。
- 系统会统计客户端错误(HTTP 状态代码 400-499,429 除外)。
- 配额按分钟计算,但这些分钟数并非与时钟一致。
监控配额
您可以在 Google Cloud 控制台中查看配额、用量和错误:
- 前往 Google Cloud 控制台
- 选择 API 和服务
- 从表格列表中选择 Firebase Cloud Messaging API
- 选择配额和系统限制。
注意:这些图表的时间与配额分钟数并不完全一致,这意味着,即使流量似乎低于配额,也可能会返回 429 响应。
申请增加配额
在申请增加配额之前,请确保:
- 您的用量通常每天至少连续 5 分钟 ≥ 配额的 80%。
- 客户端错误率低于 5%,尤其是在峰值流量期间。
- 您遵循大规模发送消息的最佳实践。
如果您符合这些条件,可以提交配额增加申请(最多可增加 25%),FCM 会尽量满足您的申请(但无法保证一定会增加配额)。
如果您因即将到来的发布或临时活动而需要更多下行消息传递配额,请至少提前 15 天申请配额,以便我们有足够的时间处理您的申请。对于较大的申请(每分钟超过 1800 万条消息),您需要至少提前 30 天通知我们。发布和特殊活动申请仍需遵守客户端错误率和最佳实践要求。
另请参阅有关FCM 配额的常见问题解答。
主题消息限额
主题订阅添加/移除率限制为每个项目 3000 QPS。
有关消息发送速率的信息,请参阅扇出限制。
扇出限制
消息扇出是指向多台设备发送消息的过程,例如当您定位主题和群组,或使用 Notifications Composer 定位目标设备或细分用户群时。
消息扇出不是瞬时间完成的,因此有时候您会同时运行多个扇出。我们将每个项目中并发进行的消息扇出数量限制为 1000。超出此值之后,我们可能会拒绝其他扇出请求,或者推迟请求中的扇出,直到某些正在进行的扇出完成为止。
实际可实现的扇出率受同时请求扇出的项目数量的影响。单个项目的扇出率为 10,000 QPS 并不罕见,但该数字与系统的总负载密切相关,并无保证。值得注意的是,可用的扇出容量在项目之间而不是在扇出请求之间分配。因此,如果您的项目有两个正在进行的扇出,那么每个扇出只能使用可用扇出率的一半。最大化扇出速度的推荐方法是一次只有一个进行中的活跃扇出。
可折叠的消息限制
如上所述,可折叠的消息是设计为可在彼此之上折叠的无内容通知。如果开发者过于频繁地向应用重复相同的消息,我们会延迟(限制)消息以减少对用户电池的影响。
例如,如果您向单个设备发送大量新电子邮件同步请求,我们可能会将下一个电子邮件同步请求延迟几分钟,以便设备可以以较低的平均速度进行同步。严格执行这种限制是为了限制对用户的电池的影响。
如果您的用例需要高突发发送模式,那么不可折叠的消息可能是正确的选择。请确保在此类消息中包含内容以降低电池损耗。
我们将可折叠的消息限制为每台设备每个应用突发 20 条消息,每 3 分钟补充 1 条消息。
XMPP 服务器限制
我们将连接到 FCM XMPP 服务器的速率限制为每个项目每分钟 400 次连接。这不会给消息传递带来问题,但对于确保系统的稳定性非常重要。针对每个项目,FCM 允许存在 2500 个并行连接。
对于使用 XMPP 的上行消息传递,FCM 将上行消息限制为每个项目每分钟 1,500,000 条,以避免上行目标服务器过载。
我们将每台设备的上行消息限制为 1000 条/分钟,以防止因不良应用行为导致电池电量耗尽。
向单一设备发送消息的最大速率
在 Android 平台上,您每分钟最多可以向单一设备发送 240 条消息,每小时最多可以发送 5,000 条消息。这一高阈值是为了满足短时间的流量突发,例如当用户通过聊天快速互动时。此限制可防止发送逻辑中的错误无意中耗尽设备上的电池电量。
在 iOS 平台上,当发送消息的速率超过 APNs 限制时,系统会返回错误。
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 分钟或更长时间的超时。这样,我们就能够提供可靠的连接,同时减少用户移动设备的电池消耗。
VPN 互动和可绕过性
Firebase Cloud Messaging 会采取各种措施来确保从手机到服务器的推送消息连接尽可能可靠且可用。使用 VPN 会使这项工作变得复杂。
VPN 会遮盖 FCM 调整连接所需的底层信息,以最大限度提高可靠性和延长电池续航时间。在某些情况下,VPN 会主动中断长期有效的连接,从而由于错过或延迟消息或是电池消耗较高而导致用户体验不佳。如果 VPN 配置允许,我们会使用加密连接(通过基础网络 Wi-Fi 或 LTE)绕过 VPN,以确保提供可靠且省电的体验。FCM 对可绕过的 VPN 的使用特定于 FCM 推送通知渠道。其他 FCM 流量(例如注册流量)会使用处于活动状态的 VPN。当 FCM 连接绕过 VPN 时,它会失去 VPN 可能提供的其他优势,例如 IP 遮盖。
不同的 VPN 会采用不同的方法来控制是否可以绕过它。如需了解相关说明,请参阅您使用的特定 VPN 的文档。
如果 VPN 未配置为可绕过,Firebase Cloud Messaging 将使用 VPN 网络连接到服务器。这可能会导致消息延迟一段时间,并且可能会导致电池用量增加,因为 Cloud Messaging 会通过 VPN 连接来维持连接。
凭据
根据要实现的 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 旧版协议发送消息)的服务器密钥。 重要提示:切勿在客户端代码中的任何位置包含服务器密钥。另外,请确保在为您的应用服务器授权时仅使用服务器密钥。Android、Apple 平台和浏览器密钥会被 FCM 拒绝。 |