3. FCM 消息类型解析
FCM 定义了三种消息传递模型:通知消息(Notification Message)、数据消息(Data Message)和混合消息(Combined Message)。理解它们的负载结构与进程行为是正确实现后台任务唤醒的关键。本章从负载格式、系统分发机制、进程存活状态下的行为三个维度进行深度解析。
3.1 三种消息的负载结构
| 消息类型 | 负载键 | 系统处理方式 | 前台/后台行为差异 | 进程被杀死后 |
|---|---|---|---|---|
| 通知消息 | notification + 可选 data |
系统自动创建通知栏, 不触发 onMessageReceived |
前台:直接显示;后台:显示 + 可选轻量处理 | 系统重新创建应用后仅显示通知 |
| 数据消息 | 仅 data,无 notification |
应用必须自行处理, 始终触发 onMessageReceived |
前台/后台均触发回调,可启动 Service | 若被杀死则无法触发回调(无唤醒能力) |
| 混合消息 | notification + data 同时存在 |
系统显示通知,同时将 data 通过 Intent 附加到启动的 Activity | 前台:直接显示 + 回调;后台:显示通知 + 附加 data | 用户点击通知后启动 Activity 可获得 data |
3.2 典型负载 JSON 示例
以下展示三种消息的完整 Payload 结构,用于服务端发送时的格式参考:
// 通知消息(Notification Only)
{
"to": "device_",
"notification": {
"title": "新消息",
"body": "您有一条未读通知",
"sound": "default"
}
}
// 数据消息(Data Only)
{
"to": "device_",
"data": {
"type": "silent_sync",
"payload": "{\"task_id\": 123}",
"priority": "high"
}
}
// 混合消息(Notification + Data)
{
"to": "device_",
"notification": {
"title": "更新提醒",
"body": "点击查看详情"
},
"data": {
"deep_link": "/detail/456",
"badge": "1"
}
}
关键区分:数据消息的 data 字段是 键值对必须被应用解析;通知消息的 notification 字段由系统 UI 层自动接管,应用层无需编码处理通知栏展示。
3.3 进程行为全景图
下方 SVG 从 FCM 服务器到 Android 设备,展示了三种消息在 前台运行、后台挂起、进程被杀死 三种状态下的系统分发路径与应用响应行为。
图解重点:绿色路径(数据消息)是唯一能在后台稳定触发 onMessageReceived 的模型,但无法在进程被杀死时唤醒;红色路径(通知消息)由系统保活,适合简单提醒;紫色路径(混合消息)适合“点击通知后获取额外数据”的场景。
3.4 进程行为深度分析
- 前台进程:三种消息的
onMessageReceived都正常触发(混合消息仅当应用在前台时触发回调,后台则不触发)。 - 后台进程(挂起/缓存):通知消息由系统直接处理;数据消息会触发回调(但 Android 12+ 有特殊前台服务限制);混合消息在后台仅显示通知,不触发回调。
- 进程被杀死:只有通知消息能重新唤醒应用(仅显示通知,不回调);数据消息彻底失效;混合消息在用户点击通知后启动 默认 Activity 并附带
data键值对。
3.5 实现建议与常见误区
常见错误:很多开发者误以为数据消息可以像 iOS 那样“静默唤醒”被杀死进程。实际上,FCM 数据消息在 Android 8.0+ 上,当应用被杀死后 完全不会传递。必须在应用存活状态才能收到。
若需要实现“被杀死后仍能执行后台任务”,必须结合 通知消息 + 高优先级 FCM 并利用系统广播接收器(如 BOOT_COMPLETED)重新注册。更可靠的方式是使用 WorkManager 周期性任务或 前台服务 保持长连接。
// 最佳实践:在 onMessageReceived 中启动前台服务确保存活
public void onMessageReceived(RemoteMessage message) {
if (message.getData().size() > 0) {
Intent intent = new Intent(this, MyForegroundService.class);
intent.putExtra("payload", message.getData().toString());
startForegroundService(intent);
}
}
3.6 性能与稳定性建议
- 避免在
onMessageReceived中执行长时间阻塞操作;使用 WorkManager 或 IntentService 异步处理。 - 混合消息的
data部分最大为 4KB,通知消息的notification字段同样受限,大数据应使用 下载任务 而非直接嵌入。 - 针对 Android 12+,后台启动前台服务限制更严,建议在通知消息中添加
ticker或使用 高优先级 FCM 配合priority: 10。 - 调试时使用 FCM 控制台或
curl发送测试消息,并观察adb logcat -s FCM输出确认回调是否触发。
章节小结:通知消息适合保活,数据消息适合后台任务,混合消息是折中方案。实际项目中应根据进程唤醒需求选择类型,并辅以前台服务或 WorkManager 保证可靠性。