
fcm 后台通知被自动显示的根本原因在于:含 notification 字段的消息由系统直接处理,根本不会触发 onbackgroundmessage 回调;要实现完全可控的通知逻辑,必须改用纯 data 消息类型。
fcm 后台通知被自动显示的根本原因在于:含 notification 字段的消息由系统直接处理,根本不会触发 onbackgroundmessage 回调;要实现完全可控的通知逻辑,必须改用纯 data 消息类型。
? 问题根源:Notification 消息 vs Data 消息
Firebase Cloud Messaging 支持两种消息类型:
Notification 消息(含 notification 字段):
当应用处于后台(或关闭)时,由浏览器/操作系统自动渲染并显示通知,完全绕过你的 service worker 逻辑。此时 onBackgroundMessage 不会被调用,你写的条件判断(如 if (!subscribedTables[table]) return;)根本不会执行。Data 消息(仅含 data 字段,不含 notification):
无论前台/后台,始终触发 onBackgroundMessage 回调,由你全权控制是否展示、如何展示通知——这才是实现订阅过滤等业务逻辑的正确路径。
✅ 正确做法:服务端发送时移除所有 notification 字段,仅保留 data,例如:
{
"message": {
"token": "YOUR_DEVICE_TOKEN",
"data": {
"title": "订单更新",
"body": "订单 #12345 已发货",
"table": "orders",
"timestamp": "1717023456"
}
}
}
✅ 修改 service worker:适配纯 data 消息
更新你的 firebase-messaging-sw.js,移除对 payload.notification 的依赖,改从 payload.data 中提取内容:
messaging.onBackgroundMessage(async function (payload) {
console.log('[FCM] Received data-only message:', payload);
// ✅ 从 data 字段读取内容(不再使用 payload.notification)
const notificationTitle = payload.data.title || '新消息';
const notificationBody = payload.data.body || '';
const table = payload.data.table;
// ✅ 关键:在 showNotification 前执行业务判断
const subscribedTables = await localforage.getItem("subscribedTables");
console.log('[FCM] Subscribed tables:', subscribedTables, 'Target table:', table);
if (!subscribedTables || !subscribedTables[table]) {
console.log(`[FCM] Ignoring notification: not subscribed to table '${table}'`);
return; // ? 阻止通知显示
}
// ✅ 构造并显示通知(仅当条件满足时)
const notificationOptions = {
body: notificationBody,
icon: "./android-icon-192x192.png",
requireInteraction: true,
badge: "./favicon.ico",
data: { table } // 可选:携带上下文供 notificationclick 使用
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
⚠️ 注意事项与最佳实践
-
服务端必须严格区分消息类型:
若使用 Firebase Admin SDK,请确保调用 messaging.send() 时不传 notification 对象,仅传 data:await admin.messaging().send({ token: deviceToken, data: { title: "库存告警", body: "SKU-A001 库存低于阈值", table: "inventory" } }); 避免混合消息(notification + data):
混合消息在后台仍会触发系统通知(优先级高于 data),导致你的 JS 逻辑失效。如需标题/图标等元信息,统一放入 data 字段,由 service worker 解析。调试技巧:
在 service worker 中添加 console.log(payload) 并打开 Chrome 的 Application → Service Workers → 打开 DevTools → Console,验证收到的消息结构是否为纯 data。兼容性提示:
确保客户端已正确注册 service worker(navigator.serviceWorker.register('firebase-messaging-sw.js')),且 HTTPS 环境下运行(FCM 要求)。
✅ 总结
FCM 的“通知总是显示”问题本质是消息类型误用。只有纯 data 消息才能将控制权交还给开发者。通过服务端移除 notification 字段 + service worker 中基于 data 的条件判断,即可精准实现按订阅表、用户偏好、时间窗口等复杂规则动态控制通知行为。这是构建专业级推送体验的基石。











