Android Firebase Notification:实现Gmail式可单独点击的合并通知
嘿,这个需求我之前帮不少开发者实现过,其实Android原生的通知系统就支持这种**分组通知(Grouped Notifications)**的功能,配合Firebase Cloud Messaging(FCM)就能完美复刻Gmail的样式。下面一步步给你拆解怎么做:
一、先搞懂核心逻辑:通知分组
Android从API 24(Android 7.0)开始支持通知分组——把同类型的通知归到一个组里,折叠状态下显示一条汇总通知,展开后能看到所有子通知,而且每个子通知都能单独点击跳转对应的内容,Gmail就是用的这个机制。
二、配置Firebase通知的分组标识
不管你是从FCM控制台发通知,还是服务器端推送,都要给同组的通知加上相同的分组Key,同时给每个子通知设置唯一标识(避免被覆盖)。
1. FCM控制台配置
在控制台的「高级选项」里:
- 给所有要合并的通知设置相同的
group字段(比如com.your.app.group.MAIL) - 每个通知设置不同的
tag(比如邮件ID),确保子通知不会互相覆盖
2. 服务器端JSON示例
如果是自己的服务器推送,payload要包含分组和唯一标识:
{ "to": "DEVICE_TOKEN", "notification": { "title": "新邮件:来自张三", "body": "项目进度更新..." }, "data": { "mail_id": "12345", "group_key": "mail_group" }, "android": { "notification": { "group": "mail_group", "tag": "mail_12345" } } }
三、Android客户端实现分组逻辑
在你的FirebaseMessagingService子类里,处理通知的创建、分组和跳转逻辑:
1. 创建可单独点击的子通知
每个子通知要绑定唯一的跳转Intent,同时设置相同的分组Key,系统会自动把它们归为一组:
override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 解析通知数据 val title = remoteMessage.notification?.title ?: "新通知" val body = remoteMessage.notification?.body ?: "" val mailId = remoteMessage.data["mail_id"] ?: "" val groupKey = remoteMessage.data["group_key"] ?: "default_group" // 子通知跳转Intent:点击打开对应邮件详情 val detailIntent = Intent(this, MailDetailActivity::class.java).apply { putExtra("MAIL_ID", mailId) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val detailPendingIntent = PendingIntent.getActivity( this, mailId.hashCode(), // 用唯一requestCode确保每个Intent不重复 detailIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // 构建子通知 val childNotification = NotificationCompat.Builder(this, "MAIL_CHANNEL_ID") .setSmallIcon(R.drawable.ic_mail) .setContentTitle(title) .setContentText(body) .setPriority(NotificationCompat.PRIORITY_HIGH) .setContentIntent(detailPendingIntent) .setAutoCancel(true) .setGroup(groupKey) // 绑定分组Key // 发送子通知:用唯一ID(比如邮件ID哈希值) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(mailId.hashCode(), childNotification.build()) // 同步创建汇总通知 createGroupSummary(groupKey, notificationManager) }
2. 创建折叠显示的汇总通知
汇总通知是折叠状态下显示的主通知,需要标记为groupSummary,同时绑定相同的分组Key:
private fun createGroupSummary(groupKey: String, notificationManager: NotificationManager) { // 汇总通知跳转Intent:点击打开邮件列表页 val listIntent = Intent(this, MailListActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val listPendingIntent = PendingIntent.getActivity( this, 0, listIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // 构建汇总通知 val summaryNotification = NotificationCompat.Builder(this, "MAIL_CHANNEL_ID") .setSmallIcon(R.drawable.ic_mail) .setContentTitle("新邮件") .setContentText("你有${getUnreadMailCount()}封未读邮件") // 可动态获取未读数量 .setPriority(NotificationCompat.PRIORITY_HIGH) .setContentIntent(listPendingIntent) .setAutoCancel(true) .setGroup(groupKey) .setGroupSummary(true) // 标记为汇总通知 // 发送汇总通知:用固定ID(比如0) notificationManager.notify(0, summaryNotification.build()) }
四、关键注意事项
- 通知渠道必须配置:Android 8.0及以上必须创建通知渠道,否则通知无法显示,记得在App启动时初始化:
private fun initNotificationChannels() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val mailChannel = NotificationChannel( "MAIL_CHANNEL_ID", "邮件通知", NotificationManager.IMPORTANCE_HIGH ).apply { description = "接收新邮件通知" } val notificationManager = getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(mailChannel) } }
- PendingIntent的requestCode必须唯一:每个子通知的requestCode不能重复,否则会导致所有子通知跳转同一个页面。
- 优先用Data Message:如果发送FCM的「通知消息」,系统会自动显示通知,但你没法完全控制分组逻辑;建议用「数据消息」,这样能在
onMessageReceived里完全自定义通知。 - 旧设备兼容:API 23及以下不支持分组,这类设备会直接显示所有子通知,和Gmail的旧版本表现一致,属于正常情况。
这样就能实现和Gmail一模一样的多通知合并效果了,每个子通知都能单独点击跳转,折叠时显示汇总信息。如果还有细节问题可以再提~
内容的提问来源于stack exchange,提问作者Abdul Qayyum
相关产品推荐
相关产品推荐

