了解消息传送

FCM 提供了三组工具,可帮助您深入了解消息传送情况:

  • Firebase 控制台消息传送报告
  • 来自 Firebase Cloud Messaging Data API 的汇总 Android SDK 传送指标
  • 将数据全面导出至 Google BigQuery

本页介绍的报告工具都需要使用 Google Analytics(分析)才能正常运行。如果您的项目未启用 Google Analytics(分析),您可以在 Firebase 项目设置的集成标签页中进行设置。

请注意,由于需要对分析数据执行批量处理,因此该页面上许多统计信息的报告可能会延迟最多 24 小时。

消息传送报告

在 Firebase 控制台中的报告标签页中,对于向 Android 或 Apple 平台 FCM SDK 发送的消息,包括通过 Notifications Composer 和 FCM API 发送的消息,您可以查看以下数据:

  • 发送次数 - 数据消息或通知消息已加入队列或已成功传递到第三方服务(例如 APNs)以进行传送。如需了解详情,请参阅消息的生命周期
  • 已收到(仅在 Android 设备上提供)- 应用已收到数据消息或通知消息。当接收 Android 设备安装了 FCM SDK 18.0.1 或更高版本时,才可以获得此数据。
  • 展示次数(仅针对 Android 设备上的通知消息提供)- 当应用在后台运行时,显示通知 (display notification) 已在设备上显示。
  • 打开次数 - 用户打开通知消息。仅针对应用在后台运行时收到的通知报告此数据。

此数据针对所有带有通知载荷的消息以及所有带标签数据消息提供。如需详细了解标签,请参阅为消息添加分析标签

在查看消息报告时,您可以设置所显示数据的日期范围,还可以选择将其导出为 CSV。您也可以按以下条件执行过滤:

  • 平台(iOS 或 Android)
  • 应用
  • 自定义分析标签

为消息添加分析标签

为消息加标签对于自定义分析非常有用,这将允许您按标签或标签集过滤传送统计信息。如需向通过 HTTP v1 API 发送的消息添加标签,您可以设置消息对象中的“fcmOptions.analyticsLabel”字段,或特定于平台的“AndroidFcmOptions”或“ApnsFcmOptions”字段。

分析标签是文本字符串,格式为:^[a-zA-Z0-9-_.~%]{1,50}$。标签可以包括大小写字母、数字和以下符号:

  • -
  • ~
  • %

长度上限为 50 个字符。您每天最多可以指定 100 个唯一标签;如果为消息添加的标签数量超出此上限,则不会报告相应消息。

在 Firebase 控制台的消息报告标签页中,您可以搜索所有现有标签的列表,并单独或组合应用这些标签来过滤所显示的统计信息。

通过 FCM Data API 的汇总传送数据

借助 Firebase Cloud Messaging Data API,您可以检索相关信息,从而了解发往 Android 应用的消息请求的结果。此 API 可为一个项目中所有支持数据收集的 Android 设备提供汇总的数据。这包括无延迟传送的消息的百分比,以及 Android 传输层中延迟或丢弃的消息数量。评估此数据可以揭示消息传送的主要趋势,并帮助您找出有效的方法来提高您的发送请求 (send request) 的性能。如需了解报告中可用的日期范围,请参阅汇总数据时间轴

此 API 提供给定应用可用的所有数据。请参阅这个 API 参考文档

数据是如何细分的?

