转到控制台

了解消息传送

FCM 提供的工具可帮助您深入了解消息传送功能。除了内置于 Firebase 控制台的送达情况报告和通知漏斗分析之外,FCM 还可以将全面的数据导出到 Google BigQuery。

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

消息送达情况报告

您可以评估您发送的消息是否已送达您的用户。在 Firebase 控制台中的报告标签页中,对于已发送至 Android 或 iOS FCM SDK 的消息,包括通过通知编辑器和 FCM API 发送的消息,您可以查看以下数据:

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

此数据适用于所有带有通知负载的的消息和所有带标签数据消息。如需详细了解标签,请参阅为消息添加分析标签

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

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

为消息添加分析标签

为消息加标签对于自定义分析非常有用,这将允许您按标签或标签集过滤传送统计信息。您可以通过在 message 对象中设置 fcmOptions.analyticsLabel 字段,向任何通过 HTTP v1 API 发送的消息添加标签,也可以在特定于平台的 AndroidFcmOptionsApnsFcmOptions 字段中执行此操作。

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

  • -
  • ~
  • %

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

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

通知漏斗分析

内置的通知漏斗分析功能可向您介绍用户如何响应从 Firebase 控制台发送的特定通知。该视图包括目标 iOS 和 Android 设备在以下类别的数据:

  • 已发送通知:消息已加入队列或已成功传递给第三方服务(例如 APN)以进行传递。请注意,定位过时的令牌或非活跃注册可能会夸大这些统计信息。
  • 已打开通知:已打开的通知的数量。仅针对应用在后台运行时收到的通知报告此数据。
  • 已触发转化事件的唯一身份用户的数量(如果已作出相关定义)。

要查看通知渠道分析数据,请执行以下操作:

  1. 在通知编辑器中选择通知标签。
  2. 在消息列表中点击已发送或正在发送的消息。系统即会在展开的视图中显示漏斗分析数据。

Analytics 报告会定期更新,但在用户打开通知与控制台中生成事件数据之间可能会略有延迟。除了通知标签页下的这些报告之外,您还可以在 Analytics 中创建自定义漏斗以直观呈现应用中一系列步骤的完成率。

向 BigQuery 导出数据

您可以将消息数据导出至 BigQuery 以便进一步分析。借助 BigQuery,您可以使用 BigQuery SQL 来分析数据,将数据导出至其他云服务商,或将该数据用于自定义机器学习模型。无论位于哪个平台,无论属于什么消息类型,也无论消息通过 API 发送,还是通过通知编辑器发送,所有消息均可导出至 BigQuery。

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

  1. 要开始使用,请使用下列其中一个选项:

    • 打开通知编辑器,然后点击页面底部的关联 BigQuery

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

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

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

当您将项目关联到 BiqQuery 时:

  • Firebase 会将您的现有数据的副本导出到 BigQuery。

  • Firebase 会安排定期将您的数据从 Firebase 项目同步到 BigQuery。

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

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

哪些数据会导出至 BigQuery?

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

导出的表中的概要如下:

_PARTITIONTIME TIMESTAMP 此伪代码列包含数据加载当天的起始的时间戳(采用世界协调时间 (UTC))。对于 YYYYMMDD 分区的情况,此伪代码列包含值 TIMESTAMP('YYYY-MM-DD')。
event_timestamp TIMESTAMP 服务器记录的事件时间戳
project_number INTEGER 发送消息的项目的唯一编号
message_id STRING 单个消息的唯一消息 ID
instance_id STRING 消息发送到的应用的实例 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
device_recently_active BOOLEAN 如果设备最近已连接,则此参数为 true
event STRING 事件的类型。可能的值包括:
  • MESSAGE_ACCEPTED:FCM 服务器收到消息,且请求有效:
  • MESSAGE_DELIVERED:消息已发送到设备;
  • MESSAGE_DELIVERED_ON_RECONNECT:设备重新连接后,消息发送到了设备;
  • MISSING_REGISTRATIONS:由于注册缺失,请求被拒绝;
  • MESSAGE_EXPIRED:在设备连接就绪以传送消息之前消息已过期;
  • MESSAGE_DELAYED_DOZE:由于设备处于低电耗模式,因此传送到设备的消息被延迟;
  • UNAUTHORIZED_REGISTRATION:消息被拒绝,因为发送者无权向注册发送消息;
  • MESSAGE_COLLAPSED:传送还未传送便被替换为具有相同折叠键的较新消息;
  • MESSAGE_RECEIVED_INTERNAL_ERROR:处理消息请求时发生不明错误;
  • MESSAGE_DELAYED_THROTTLED:传送到设备的消息被延迟,因为其折叠键受到限制;
  • MISMATCH_SENDER_ID:由于发送消息的发送者 ID 与声明的端点 ID 消息不匹配,发送消息的请求被拒绝;
  • QUOTA_EXCEEDED:由于配额不足,发送消息的请求被拒绝;
  • INVALID_REGISTRATION:由于注册无效,发送消息的请求被拒绝;
  • INVALID_PACKAGE_NAME:由于软件包的名称无效,发送消息的请求被拒绝;
  • INVALID_APNS_CREDENTIAL:由于 APNS 证书无效,发送消息的请求被拒绝;
  • INVALID_PARAMETERS:由于参数无效,发送消息的请求被拒绝;
  • PAYLOAD_TOO_LARGE:由于负载超出限制,发送消息的请求被拒绝;
  • DEVICE_NOT_FOUND:由于在我们的数据库中未找到相应设备,发送消息的请求被拒绝;
  • AUTHENTICATION_ERROR:由于出现身份验证错误,发送消息的请求被拒绝(请检查用于发送消息的 API 密钥);
  • INVALID_TTL:由于 TTL 无效,发送消息的请求被拒绝。

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

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

SELECT app_name, COUNT(1)
FROM [<project name>: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 name>:firebase_messaging.data]
WHERE
  _PARTITIONTIME = TIMESTAMP('<date as YYYY-MM-DD>')
  AND event = 'MESSAGE_ACCEPTED';

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

SELECT COUNT(1)
FROM [<project name>: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 name>: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 name>:firebase_messaging.data]
WHERE
  _PARTITIONTIME = TIMESTAMP('<date as YYYY-MM-DD>')
  AND event = 'MESSAGE_ACCEPTED'
  AND bulk_id = <your bulk id> AND 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 name>: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 name>: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 name>: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 name>:firebase_messaging.data]
    WHERE
      _PARTITIONTIME = TIMESTAMP('<date as YYYY-MM-DD>')
      AND (event = 'MESSAGE_DELIVERED' OR event = 'MESSAGE_DELIVERED_ON_RECONNECT')
      AND message_id
      IN (
        SELECT message_id FROM [<project name>:firebase_messaging.data]
        WHERE
          _PARTITIONTIME = TIMESTAMP('<date as YYYY-MM-DD>')
          AND event = 'MESSAGE_ACCEPTED'
        GROUP BY 1
      )
  ) delivered;

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

SELECT *
FROM [<project name>: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 name>: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 name>: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' OR event = 'MESSAGE_DELIVERED_ON_RECONNECT')
  ) delivered;