OpenHarmony 通知消息 Notification 完整开发(API Version23 + 适配版)
摘要
Notification 通知模块用于在系统状态栏弹出消息提醒,包含普通文本通知、多行详情通知、大图片横幅通知、常驻后台通知,适用于消息推送、定时提醒、任务进度、离线消息等场景。API Version23 重构通知渠道管理、权限校验、通知生命周期、点击跳转 Want 逻辑,修复低版本通知无法弹出、点击无响应、重复推送、后台进程通知消失、渠道删除残留等兼容缺陷。旧项目升级 API23 后常出现:发送通知无任何状态栏提示、点击通知无法跳转页面、退出应用通知自动清除、多次推送产生大量重复通知、无通知权限直接报错闪退等问题。本文基于 DevEco Studio 适配 OpenHarmony API23 及以上版本,封装全局通知工具类,实现普通文本通知、大图通知、常驻通知、通知点击路由跳转四大核心能力,搭配消息提醒、后台定时任务两套实战页面提供完整可运行代码,输出通知权限、渠道创建、资源销毁规范,汇总版本升级兼容故障解决方案,为鸿蒙消息提醒功能开发提供标准化实操模板。
关键词
OpenHarmony;ArkUI;API Version23;Notification;系统通知;消息推送;通知渠道;通知点击跳转
一、引言
1.1 通知开发背景
聊天消息、日程提醒、下载进度、离线推送都依赖系统通知能力,通知独立于应用页面,锁屏、应用切后台状态下仍可展示在状态栏。系统对通知实行渠道分组管理,同类型消息共用一个渠道,用户可在系统设置单独关闭某一类通知。 OpenHarmony API Version23 针对 Notification 底层调度引擎完成全面升级,核心变更点:
- 强制所有通知必须先创建 NotificationChannel 渠道,无渠道发送直接失败;
- 重构通知动态权限校验逻辑,未授予通知权限拦截推送并友好提示;
- 标准化点击通知 Want 跳转规则,区分打开页面、跳转 Ability;
- 优化通知缓存队列,限制同一渠道短时间重复推送频率,避免刷屏;
- 新增常驻通知(ONGOING)生命周期管控,退出应用不会自动移除;
- 修复通知 ID 复用覆盖原有通知、渠道删除后无法重建的 bug。
大量 API9~11 旧项目升级后,调用推送接口状态栏无消息,根源是缺少渠道创建逻辑、未申请通知动态权限,因此掌握 API23 标准通知封装规范是消息提醒类功能必备技能。
1.2 开发环境与测试场景
开发工具:DevEco Studio 5.0 及以上 适配系统:OpenHarmony API Version23、HarmonyOS NEXT 导入模块:@ohos.notification、@ohos.notificationManager 前置权限:动态通知权限 ohos.permission.NOTIFICATION_AGENT 测试场景:普通文字消息通知、大图预览通知、常驻后台提醒、点击通知跳转指定页面、清除全部通知、删除单条通知
二、API23+ Notification 通知核心 API 与版本变更说明
2.1 核心模块导入
ets
import notificationManager from '@ohos.notificationManager' import notification from '@ohos.notification'2.2 通知渠道创建(API23 强制前置)
ets
// 创建渠道配置 const channel: notification.NotificationChannel = { id: "msg_channel", name: "消息通知", description: "应用普通消息提醒", importance: notification.NotificationImportance.LEVEL_3 } await notificationManager.createChannel(channel)importance 优先级等级:
- LEVEL_0:无提醒,静默存储
- LEVEL_3:状态栏展示 + 提示音(常规消息推荐)
- LEVEL_4:横幅弹窗强提醒
2.3 通知基础推送结构
- NotificationRequest:通知载体,包含 id、渠道 ID、内容、点击跳转 want
- NotificationContent:通知内容,支持普通文本、大图、多行文本
- Want:点击通知后跳转页面路由参数
2.4 常用控制 API
- notificationManager.publish (request):推送通知
- notificationManager.cancel (id):根据 ID 删除单条通知
- notificationManager.cancelAll ():清空本应用全部通知
- notificationManager.getChannels ():获取已创建渠道列表
2.5 API23 废弃与强制约束
- 废弃无渠道直接推送通知,必须提前创建对应 channel;
- 通知属于动态敏感权限,页面调用前必须申请 NOTIFICATION_AGENT;
- 相同 channel + 相同 id 会覆盖旧通知,不同 id 生成多条独立消息;
- 常驻 ONGOING 通知无法被用户手动清除,仅代码可 cancel;
- 后台无进程状态下部分设备限制普通通知推送,常驻通知不受限。
三、API23 标准基础示例代码
3.1 创建通知渠道 + 普通文本通知推送
ets
import notificationManager from '@ohos.notificationManager' import notification from '@ohos.notification' import Want from '@ohos.app.ability.Want' import router from '@ohos.router' async function createMsgChannel() { const channel: notification.NotificationChannel = { id: "msg_default", name: "通用消息", description: "应用各类消息推送提醒", importance: notification.NotificationImportance.LEVEL_3 } await notificationManager.createChannel(channel) } async function sendSimpleNotify(id: number, title: string, content: string) { await createMsgChannel() // 点击跳转首页Want let want: Want = { bundleName: getContext(this).bundleName, abilityName: "EntryAbility", uri: "pages/index/index" } const notifyRequest: notification.NotificationRequest = { id: id, channelId: "msg_default", content: { contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: title, text: content } }, want: want } await notificationManager.publish(notifyRequest) }3.2 清除指定 ID 通知
ets
async function cancelSingleNotify(notifyId: number) { await notificationManager.cancel(notifyId) } async function clearAllNotify() { await notificationManager.cancelAll() }四、两大业务完整实战案例(全兼容 API23)
4.1 实战一:全局通知工具类封装(utils/notify_util.ets)
ets
import notificationManager from '@ohos.notificationManager' import notification from '@ohos.notification' import Want from '@ohos.app.ability.Want' import common from '@ohos.app.ability.common' import promptAction from '@ohos.promptAction' import PermissionUtil, { PERMISSION } from './permission_util' // 通知渠道常量统一管理 export const NOTIFY_CHANNEL = { MSG: "channel_msg", TASK: "channel_task" } class NotifyUtil { private static instance: NotifyUtil private ctx: common.UIAbilityContext | null = null static getInstance(): NotifyUtil { if (!NotifyUtil.instance) { NotifyUtil.instance = new NotifyUtil() } return NotifyUtil.instance } setContext(context: common.UIAbilityContext) { this.ctx = context } // 初始化消息通知渠道 private async createMsgChannel() { const channel: notification.NotificationChannel = { id: NOTIFY_CHANNEL.MSG, name: "消息通知", description: "聊天、资讯类消息提醒", importance: notification.NotificationImportance.LEVEL_3 } await notificationManager.createChannel(channel) } // 初始化后台任务常驻渠道 private async createTaskChannel() { const channel: notification.NotificationChannel = { id: NOTIFY_CHANNEL.TASK, name: "后台任务", description: "下载、同步常驻提醒", importance: notification.NotificationImportance.LEVEL_2 } await notificationManager.createChannel(channel) } // 推送普通文本通知 async sendBasicNotify(notifyId: number, title: string, text: string, pageUrl: string) { if (!this.ctx) return // 前置校验通知权限 const hasPerm = PermissionUtil.checkSingle("ohos.permission.NOTIFICATION_AGENT") if (!hasPerm) { promptAction.showToast({ message: "未开启通知权限,无法推送消息" }) return } await this.createMsgChannel() // 构建跳转Want const want: Want = { bundleName: this.ctx.bundleName, abilityName: "EntryAbility", uri: pageUrl } const request: notification.NotificationRequest = { id: notifyId, channelId: NOTIFY_CHANNEL.MSG, content: { contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title, text } }, want: want } try { await notificationManager.publish(request) promptAction.showToast({ message: "通知已发送至状态栏" }) } catch (err) { promptAction.showToast({ message: "通知推送失败" }) console.error("推送通知异常", err) } } // 推送常驻后台通知(无法手动清除) async sendOngoingTaskNotify(notifyId: number, title: string, text: string) { if (!this.ctx) return const hasPerm = PermissionUtil.checkSingle("ohos.permission.NOTIFICATION_AGENT") if (!hasPerm) return await this.createTaskChannel() const request: notification.NotificationRequest = { id: notifyId, channelId: NOTIFY_CHANNEL.TASK, content: { contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title, text } }, ongoing: true // 标记为常驻通知 } await notificationManager.publish(request) } // 删除单条通知 async cancelNotify(notifyId: number) { await notificationManager.cancel(notifyId) promptAction.showToast({ message: "已移除该条通知" }) } // 清空全部通知 async clearAll() { await notificationManager.cancelAll() promptAction.showToast({ message: "已清空所有通知" }) } } export default NotifyUtil.getInstance()4.2 实战二:通知推送演示页面(普通通知 + 常驻任务通知)
ets
import NotifyUtil from '../utils/notify_util' import PermissionUtil from '../utils/permission_util' @Entry @Component struct NotificationPage { notifyId: number = 1001 taskNotifyId: number = 9001 aboutToAppear() { // 绑定页面上下文 const ctx = getContext(this) NotifyUtil.setContext(ctx) PermissionUtil.setContext(ctx) } // 发送普通资讯通知,点击跳转首页 async sendMsgNotify() { await NotifyUtil.sendBasicNotify( this.notifyId++, "新资讯推送", "今日鸿蒙技术更新,点击查看详情", "pages/index/index" ) } // 发送常驻后台同步通知 async sendSyncTaskNotify() { await NotifyUtil.sendOngoingTaskNotify( this.taskNotifyId, "文件同步中", "后台正在同步本地笔记数据" ) } // 清除常驻任务通知 async removeTaskNotify() { await NotifyUtil.cancelNotify(this.taskNotifyId) } // 清空全部通知 async clearAllNotify() { await NotifyUtil.clearAll() } build() { Column({ space: 20 }) { Text("系统通知Notification演示") .fontSize(22) .fontWeight(FontWeight.Bold) .margin({ bottom: 10 }) Button("推送普通资讯通知") .width(300) .height(46) .backgroundColor("#007DFF") .onClick(async () => await this.sendMsgNotify()) Button("推送常驻后台同步通知") .width(300) .height(46) .backgroundColor("#009966") .onClick(async () => await this.sendSyncTaskNotify()) Button("移除常驻同步通知") .width(300) .height(46) .backgroundColor("#ff9500") .onClick(async () => await this.removeTaskNotify()) Button("清空全部应用通知") .width(300) .height(46) .backgroundColor("#f56c6c") .onClick(async () => await this.clearAllNotify()) } .width("100%") .height("100%") .justifyContent(FlexAlign.Center) .padding(20) .backgroundColor("#F5F5F5") } }五、API23+ 通知适配与性能优化规范
5.1 渠道管理规范
- 按业务类型拆分渠道:消息、后台任务、活动推送分开创建;
- 页面推送前自动检测并创建渠道,无需手动提前执行;
- 同一渠道相同 ID 通知会覆盖,不同 ID 独立多条展示。
5.2 权限交互规范
- 推送通知前校验 NOTIFICATION_AGENT 动态权限,无权限阻断推送并提示;
- 应用首次使用通知功能主动申请权限,不静默失败;
- 用户永久拒绝权限时提示前往系统设置开启通知。
5.3 常驻通知业务规范
- 下载、同步、录音等后台服务使用 ongoing 常驻通知;
- 常驻通知用户无法手动清除,业务完成必须代码调用 cancel 删除;
- 普通聊天、资讯消息不使用常驻类型,允许用户上滑清除。
5.4 跳转 Want 规范
- Want 必须填写当前应用 bundleName 与 EntryAbility;
- uri 填写目标页面路由地址,点击通知自动跳转对应业务页面;
- 需要携带参数可在 want.parameters 中追加自定义键值。
六、API23 升级高频兼容问题与解决方案
问题 1:调用推送接口,状态栏完全不显示通知 解决:1. 创建对应 NotificationChannel 渠道;2. 授予 NOTIFICATION_AGENT 通知权限;3. 渠道 importance 等级≥LEVEL_2。
问题 2:多次推送通知只会显示一条,新消息覆盖旧消息 解决:每次推送使用不同 notifyId,相同 ID 会覆盖同渠道旧通知。
问题 3:点击通知无任何页面跳转 解决:完整配置 want 的 bundleName、abilityName、uri 页面路由。
问题 4:退出应用后常驻通知自动消失 解决:推送时设置 ongoing:true 标记为后台常驻通知。
问题 5:升级 API23 旧代码直接推送报错 解决:全部补充渠道创建逻辑,API9 及以下无强制渠道要求,API23 必须创建。
问题 6:短时间连续推送多条通知系统拦截不展示 解决:拆分不同 channel 或增加推送间隔,避免高频刷屏触发系统限流。
七、总结
Notification 系统通知是鸿蒙应用消息提醒标准实现方案,API Version23 强制引入通知渠道前置创建、动态权限校验机制,统一通知内容、点击跳转、常驻任务的标准化配置,彻底解决旧版无消息、点击失效、通知丢失等核心兼容问题。项目封装全局通知工具类,拆分消息、任务双渠道,提供普通通知、常驻后台通知、清除通知全套方法,搭配权限前置校验,适配资讯推送、后台同步、日程提醒等主流业务场景。