传送数据是按应用、日期和分析标签细分的。对此 API 的调用会针对日期、应用和分析标签的每个组合返回数据。例如,单个 androidDeliveryData JSON 对象将如下所示:

 {
  "appId": "1:23456789:android:a93a5mb1234efe56",
  "date": {
    "year": 2021,
    "month": 1,
    "day": 1
  },
  "analyticsLabel": "foo",
  "data": {
    "countMessagesAccepted": "314159",
    "messageOutcomePercents": {
      "delivered": 71,
      "pending": 15
    },
   "deliveryPerformancePercents": {
      "deliveredNoDelay": 45,
      "delayedDeviceOffline": 11
    }
  }

如何解读指标

传送数据概述了符合以下各个指标的消息所占的百分比。一条信息可能符合多个指标。由于数据的采集方式和汇总指标的粒度级别限制,有些消息结果不会体现到指标中,因此以下百分比之和不等于 100%。

接受的消息数

此数据集内包含的唯一计数是 FCM 接受以传送到 Android 设备的消息数。所有百分比都使用此值作为分母。请注意,此计数不包括定位到已在其设备上停止收集使用情况和诊断信息的用户的消息。

消息结果百分比

MessageOutcomePercents 对象中包含的字段提供有关消息请求的结果的信息。这些类别是互相排斥的。它可以回答“我的消息是否被传送?”和“导致消息丢失的原因是什么?”这样的问题。

例如,如果 droppedTooManyPendingMessages 字段值较高,则表示应用实例接收的不可折叠消息数量超出了 FCM 的待处理消息上限(100 条)。为了缓解这种情况,请确保您的应用会处理对 onDeletedMessages 的调用,并考虑发送可折叠的消息。同样,高百分比的 droppedDeviceInactive 可能表示需要更新服务器上的注册令牌,从而移除过时令牌并将其从主题退订。请参阅管理 FCM 注册令牌,了解此方面的最佳实践。

传送性能百分比

DeliveryPerformancePercents 对象中的字段提供有关成功传送的消息的信息。它可以回答诸如“我的消息是否出现延迟?”以及“消息为什么延迟?”这样的问题。例如,如果 delayedMessageThrottled 的值较高,则表示您超出了每台设备的最大限制,因此应该调整发送消息的速率。

消息分析百分比

此对象提供有关所有消息发送的更多信息。priorityLowered 字段表示使优先级从 HIGH 降低至 NORMAL 的已接受消息的百分比。如果此值较高,请尝试减少发送高优先级的消息,或确保在发送高优先级消息后始终显示通知。如需了解详情,请参阅关于消息优先级的文档

这些数据与导出到 BigQuery 的数据有何不同?

BigQuery 导出可提供关于消息是否被 FCM 后端接受以及设备上 SDK 中的消息传送情况(FCM 架构中的第 2 步和第 4 步)的单独消息记录。此数据对于确保各条信息被接受和传送很重要。请在下一部分中详细了解 BigQuery 数据导出

相比之下,Firebase Cloud Messaging Data API 提供关于 Android 传输层(或 FCM 架构的第 3 步)所发生的情况的详细信息。通过这些数据,您可以深入了解从 FCM 后端向 Android SDK 传送消息的情况。它对于显示消息在传输过程中延迟或丢弃的趋势尤其有用。

在某些情况下,这两个数据集可能并不精准匹配,原因如下:

  • 汇总的指标只会抽样部分消息
  • 汇总的指标经过了舍入处理
  • 我们不呈现低于隐私保护阈值的指标
  • 因为优化管理大流量的方式而导致部分消息结果丢失。

此 API 的限制

汇总数据时间轴

该 API 将返回 7 天的历史数据;不过,此 API 返回的数据最长会延迟 5 天。例如,在 1 月 20 日,系统会提供 1 月 9 日 - 1 月 15 日的数据,但无法提供 1 月 16 日或之后的数据。此外,这些数据是以“尽力而为”的前提提供的。如果数据中断,FCM 将向前修复,但不会在问题修复后回填数据。如果出现较大的中断,可能会有一周或更长的时间数据不可用。

数据涵盖情况

Firebase Cloud Messaging Data API 提供的指标旨在让您了解消息传送的广泛趋势。但是,它们并不涵盖所有的消息场景。已知以下场景的结果不会反映在指标中。

被折叠的消息

被其他消息折叠的消息不会显示在数据集中。

向非活跃设备发送的消息

发送到非活跃设备的消息不一定会显示在数据集中,具体取决于它们采取的数据路径。这可能会导致 droppedDeviceInactivepending 字段中的一些错误计数。

向具有某些用户偏好设置的设备发送的消息

如果用户已在其设备上停止收集使用情况和诊断信息,则向这类用户发送的消息不会包括在计数中,以便与其偏好设置保持一致。

舍入和最小值

FCM 会有意地舍入和排除数量不足的计数。

BigQuery 数据导出服务

您可以将消息数据导出至 BigQuery 以便进一步分析。借助 BigQuery,您可以使用 BigQuery SQL 来分析数据,将数据导出至其他云服务商,或将该数据用于自定义机器学习模型。向 BigQuery 执行的导出操作可以包括所有消息的数据,无论平台、无论消息类型,也无论消息通过 API 发送还是通过 Notifications Composer 发送。

对于发送到具有以下 FCM SDK 最低版本的设备的消息,您还可以选择为应用启用消息传送数据导出功能:

  • Android 20.1.0 或更高版本。
  • iOS 8.6.0 或更高版本
  • Firebase Web SDK 9.0.0 或更高版本

请参阅下文,详细了解如何为 AndroidiOS 启用数据导出功能。

首先,请将您的项目与 BigQuery 关联:

  1. 选择以下一个选项:

    • 打开 Notifications Composer,然后点击页面底部的访问 BigQuery

    • 在 Firebase 控制台的集成页面中,点击 BigQuery 卡片中的关联

      此页面显示了项目中所有启用 FCM 的应用的 FCM 导出选项。

  2. 按照屏幕上的说明启用 BigQuery。

如需了解详情,请参阅将 Firebase 关联到 BigQuery

为 Cloud Messaging 启用 BigQuery Export 功能后:

  • Firebase 会将您的数据导出到 BigQuery。请注意,导出数据的初始传播最长可能需要 48 小时才能完成。

  • 创建数据集后,将无法更改其位置,但可以将数据集复制到其他位置,或手动将数据集移动(重新创建)到其他位置。如需了解详情,请参阅更改数据集位置

  • Firebase 会安排定期将您的数据从 Firebase 项目同步到 BigQuery。这些每日导出操作的开始时间是凌晨 4:00(太平洋时间),通常会在 24 小时内完成。

  • 默认情况下,您项目中的所有应用都会关联到 BigQuery,而且您以后向项目中添加的所有应用也都会自动关联到 BigQuery。您可以管理哪些应用可发送数据

如需停用 BigQuery 导出,请在 Firebase 控制台中取消关联您的项目

启用消息传送数据导出功能

搭载 FCM SDK 20.1.0 或更高版本的 Android 设备可以启用其应用的消息传送数据导出功能。默认情况下,数据导出功能在应用级处于停用状态。如果以编程方式在应用实例级启用该功能,您可以向最终用户请求分析其消息传送数据的权限(推荐做法)。如果两者都设置,则应用实例级的值会替换应用级的值。

启用这些选项之前,您必须先按照 BigQuery 数据导出中的说明为您的项目创建 FCM-BiqQuery 链接。

为应用实例启用传送数据导出功能

在大多数情况下,建议仅在应用实例级启用消息传送数据导出功能,而在应用级停用此功能。

 FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true)

