鸿蒙通知防刷屏:原生聚合能力,让同类消息优雅合并
在鸿蒙(HarmonyOS)应用开发中,通知是连接应用与用户的重要桥梁 —— 电商 APP 的订单动态、社交 APP 的消息提醒、工具类 APP 的任务通知等,都依赖通知触达用户。但当同类消息高频推送时(如 10 条订单状态更新、20 条群聊消息),通知栏会被 “刷屏”,不仅干扰用户视线,还可能导致关键信息被淹没。
幸运的是,鸿蒙通知模块原生支持消息聚合(分组)功能,无需第三方库,只需通过 “通知通道 + 通知分组” 组合配置,即可将同类消息合并为一条通知,折叠时显示摘要,展开时查看详情。本文将从机制解析到代码落地,完整讲解鸿蒙通知聚合的实现方案。
一、为什么需要通知聚合?
在未做聚合处理的场景中,高频同类通知会带来三大问题:
- 视觉干扰:通知栏被大量重复类型的消息占据,用户需滑动多次才能找到其他重要通知;
- 信息冗余:同类消息的格式、来源一致,重复展示会浪费屏幕空间(尤其在智能手表等小屏设备上);
- 操作低效:用户需逐条点击查看同类消息,无法批量处理(如 “一键标记已读”)。
而通知聚合能解决这些问题:
- 折叠展示:同类消息合并为一条,显示 “XX 条通知” 摘要,减少视觉占用;
- 分层查看:点击聚合通知可展开所有单条消息,既保留细节又不占用空间;
- 统一管理:用户可对聚合组批量操作(如删除、静音),提升操作效率。
二、鸿蒙通知聚合的核心机制:两大能力支撑
鸿蒙通过 “通知通道(NotificationSlot) ” 和 “通知分组(NotificationGroup) ” 两大原生能力,实现通知聚合。两者分工明确、协同工作:
机制逻辑梳理
- 应用先创建 “订单通知” 通道,并开启通道的分组能力;
- 发送第一条订单消息时,同时发送一条 “摘要通知”(标记该分组的总条数);
- 后续发送同订单的消息时,指定相同的groupKey,系统自动将其归入该分组;
- 用户在通知栏看到的是 “1 条摘要通知”(显示 “3 条订单通知”),点击可展开 3 条单条消息。
三、实战落地:从通道初始化到聚合通知发送
以 “电商 APP 订单通知” 为例,实现 “同一订单的多条状态更新聚合为一条通知” 的功能,完整步骤如下:
1. 第一步:初始化通知通道(聚合的 “分类基础”)
通知通道是鸿蒙通知管理的核心,所有通知必须绑定通道才能推送。要实现聚合,需在通道初始化时开启 “分组支持”。
关键 API 说明
- NotificationSlot:创建通道实例,参数为 “通道 ID(唯一)、通道名称(用户可见)、通道类型”;
- setGroupEnabled(true):允许该通道下的通知进行分组;
- setGroupSummaryEnabled(true):开启分组摘要显示(折叠时显示 “XX 条通知”);
- createNotificationSlot(slot):将通道注册到系统,需在应用启动时执行(仅需执行一次)。
import notification from '@ohos.notification';
import { BusinessError } from '@ohos.base';
// 通道常量定义
const ORDER_NOTIFICATION_SLOT_ID = "order_notification_slot";
const ORDER_NOTIFICATION_SLOT_NAME = "订单通知";
// 初始化通知通道
async function initNotificationSlot() {
try {
// 创建通道配置
const slot: notification.NotificationSlot = {
slotId: ORDER_NOTIFICATION_SLOT_ID,
slotName: ORDER_NOTIFICATION_SLOT_NAME,
slotType: notification.SlotType.SERVICE_INFORMATION,
groupEnabled: true, // 允许分组
groupSummaryEnabled: true, // 显示摘要
lockscreenVisibility: notification.Visibility.PUBLIC,
ledLightColor: '#FF6600',
vibrationEnabled: true
};
// 注册通道
await notification.notificationHelper.createNotificationSlot(slot);
} catch (error) {
const err = error as BusinessError;
console.error(`初始化订单通知通道失败:${err.code}, ${err.message}`);
}
}
2. 第二步:发送聚合通知(分组的 “核心逻辑”)
同一订单的多条状态更新(如 “订单已支付”“订单已发货”“订单已签收”)需归入同一分组,需满足两个条件:
- 所有通知绑定同一通道(ORDER_NOTIFICATION_SLOT_ID);
- 所有通知设置相同的groupKey(如 “order_123456”,对应订单 ID);
- 需发送一条 “摘要通知”,用于折叠状态展示总条数。
关键 API 说明
- NotificationRequest:通知请求实例,参数为 “通知 ID(唯一,建议用哈希值生成)”;
- setSlotId(slotId):绑定通知通道;
- setGroup(groupKey):指定分组唯一标识(同一分组需相同);
- setGroupSummary(isSummary):标记是否为摘要通知(true表示摘要,false表示单条消息);
- publishNotification(request):发送通知到系统。
代码实现(ArkTS 版,含摘要 + 单条通知)
import notification from '@ohos.notification';
import { BusinessError } from '@ohos.base';
// 订单通知聚合发送工具类
class OrderNotificationSender {
// 分组标识(格式:order_+订单ID,确保同一订单的通知归为一组)
private getGroupKey(orderId: string): string {
return `order_group_${orderId}`;
}
// 生成唯一通知ID(避免不同通知覆盖)
private getNotificationId(content: string): number {
return content.hashCode() + Date.now();
}
/**
* 发送订单聚合通知
* @param orderId 订单ID(用于分组)
* @param orderStatus 订单状态(如“已支付”“已发货”)
* @param notifyContent 通知详情内容
* @param totalCount 该订单的通知总条数(用于摘要)
*/
async sendAggregatedOrderNotification(
orderId: string,
orderStatus: string,
notifyContent: string,
totalCount: number
) {
try {
// 1. 先发送“分组摘要通知”(折叠时显示)
await this.sendGroupSummaryNotification(orderId, totalCount);
// 2. 再发送“单条订单通知”(展开时显示)
await this.sendSingleOrderNotification(orderId, orderStatus, notifyContent);
} catch (error) {
const err = error as BusinessError;
console.error(`发送订单通知失败:${err.code}, ${err.message}`);
}
}
// 发送分组摘要通知(仅需一条,可随总条数更新)
private async sendGroupSummaryNotification(orderId: string, totalCount: number) {
const groupKey = this.getGroupKey(orderId);
const summaryId = this.getNotificationId(`summary_${orderId}`);
// 构建摘要通知内容
const summaryContent: notification.NotificationContent = {
title: `您有${totalCount}条订单动态`,
text: `订单${orderId}的最新状态更新,点击查看详情`,
additionalText: `${totalCount}条` // 通知右侧显示的条数提示
};
// 构建通知请求
const summaryRequest: notification.NotificationRequest = {
id: summaryId,
slotId: ORDER_NOTIFICATION_SLOT_ID,
content: summaryContent,
group: groupKey, // 绑定分组
groupSummary: true // 标记为摘要通知
};
// 发送摘要通知
await notification.notificationHelper.publishNotification(summaryRequest);
}
// 发送单条订单通知(每条状态更新对应一条)
private async sendSingleOrderNotification(
orderId: string,
orderStatus: string,
notifyContent: string
) {
const groupKey = this.getGroupKey(orderId);
const singleId = this.getNotificationId(`single_${orderId}_${Date.now()}`);
// 构建单条通知内容(可添加跳转参数,点击时打开订单详情页)
const singleContent: notification.NotificationContent = {
title: `订单${orderId}:${orderStatus}`,
text: notifyContent,
// 点击通知跳转的意图(可选,需配置Ability路由)
intent: {
url: `ability://com.example.shop/OrderDetailAbility?orderId=${orderId}`,
type: 'ability'
}
};
// 构建通知请求
const singleRequest: notification.NotificationRequest = {
id: singleId,
slotId: ORDER_NOTIFICATION_SLOT_ID,
content: singleContent,
group: groupKey, // 绑定到同一分组
groupSummary: false // 标记为单条消息
};
// 发送单条通知
await notification.notificationHelper.publishNotification(singleRequest);
}
}
// 调用示例:发送订单123的第2条通知(状态为“已发货”)
const sender = new OrderNotificationSender();
sender.sendAggregatedOrderNotification(
"123456",
"已发货",
"您的订单已由顺丰快递发出,运单号:SF123456789",
2 // 该订单当前共有2条通知
);
3. 第三步:处理通知交互(展开 / 点击)
聚合通知的交互体验需重点关注两点:分组展开 / 折叠和点击跳转。
(1)分组展开 / 折叠
鸿蒙系统默认支持聚合通知的展开 / 折叠:
- 折叠状态:显示 “摘要通知”,右侧标注 “XX 条”;
- 展开状态:点击摘要通知,自动展开该分组下的所有单条通知;
- 批量操作:长按分组通知,可选择 “全部删除”“静音该分组” 等操作(系统原生支持)。
(2)点击跳转配置
通过NotificationContent的intent属性,配置点击通知后的跳转逻辑:
- 跳转到应用内页面(如订单详情页):使用ability类型的url,携带订单 ID 等参数;
- 跳转到网页:使用url类型的url,直接指定网页地址。
示例中已配置跳转到OrderDetailAbility,接收参数的代码如下(在OrderDetailAbility的onStart中):
import { AbilityConstant, UIAbility, Want } from '@ohos.app.ability';
import { window } from '@ohos.ui.window';
export default class OrderDetailAbility extends UIAbility {
onStart(want: Want) {
// 接收通知跳转携带的订单ID
const orderId = want.parameters?.orderId as string;
console.log(`跳转至订单详情页,订单ID:${orderId}`);
// 后续加载订单详情数据...
super.onStart(want);
}
}
四、进阶优化:让聚合通知更智能
1. 动态更新摘要通知的总条数
当同一分组的通知数量增加时,需更新摘要通知的 “总条数”,避免显示过时信息。实现方式:
- 维护每个订单的通知计数器(如用DistributedKVStore存储);
- 每次发送新通知前,更新计数器,再调用sendGroupSummaryNotification覆盖旧摘要。
// 维护订单通知计数器(示例:用内存变量,实际建议用本地存储)
private orderNotifyCountMap: Map<string, number> = new Map();
// 更新计数器并发送通知
async sendOrderNotifyWithCount(orderId: string, orderStatus: string, notifyContent: string) {
// 1. 更新计数器
const currentCount = (this.orderNotifyCountMap.get(orderId) || 0) + 1;
this.orderNotifyCountMap.set(orderId, currentCount);
// 2. 发送聚合通知(携带最新计数器)
await this.sendAggregatedOrderNotification(
orderId,
orderStatus,
notifyContent,
currentCount
);
}
2. 按 “时间 / 类型” 细分分组
若订单通知类型复杂(如 “状态更新”“优惠提醒”“物流通知”),可进一步细分分组:
- 分组标识格式改为order_group_${orderId}_${type}(如order_group_123456_logistics);
- 不同类型的通知归入不同分组,避免混在一起导致混乱。
3. 支持用户自定义聚合开关
在应用内添加 “通知聚合设置”,允许用户控制是否开启聚合:
- 若用户关闭聚合,发送通知时不设置group和groupSummary;
- 若用户开启聚合,按正常分组逻辑发送。
// 读取用户聚合设置(示例:从本地存储获取)
private async isUserEnableNotificationAggregation(): Promise<boolean> {
// 实际项目中从KV存储读取,此处简化为默认开启
return true;
}
// 发送通知时根据用户设置决定是否聚合
async sendNotificationByUserSetting(
orderId: string,
orderStatus: string,
notifyContent: string
) {
const isAggregated = await this.isUserEnableNotificationAggregation();
if (isAggregated) {
// 开启聚合:按分组逻辑发送
await this.sendOrderNotifyWithCount(orderId, orderStatus, notifyContent);
} else {
// 关闭聚合:直接发送单条通知(不设置group)
await this.sendSingleOrderNotification(orderId, orderStatus, notifyContent);
}
}
五、常见问题与避坑指南
1. 分组不生效?检查 3 个关键点
- 通知通道是否开启groupEnabled: true?未开启则无法分组;
- 所有通知的groupKey是否完全一致?大小写、字符差异都会导致分组失败;
- 是否发送了 “摘要通知”?没有摘要通知,系统无法识别分组,会显示多条单条通知。
2. 摘要通知被覆盖?注意通知 ID 唯一性
- 摘要通知的id需固定(如用summary_${orderId}生成),每次更新时用相同id覆盖旧摘要;
- 单条通知的id需唯一(如加Date.now()),避免被覆盖。
3. 小屏设备(如手表)适配
- 小屏设备建议简化摘要内容,仅保留核心信息(如 “3 条订单通知”);
- 单条通知的文本长度控制在 15 字以内,避免换行导致体验差。
更多推荐
所有评论(0)