鸿蒙操作系统使用 Notification Kit 实现本地通知发布与进度条更新实战
一、背景说明
HarmonyOS 7 近期持续推送补丁包,跨设备「通知流转」正在成为生态标配能力(如与 Apple Watch 的通知流转互联),而通知能力的第一步始终是应用内的本地通知发布。本文不展开跨设备流转,聚焦一个具体技术点:使用 Notification Kit(@kit.NotificationKit)实现鸿蒙应用本地通知的完整生命周期——授权申请、文本通知发布、带 WantAgent 的点击跳转、进度条通知的持续更新与取消。
二、技术原理
Notification Kit 提供应用本地通知的发布通道,核心概念如下:
- 授权流程:应用通知能力默认关闭,先
isNotificationEnabled()查询,未授权时requestEnableNotification()拉起授权框。 - NotificationRequest:通知请求对象,
id标识一条通知;相同id再次 publish 会更新原通知,不同id则新建。 - Slot(通知渠道):通过
addSlot()声明渠道类型(社交通讯、服务提醒、内容资讯等),影响铃声/横幅等展示形态。 - WantAgent:由 Ability Kit 创建的行为意图,封装进通知后,用户点击通知即可拉起应用指定页面。
- 进度条模板:系统唯一模板
downloadTemplate,通过template.data.progressValue携带进度,配合updateOnly: true只更新不新建。
数据流:授权查询/申请 → 构造 NotificationRequest(可带 WantAgent / template)→ notificationManager.publish() → 通知中心展示 → publish 同 id 更新 / cancel 取消。
三、实现步骤
工程为 Stage 模型(API 12+)。通知能力无需在 module.json5 声明用户权限(requestEnableNotification 走系统授权框),保持默认配置即可。
1. 通知管理类 NotifyManager.ets
import { notificationManager } from '@kit.NotificationKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';
import { Context } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
export class NotifyManager {
// 第一步:确保通知权限已开启
static async ensurePermission(context: Context): Promise<boolean> {
const enabled = await notificationManager.isNotificationEnabled();
if (enabled) {
return true;
}
// 拉起系统授权框,由用户决定是否开启
return await notificationManager.requestEnableNotification(context)
.then(() => true)
.catch((err: BusinessError) => {
console.error(`auth denied, code=${err.code}, msg=${err.message}`);
return false;
});
}
// 第二步:发布普通文本通知
static async publishText(id: number, title: string, text: string): Promise<void> {
const request: notificationManager.NotificationRequest = {
id: id,
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: title,
text: text,
additionalText: '鸿蒙通知实战'
}
}
};
await notificationManager.publish(request);
}
// 第三步:发布带点击跳转(WantAgent)与操作按钮的通知
static async publishWithAction(id: number, title: string, text: string,
abilityName: string): Promise<void> {
const wantAgentInfo: wantAgent.WantAgentInfo = {
wants: [
{
bundleName: 'com.example.notifydemo',
abilityName: abilityName, // 点击通知拉起的目标 UIAbility
entities: ['entity.system.home'],
parameters: { 'from': 'notification' }
}
],
requestCode: 0,
actionType: wantAgent.OperationType.START_ABILITY,
actionFlags: [wantAgent.WantAgentFlags.CONSTANT_FLAG]
};
const agent: WantAgent = await wantAgent.getWantAgent(wantAgentInfo);
const request: notificationManager.NotificationRequest = {
id: id,
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: { title: title, text: text }
},
wantAgent: agent, // 点击通知本体触发
actionButtons: [
{ title: '查看详情', wantAgent: agent } // 通知按钮
]
};
await notificationManager.publish(request);
}
// 第四步:发布进度条通知(下载场景)
static async publishProgress(id: number, fileName: string, progressValue: number): Promise<void> {
const request: notificationManager.NotificationRequest = {
id: id,
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '正在下载',
text: fileName
}
},
template: {
name: 'downloadTemplate', // 模板名固定为 downloadTemplate
data: {
title: '文件下载',
fileName: fileName,
progressValue: progressValue // 0~100
}
}
};
await notificationManager.publish(request);
}
// 第五步:仅更新已有进度条通知(updateOnly 不存在同 id 时会失败)
static async updateProgress(id: number, fileName: string, progressValue: number): Promise<void> {
const request: notificationManager.NotificationRequest = {
id: id,
updateOnly: true, // API 18+:只更新已存在的通知
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: { title: '正在下载', text: fileName }
},
template: {
name: 'downloadTemplate',
data: { title: '文件下载', fileName: fileName, progressValue: progressValue }
}
};
await notificationManager.publish(request);
}
// 取消指定通知
static async cancel(id: number): Promise<void> {
await notificationManager.cancel(id);
}
}
2. UI 调用示例 Index.ets
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { NotifyManager } from '../model/NotifyManager';
@Entry
@Component
struct Index {
private context = getContext(this) as common.UIAbilityContext;
@State progress: number = 0;
private timerId: number = -1;
// 模拟下载:进度条通知从 0 更新到 100
startDownload(): void {
this.progress = 0;
NotifyManager.publishProgress(1001, 'music.mp4', 0)
.catch((err: BusinessError) => console.error(`publish failed: ${err.code}`));
this.timerId = setInterval(() => {
this.progress += 10;
if (this.progress >= 100) {
clearInterval(this.timerId);
// 下载完成:更新为 100 后延时取消通知
NotifyManager.updateProgress(1001, 'music.mp4', 100)
.then(() => {
setTimeout(() => { NotifyManager.cancel(1001); }, 2000);
});
return;
}
NotifyManager.updateProgress(1001, 'music.mp4', this.progress)
.catch((err: BusinessError) => {
clearInterval(this.timerId);
console.error(`update failed, code=${err.code}`);
});
}, 1000);
}
build() {
Column({ space: 16 }) {
Button('发布文本通知')
.onClick(() => {
NotifyManager.ensurePermission(this.context)
.then((ok: boolean) => {
if (ok) {
NotifyManager.publishText(1000, '新消息提醒', '您有一条新的待办事项');
}
});
})
Button('发布可点击跳转的通知')
.onClick(() => {
NotifyManager.ensurePermission(this.context)
.then((ok: boolean) => {
if (ok) {
NotifyManager.publishWithAction(1002, '作业提醒',
'点击查看今日任务详情', 'EntryAbility');
}
});
})
Button('开始模拟下载(进度条通知)')
.onClick(() => {
NotifyManager.ensurePermission(this.context)
.then((ok: boolean) => {
if (ok) { this.startDownload(); }
});
})
Button('取消全部通知')
.onClick(() => {
notificationManager.cancelAll();
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
四、应用场景示例
下载管理器中监听真实下载进度并同步到通知栏:
import { request } from '@kit.BasicServicesKit';
// 下载任务回调中同步通知进度
downloadTask.on('progress', (received: number, total: number) => {
const percent = Math.floor(received * 100 / total);
NotifyManager.updateProgress(1001, 'update.zip', percent)
.catch(() => { /* 通知已被用户移除时静默处理 */ });
});
五、技术要点
1. 频次限制
- 单应用发布新通知累计不超过 10 条/秒,更新通知不超过 20 条/秒,超限会返回错误码——进度更新节流到 500ms 以上一次即可安全覆盖;
- 单应用在通知中心留存上限 24 条,通知体序列化后不能超过 200KB。
2. 授权被拒后的降级
requestEnableNotification 被用户拒绝后再次调用会返回 1600004(用户拒绝),此时不应反复拉起授权框,应引导用户到设置页手动开启。
3. 错误处理
try {
await NotifyManager.publishProgress(1001, 'a.mp4', 50);
} catch (err) {
const e = err as BusinessError;
if (e.code === 1600004) {
console.error('通知授权被拒绝');
} else if (e.code === 1600018) {
console.error('进度更新过于频繁,需节流重试');
} else {
console.error(`notify error code=${e.code}, msg=${e.message}`);
}
}
4. 模板使用前提
进度条模板需先 isSupportTemplate('downloadTemplate') 确认设备支持(当前系统模板仅此一种),不支持时降级为普通文本通知并在 additionalText 中携带百分比。
六、扩展建议
- 多行文本通知:
notificationContentType使用NOTIFICATION_CONTENT_MULTILINE,最多展示三行内容; - 后台定时通知:进程退后台后需要定时提醒(抢购、日程),接入 Background Tasks Kit 的提醒类任务而非常驻进程轮询;
- 通知分组:同组通知用
groupName聚合,并用cancelGroup一键撤销:
const request: notificationManager.NotificationRequest = {
id: 2001,
groupName: 'download_group', // 同组通知在通知中心折叠展示
content: { /* ... */ }
};
结语
本文用 Notification Kit 完成了鸿蒙应用本地通知从授权、发布、WantAgent 跳转到进度条模板更新的完整实现,核心代码约 180 行,均可直接编译运行。掌握这条链路后,下载进度、消息提醒、任务催办等场景都能以系统级通知的形态触达用户,而不需要引入任何推送服务。
更多推荐


所有评论(0)