为应用启用传送数据导出功能

如果您希望在应用级启用导出功能,请确保不要调用 setDeliveryMetricsExportToBigQuery 方法,而应在应用清单中向应用对象添加以下属性:

<application>
  <meta-data android:name="delivery_metrics_exported_to_big_query_enabled"
      android:value="true" />
</application>

哪些数据会导出至 BigQuery?

请注意,定位过时的令牌或非活跃注册可能会夸大其中的一些统计信息。

导出的表中的概要如下:

_PARTITIONTIME 时间戳 此伪代码列包含数据加载当天的起始的时间戳(采用世界协调时间 (UTC))。对于 YYYYMMDD 分区的情况,此伪代码列包含值 TIMESTAMP('YYYY-MM-DD')。
event_timestamp 时间戳 服务器记录的事件时间戳
project_number INTEGER 发送消息的项目的唯一编号
message_id STRING 消息 ID 用于标识消息。消息 ID 根据应用 ID 和时间戳生成,在某些情况下可能不是全局唯一的。
instance_id STRING 消息发送到的应用的唯一 ID(如有)它可以是实例 ID 或 Firebase 安装 ID。
message_type STRING 消息的类型。可以是通知消息或数据消息。主题用于标识主题或广告系列发送的原始消息;后续消息则为通知消息或数据消息。
sdk_platform STRING 接收消息的应用所在的平台
app_name STRING Android 应用的软件包名称或 iOS 应用的软件包 ID
collapse_key STRING 标识一组可折叠消息的折叠键。若未连接设备,则仅具有给定折叠键的最后一条消息将排队等待最终传送
priority INTEGER 消息的优先级。有效值包括“normal”(普通)和“high”(高)。在 iOS 中,这些值相当于 APNs 优先级中的 5 和 10
ttl INTEGER 此参数指定设备离线后消息在 FCM 存储中保留的时长(以秒为单位)
topic STRING 消息发送到的主题的名称(如有)
bulk_id INTEGER 标识一组相关消息(例如向某个特定主题发送的一组消息)的批量 ID
event STRING 事件的类型。可能的值包括:
  • MESSAGE_ACCEPTED:FCM 服务器收到了消息,且请求有效;
  • MESSAGE_DELIVERED:消息已发送到设备上的应用的 FCM SDK。默认情况下,此字段不会被传播。如需启用,请按照 setDeliveryMetricsExportToBigQuery(boolean) 中的说明操作。
  • MISSING_REGISTRATIONS:由于注册缺失,请求被拒绝;
  • UNAUTHORIZED_REGISTRATION:消息被拒绝,因为发送者无权向注册发送消息;
  • MESSAGE_RECEIVED_INTERNAL_ERROR:处理消息请求时发生不明错误;
  • MISMATCH_SENDER_ID:由于发送消息的发送者 ID 与声明的端点 ID 消息不匹配,发送消息的请求被拒绝;
  • QUOTA_EXCEEDED:由于配额不足,发送消息的请求被拒绝;
  • INVALID_REGISTRATION:由于注册无效,发送消息的请求被拒绝;
  • INVALID_PACKAGE_NAME:由于软件包的名称无效,发送消息的请求被拒绝;
  • INVALID_APNS_CREDENTIAL:由于 APNS 证书无效,发送消息的请求被拒绝;
  • INVALID_PARAMETERS:由于参数无效,发送消息的请求被拒绝;
  • PAYLOAD_TOO_LARGE:由于载荷超出限制,发送消息的请求被拒绝;
  • AUTHENTICATION_ERROR:由于出现身份验证错误,发送消息的请求被拒绝(请检查用于发送消息的 API 密钥);
  • INVALID_TTL:由于 TTL 无效,发送消息的请求被拒绝。
