FCM 实战:消息结构、数据与通知

FreeGuideOnline 最新 2026-06-17

Firebase Cloud Messaging (FCM) 实战:消息结构、数据与通知

什么是 FCM?

Firebase Cloud Messaging (FCM) 是 Google 提供的跨平台消息传递解决方案,让你能免费、可靠地将消息发送到 Android、iOS 和 Web 应用。无论是推送通知、即时消息同步还是后台数据刷新,FCM 都是首选工具。

在 FCM 中,消息分为两种核心类型:通知消息数据消息。理解它们的结构与行为差异,是构建稳定推送逻辑的基础。


FCM 消息的基本结构

一条 FCM 消息本质是一个 JSON 对象,通过 HTTP/2 协议或 Firebase Admin SDK 发送。最外层字段如下:

{
  "message": {
    "token": "设备注册令牌",
    "notification": { ... },
    "data": { ... },
    "android": { ... },
    "apns": { ... },
    "webpush": { ... }
  }
}
  • token:目标设备的 FCM 注册令牌(单一设备)。
  • topic:发送到订阅了某个主题的设备(可选,与 token 二选一)。
  • condition:多主题条件表达式,如 "TopicA" in topics && ("TopicB" in topics || "TopicC" in topics)(可选)。
  • notification:通知消息体,由系统自动处理显示。
  • data:数据消息体,由应用自行处理。
  • android / apns / webpush:平台特定配置,可覆盖通知行为、定制铃声、图片等。

基础用法:只需关心 token(或 topic)、notificationdata,其他字段可按需使用。


通知消息(Notification Message)

通知消息由 FCM SDK 自动将内容展示为系统通知栏中的一条标准通知。你无需编写任何展示代码,适合快速发送提醒。

主要字段

"notification": {
  "title": "新消息",
  "body": "你收到了一条新评论",
  "image": "https://example.com/icon.png"
}
  • title:通知标题(必填)。
  • body:通知内容文本(必填)。
  • image:在通知中展示的图片 URL(Android 支持大图,iOS 支持富媒体推送)。

行为特点

  • 前台/后台:当应用在前台时,系统不会自动弹出通知,需在 onMessageReceived 中手动处理;后台时则由系统托盘自动显示。
  • 直接使用 FCM 控制台:无需写代码,只需填写标题和正文,即可快速下发。

📌 注意:仅靠通知消息无法携带自定义数据,若点击通知后需跳转到指定页面,务必发送通知+数据组合消息


数据消息(Data Message)

数据消息完全由客户端代码处理,系统不显示任何通知。适合静默同步数据、刷新界面、触发后台任务等场景。

主要字段

"data": {
  "type": "chat",
  "conversationId": "abc123",
  "sender": "Alice"
}
  • 所有键值对都是字符串类型。
  • 键名避免使用 FCM 保留字段(如 fromgoogle. 开头等)。
  • 最大总大小 4KB(适合轻量数据,大体积内容应传递资源 ID 后再请求)。

行为特点

  • 始终触发 onMessageReceived:无论应用在前台还是后台,都会回调该方法,由开发者决定如何反应。
  • 后台数据消息会唤醒应用短暂处理(Android 10+ 有后台执行限制),适合小量工作。
  • 可自行构造本地通知,实现点击跳转等复杂逻辑。

通知 + 数据组合消息

在实际项目中,最常见的做法是同时携带 notificationdata,让消息既有自动显示的便利,又能携带自定义数据用于点击跳转。

{
  "message": {
    "token": "your-device-token",
    "notification": {
      "title": "新消息",
      "body": "你收到了一条私信"
    },
    "data": {
      "screen": "chat",
      "userId": "U12345"
    }
  }
}

不同状态下的接收行为

应用状态 通知显示 data 获取方式
前台 不自动显示,你需要在 onMessageReceived 中自行处理 remoteMessage.getData() 直接获取
后台 系统自动显示通知 点击通知后通过 intent.getExtras()(Android)或 launchOptions(iOS/Web)获取

🔍 关键点:在后台收到组合消息时,data 不会传递给 onMessageReceived,而是附加在点击通知打开的 Activity 的 Intent 中。因此务必在启动 Activity 中处理 data 负载。


实战案例:通过 Firebase 控制台发送组合消息

  1. 打开 Firebase 控制台 > 你的项目 > Messaging
  2. 点击“发送您的第一条消息”。
  3. 选择“通知消息”类型,填写通知标题和正文。
  4. 点击“添加自定义数据”,输入键值对(例如 screen = "chat", userId = "U12345")。
  5. 目标选择“User segment”或“Topic”,也可以输入设备令牌测试。
  6. 点击“审阅”后直接发送。

收到的消息会自动弹出通知,点击后你可以在 Activity 中获取 data 并处理跳转。


客户端代码处理(Android 示例)

1. 继承 FirebaseMessagingService 接收消息

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        // 检查是否包含 data
        if (remoteMessage.getData().size() > 0) {
            String screen = remoteMessage.getData().get("screen");
            // 在前台时可自定义创建通知,或在后台时处理逻辑
            // 注意:应用在后台时此方法不会被调用,数据需通过 Launcher Activity 获取
        }
    }
}

2. 在 Launcher Activity 中获取后台消息数据

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("FCM Data", "Key: " + key + " Value: " + value);
        }
        String screen = getIntent().getExtras().getString("screen");
        // 根据 screen 跳转对应界面
    }
}

3. 使用 Firebase Admin SDK 发送(Node.js 示例)

const admin = require("firebase-admin");
admin.initializeApp({
  credential: admin.credential.applicationDefault()
});

const message = {
  token: "设备令牌",
  notification: {
    title: "新评论",
    body: "有人回复了你的帖子"
  },
  data: {
    postId: "123",
    commentId: "456"
  }
};

admin.messaging().send(message)
  .then(response => console.log("成功:", response))
  .catch(error => console.error("失败:", error));

常见问题与最佳实践

❓ 为什么后台收到通知时,onMessageReceived 没有被调用?

这是预期行为。后台通知消息由系统托盘接管,不会回调该方法。只有前台消息或纯数据消息才会触发 onMessageReceived。要获取后台通知里携带的 data,必须从启动 Activity 的 Intent 中读取。

❓ 如何让通知点击后打开指定页面?

一定要在消息中加入 data 字段,并在目标 Activity 中解析这些数据实现跳转。不要依赖 notificationclick_action(因平台限制很多)。

❓ 数据消息和通知消息选哪个?

  • 只需显示通知 → 纯通知消息
  • 需要静默同步或自定义显示逻辑 → 数据消息
  • 既显示通知又要携带点击逻辑 → 组合消息(推荐)

❓ 消息大小有什么限制?

整个消息负载(包括所有字段)不得超过 4,096 字节。如果 data 中的内容较大,考虑传递资源 ID,让客户端再通过 API 获取完整信息。

❓ 如何避免重复通知或丢失数据?

  • 不要在 onMessageReceived 中再次发送系统通知(避免前台重复显示)。
  • 使用 Firebase 的 collapse_key 参数让多条同类消息只保留最新一条。
  • 设计幂等的 data 处理逻辑,防止网络重试导致重复操作。

总结

FCM 的消息结构清晰且灵活:通知消息让推送变得极其简单,数据消息赋予你完全的控制权,而两者的结合则是实际应用中的黄金组合。掌握前台/后台的接收差异、正确解析 data 负载、遵守大小限制,就能构建出稳定、不打扰用户的推送体验。

从 Firebase 控制台到 Admin SDK,再到客户端接收,整条链路现在你已经完整贯通。快去动手发送你的第一条组合消息吧!