You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:50:40