analytics_label STRING 使用 HTTP v1 API 时,可以在发送消息时设置分析标签,以便标记消息以供分析之用

您可以对导出的数据执行哪些操作?

以下部分提供了可以针对导出的 FCM 数据在 BigQuery 中运行的查询示例。

按应用统计已发送消息的数量

SELECT app_name, COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_id != ''
GROUP BY 1;

统计消息指向的非重复应用实例的数量

SELECT COUNT(DISTINCT instance_id)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED';

统计已发送的通知消息的数量

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_type = 'DISPLAY_NOTIFICATION';

统计已发送的数据消息的数量

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND message_type = 'DATA_MESSAGE';

统计发送到主题或广告系列的消息数量

SELECT COUNT(1)
FROM `project ID.firebase_messaging.data`
WHERE
  _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
  AND event = 'MESSAGE_ACCEPTED'
  AND bulk_id = your bulk id AND message_id != '';

若要跟踪发送到特定主题的消息的事件,请修改此查询以将 AND message_id != '' 替换为 AND message_id = <your message id>;

计算给定主题或广告系列的扇出时长

扇出开始时间是收到原始请求的时间,结束时间是指向单个实例的最后一条消息的创建时间。

SELECT
  TIMESTAMP_DIFF(
    end_timestamp, start_timestamp, MILLISECOND
  ) AS fanout_duration_ms,
  end_timestamp,
  start_timestamp
FROM (
    SELECT MAX(event_timestamp) AS end_timestamp
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
      AND bulk_id = your bulk id
  ) sent
  CROSS JOIN (
    SELECT event_timestamp AS start_timestamp
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
      AND bulk_id = your bulk id
      AND message_type = 'TOPIC'
  ) initial_message;

统计已送达的消息的百分比

SELECT
  messages_sent,
  messages_delivered,
  messages_delivered / messages_sent * 100 AS percent_delivered
FROM (
    SELECT COUNT(DISTINCT CONCAT(message_id, instance_id)) AS messages_sent
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND event = 'MESSAGE_ACCEPTED'
  ) sent
  CROSS JOIN (
    SELECT COUNT(DISTINCT CONCAT(message_id, instance_id)) AS messages_delivered
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND (event = 'MESSAGE_DELIVERED'
      AND message_id
      IN (
        SELECT message_id FROM `project ID.firebase_messaging.data`
        WHERE
          _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
          AND event = 'MESSAGE_ACCEPTED'
        GROUP BY 1
      )
  ) delivered;

跟踪给定消息 ID 和实例 ID 的所有事件

SELECT *
FROM `project ID.firebase_messaging.data`
WHERE
    _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
    AND message_id = 'your message id'
    AND instance_id = 'your instance id'
ORDER BY event_timestamp;

计算给定消息 ID 和实例 ID 的延迟时间

SELECT
  TIMESTAMP_DIFF(
    MAX(delivered_time), MIN(accepted_time), MILLISECOND
  ) AS latency_ms
FROM (
    SELECT event_timestamp AS accepted_time
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD')
      AND message_id = 'your message id'
      AND instance_id = 'your instance id'
      AND event = 'MESSAGE_ACCEPTED'
  ) sent
  CROSS JOIN (
    SELECT event_timestamp AS delivered_time
    FROM `project ID.firebase_messaging.data`
    WHERE
      _PARTITIONTIME = TIMESTAMP('date as YYYY-MM-DD') AND
      message_id = 'your message id' AND instance_id = 'your instance id'
      AND (event = 'MESSAGE_DELIVERED'
  ) delivered;