如何使用Firebase将多条通知合并为单条?
Firebase 实现多条通知合并的可行方案
我懂你现在的困扰——用collapse_key只有设备离线时才起作用,tag又会直接覆盖旧通知,都没法实现多条同类型通知合并展示的需求对吧?其实FCM本身没有直接的服务端API来自动合并多条通知,但咱们可以通过以下几种方式来实现:
1. 客户端手动维护通知计数(推荐灵活场景)
这种方式是让客户端来处理通知的合并逻辑,核心思路是:
- 发送通知时,在payload里附带自定义标识(比如通知类型
type: "order_update"、当前计数count: 1或者唯一的业务ID) - 客户端收到新通知后,先检查系统通知栏里是否已有同类型的通知
- 如果存在,就更新原有通知的内容(比如把“1条订单更新”改成“2条订单更新”),同时更新计数;如果不存在,再新建通知
举个Android端的简单示例(Kotlin):
// 收到FCM消息后处理 fun handleNotification(data: Map<String, String>) { val notificationType = data["type"] ?: return val currentCount = data["count"]?.toInt() ?: 1 // 检查是否已有同类型通知 val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val existingNotifications = notificationManager.activeNotifications .filter { it.tag == notificationType } val updatedCount = if (existingNotifications.isNotEmpty()) { existingNotifications.first().extras.getInt("count", 0) + currentCount } else { currentCount } // 构建更新后的通知 val notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("订单更新") .setContentText("您有 $updatedCount 条新的订单消息") .setSmallIcon(R.drawable.ic_notification) .setTag(notificationType) // 用类型作为tag,方便找到同类型通知 .setExtras(Bundle().apply { putInt("count", updatedCount) }) .build() notificationManager.notify(notificationType, 1, notification) }
2. 使用通知组(折叠展示多条通知)
如果希望用户既能看到汇总,又能展开查看每条通知的详情,可以用FCM的通知组功能:
- Android:在payload的
android.notification里添加group字段,同组的通知会自动折叠 - iOS:在
apns.payload.aps里添加thread-id字段,实现类似的分组折叠
服务端Node.js的payload示例:
const payload = { notification: { title: "订单更新", body: "您的订单已发货" }, data: { type: "order_update" }, android: { notification: { group: "ORDER_NOTIFICATIONS", groupSummary: false // 如果设为true,这条会作为组的汇总通知 } }, apns: { payload: { aps: { "thread-id": "ORDER_NOTIFICATIONS" } } }, token: "DEVICE_TOKEN" };
如果需要一个汇总通知,可以单独发一条groupSummary: true的通知,内容比如“您有3条订单更新”,其他同组通知会折叠在它下面。
3. 服务端预合并通知(适合批量场景)
如果你的业务允许直接发送汇总后的通知,可以在服务端先统计用户的未读通知:
- 每次要发送新通知前,先查询数据库中该用户未发送的同类型通知数量
- 直接发送一条汇总内容的通知(比如“您有5条新消息”),同时标记这些通知为已发送
- 这种方式不需要客户端处理,但需要维护用户的通知状态
比如Node.js服务端的逻辑示例:
// 假设从数据库查询用户未读的订单更新数量 async function sendMergedNotification(userId, deviceToken) { const unreadCount = await db.collection("notifications") .where("userId", "==", userId) .where("type", "==", "order_update") .where("sent", "==", false) .count() .get(); if (unreadCount.data().count === 0) return; const payload = { notification: { title: "订单更新", body: `您有 ${unreadCount.data().count} 条新的订单消息` }, token: deviceToken }; await admin.messaging().send(payload); // 标记这些通知为已发送 await db.collection("notifications") .where("userId", "==", userId) .where("type", "==", "order_update") .where("sent", "==", false) .update({ sent: true }); }
为什么collapse_key和tag不符合需求?
再帮你理清楚这两个字段的作用:
collapse_key:仅当设备离线时,FCM会把同key的多条通知合并成一条发送给设备,设备在线时还是会逐条推送,所以没法实现在线时的合并tag:在线时,新的同tag通知会直接覆盖旧的,相当于替换而不是合并,所以也不符合你的需求
你可以根据自己的业务场景选择最合适的方案——如果需要保留每条通知的详情,用通知组;如果只需要汇总提醒,客户端计数或者服务端预合并都可以。
内容的提问来源于stack exchange,提问作者Always Learner
相关产品推荐
相关产品推荐

