如何将Android应用通知聚合展示(仿WhatsApp样式)
问题描述
需求:顶部显示应用名称,下方聚合展示该应用的所有通知。当前通过Firebase接收通知,用Kotlin实现后通知仍分散显示,想要达到类似WhatsApp的聚合效果——多条通知折叠成一条,展开后能查看所有消息内容。
当前实现代码:
val messagingStyle = Notification.MessagingStyle(person) val remoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).also { it.setLabel(context.getString(R.string.type_to_reply)) }.build() val mChannel = NotificationChannel(channelId, newMessage.text, NotificationManager.IMPORTANCE_HIGH) mChannel.description = newMessage.text.toString() mChannel.enableVibration(true) val notifManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notifManager.createNotificationChannel(mChannel) val statusBarNotification = notifManager.activeNotifications.firstOrNull { it.id == channelId.toInt() } if (statusBarNotification == null) { val builder: Notification.Builder = Notification.Builder(context, channelId) val pendingIntent: PendingIntent = PendingIntent.getActivity( context, channelId.toInt(), navIntent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE ) builder.setContentTitle(newMessage.text) .setSmallIcon(R.drawable.my_logo) // required .setContentText(newMessage.text) // required .setDefaults(Notification.DEFAULT_ALL) .setAutoCancel(true) .addAction( getNotificationIntent(context, channelId.toInt(), remoteInput) ) .setWhen(newMessage.timestamp) .setStyle(messagingStyle.addMessage(newMessage)) .setContentIntent(pendingIntent) .setGroup(MY_NOTIFICATIONS) .setGroupSummary(true) val notification = builder.build() notifManager.notify(channelId.toInt(), notification) } else { var notificationBuilder = recoverBuilder(context, statusBarNotification.notification) notificationBuilder.also { val messageStyle = it.style as Notification.MessagingStyle messageStyle.addMessage(newMessage.text, newMessage.timestamp, person) it.style = messageStyle } notifManager.notify(channelId.toInt(), notificationBuilder.build()) }
目标效果:类似WhatsApp的通知聚合——所有来自该应用的通知折叠成一条,顶部显示应用名称,展开后可查看所有消息内容。
当前效果:每条通知单独显示,未实现聚合。
解决方案
你的代码里有几个关键问题导致聚合失败,修改如下:
统一通知渠道配置
你现在用newMessage.text作为渠道名称,且每次收消息都重建渠道——如果消息内容不同,会生成多个独立渠道,系统会把不同渠道的通知分开显示。
固定渠道ID和名称,且渠道创建代码只执行一次(比如放在Application初始化时):private const val MESSAGE_CHANNEL_ID = "app_message_channel" // 初始化渠道(仅执行一次) fun initNotificationChannel(context: Context) { val mChannel = NotificationChannel( MESSAGE_CHANNEL_ID, "应用消息", NotificationManager.IMPORTANCE_HIGH ) mChannel.description = "接收应用内所有消息通知" mChannel.enableVibration(true) val notifManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notifManager.createNotificationChannel(mChannel) }修正分组逻辑:区分普通通知和汇总通知
当前所有通知都加了setGroupSummary(true),但这个标记只应该给汇总通知用——普通消息通知只需要设置setGroup(MY_NOTIFICATIONS),汇总通知负责把它们折叠起来。
调整后的逻辑:private const val SUMMARY_NOTIFICATION_ID = 0 private const val MY_NOTIFICATIONS = "app_notification_group" // 1. 发送单条消息通知(用唯一ID,比如消息的服务器ID或时间戳) val messageId = newMessage.timestamp.toInt() // 确保每个消息ID唯一 val messageBuilder = Notification.Builder(context, MESSAGE_CHANNEL_ID) .setSmallIcon(R.drawable.my_logo) .setContentTitle(newMessage.senderName) // 显示发送者名称,而非消息内容 .setContentText(newMessage.text) .setWhen(newMessage.timestamp) .setStyle(Notification.MessagingStyle(person).addMessage(newMessage.text, newMessage.timestamp, person)) .setGroup(MY_NOTIFICATIONS) .setContentIntent(navIntent) .addAction(getNotificationIntent(context, messageId, remoteInput)) notifManager.notify(messageId, messageBuilder.build()) // 2. 更新汇总通知 val summaryBuilder = Notification.Builder(context, MESSAGE_CHANNEL_ID) .setSmallIcon(R.drawable.my_logo) .setContentTitle("你的应用名称") .setContentText("${unreadCount}条新消息") // 替换为实际未读数量 .setStyle(Notification.InboxStyle() .addLine("${newMessage.senderName}: ${newMessage.text}") // 可添加更多历史消息预览 .setSummaryText("你的应用名称")) .setGroup(MY_NOTIFICATIONS) .setGroupSummary(true) .setContentIntent(navIntent) notifManager.notify(SUMMARY_NOTIFICATION_ID, summaryBuilder.build())通知ID要区分开
你之前用channelId.toInt()作为所有通知的ID,会导致新消息直接覆盖旧消息,无法聚合。普通消息用唯一ID,汇总通知用固定ID(比如0),这样每条消息都能独立存在,再被汇总通知折叠。避免依赖
recoverBuilder
恢复旧通知的样式容易出现状态丢失,建议每次更新汇总通知时,直接重新构建样式并添加未读消息列表,保证聚合逻辑的稳定性。
内容的提问来源于stack exchange,提问作者Sneha
相关产品推荐
相关产品推荐

