引言

通知是移动应用中连接用户与信息的桥梁。一条好的通知——在恰当的时机、以恰当的形式、携带恰当的信息量——可以显著提升用户活跃度和留存率。反之,通知权限被拒绝、通知内容不当、通知频率过高,则会让用户直接卸载应用。

HarmonyOS NEXT 提供了完整的通知管理 API——@ohos.notificationManager(Notification Kit),支持从权限检测、授权请求、通知发布、通知取消到多种内容类型的基础/长文本/多行/图片通知的统一管理。所有 API 均为异步操作(支持 Promise 和 callback 两种调用方式),完美集成在 ArkTS 开发流程中。

本文构建一个通知管理实验室 Demo,在页面内实现通知权限检测与请求、三种通知内容类型(基础文本/长文本/多行文本)的创建与发布、通知取消管理(按 ID 取消 / 全部取消)、操作日志追踪等功能,全面演示通知管理的完整工作流。

读完本文,你将掌握:

  • 权限管理isNotificationEnabled() / requestEnableNotification() — 检测与请求通知权限
  • 发布通知publish(NotificationRequest) — 构造通知请求体并发布
  • 取消通知cancel(id) / cancelAll() — 按 ID 或全部清除通知
  • 三种内容类型NOTIFICATION_CONTENT_BASIC_TEXT / LONG_TEXT / MULTILINE — 适配不同信息密度的场景
  • NotificationContent 数据结构:每种类型对应的 normal / longText / multiLine 字段
  • 错误处理:Promise.catch() 模式捕获发布失败、权限拒绝等异常

一、notificationManager 体系总览

1.1 导入与模块结构

import { notificationManager } from '@kit.NotificationKit';

notificationManager 是一个全局单例对象,所有 API 通过它调用。在 API 24 + DevEco Studio 6.1.1 环境中,推荐使用 @kit.NotificationKit 导入路径。

1.2 核心 API 速查表

API 说明 返回值 权限要求
isNotificationEnabled() 检查当前应用通知是否已启用 Promise<boolean>
requestEnableNotification() 弹出系统对话框请求通知权限 Promise<void>
publish(request) 发布一条通知 Promise<void> 无(基础通知)
cancel(id) 按 ID 取消指定通知 Promise<void>
cancelAll() 取消当前应用所有通知 Promise<void>
setBadgeNumber(num) 设置桌面角标数字 Promise<void>
isBadgeDisplayed() 检查角标是否启用 Promise<boolean>
addSlot(slot) 添加通知渠道 Promise<void>
getSlot(slotType) 获取通知渠道配置 Promise<NotificationSlot>

核心发现:基本的发布/取消/权限操作全部无需声明任何权限,开箱即用。这是鸿蒙通知系统设计中非常友好的一个特点——Android 的通知权限管理相对复杂(需要 NotificationChannel + 运行时权限),而 HarmonyOS 将其大幅简化。

1.3 通知内容类型总览

HarmonyOS 支持四种通知内容类型:

内容类型 枚举值 对应字段 适用场景
基础文本 NOTIFICATION_CONTENT_BASIC_TEXT normal 即时通讯消息、系统提醒
长文本 NOTIFICATION_CONTENT_LONG_TEXT longText 邮件预览、详情摘要
多行文本 NOTIFICATION_CONTENT_MULTILINE multiLine 待办事项列表、消息汇总
图片通知 NOTIFICATION_CONTENT_PICTURE picture 截图分享、富媒体推送

每种类型对应 NotificationContent 中不同的数据字段,下文将逐一展开。

二、NotificationRequest — 通知请求体详解

NotificationRequestpublish() 方法的核心参数,它定义了一条通知的全部属性:

interface NotificationRequest {
  id: number;                    // 通知 ID(同一应用内唯一,用于后续取消)
  content: NotificationContent;  // 通知内容(根据 contentType 选择不同字段)
  deliveryTime?: number;         // 定时发布时间戳(毫秒)
  showDeliveryTime?: boolean;    // 是否在通知栏显示发送时间
  notificationSlotType?: notificationManager.SlotType;  // 通知渠道类型
  isFloatingIcon?: boolean;      // 是否显示浮动图标
  tapDismissed?: boolean;        // 点击后是否自动消失
  color?: number;                // 通知颜色
  badgeNumber?: number;          // 角标数字(可覆盖全局角标)
}

关键字段说明

  • id:整数类型,同一应用中每条通知必须有唯一 ID。发布同 ID 的通知会覆盖之前的那条。
  • contentNotificationContent 类型,是通知内容的核心载体,结构因 notificationContentType 而异。
  • notificationSlotType:通知渠道类型(社交、服务提醒、内容资讯等),影响系统对通知的排序和展示策略。
  • tapDismissed:设为 true 时,用户点击通知后自动从通知栏消失。

三、NotificationContent — 四种内容类型详解

3.1 NOTIFICATION_CONTENT_BASIC_TEXT — 基础文本

最基本的通知类型,包含标题和正文:

let content: notificationManager.NotificationContent = {
  notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
  normal: {
    title: '会议提醒',
    text: '14:00 在 3 号会议室进行项目评审',
    additionalText: '还有 3 人未确认出席'  // 可选补充信息
  }
};

normal 对应的 NotificationBasicContent 接口:

字段 类型 必填 说明
title string 通知标题
text string 通知正文内容
additionalText string 补充文本(显示在标题上方或下方)

基础文本通知适合绝大多数场景:即时通讯消息、任务提醒、状态变更通知等。

3.2 NOTIFICATION_CONTENT_LONG_TEXT — 长文本

当通知正文很长时,使用长文本类型——系统在通知栏只显示摘要,用户展开后看到完整内容:

let content: notificationManager.NotificationContent = {
  notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_LONG_TEXT,
  longText: {
    title: '邮件预览',
    text: '周报:本周进度正常,完成了核心模块开发',  // 收起的摘要
    briefText: '周报摘要',                           // 展开前的简洁描述
    longText: '详细内容:本周完成了用户模块、订单模块的接口开发...(此处可放大量文字)'
  }
};

longText 对应的 NotificationLongTextContent 接口:

字段 类型 必填 说明
title string 通知标题
text string 通知概要(收起状态显示)
briefText string 展开前的简短摘要
longText string 完整长文本(展开后显示)

使用场景:邮件摘要、新闻摘要、系统更新日志(ChangeLog)等需要携带较多信息的通知。

3.3 NOTIFICATION_CONTENT_MULTILINE — 多行文本

以列表形式展示多条信息,每条占一行:

let content: notificationManager.NotificationContent = {
  notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,
  multiLine: {
    title: '今日待办',
    text: '共 4 项待处理任务',
    briefText: '点击查看详情',
    lines: [
      '代码评审:PR #234 — 需要你的 Review',
      'Bug 修复:登录页偶发崩溃 — 优先级 P0',
      '会议:16:00 周会 — 3 楼会议室',
      '文档:更新 API 对接文档 — 本周五前'
    ]
  }
};

multiLine 对应的 NotificationMultiLineContent 接口:

字段 类型 必填 说明
title string 通知标题
text string 概要描述
briefText string 展开前的简短描述
lines Array<string> 每行一条文本,在通知栏展开后逐行显示

注意lines 数组的元素数量没有硬性上限,但建议控制在 5-8 条以内以保证可读性。

3.4 NOTIFICATION_CONTENT_PICTURE — 图片通知

附带大图的富媒体通知:

let content: notificationManager.NotificationContent = {
  notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_PICTURE,
  picture: {
    title: '截图已保存',
    text: '截屏已保存到相册',
    additionalText: '点击查看',
    picture: pixelMap  // image.PixelMap 对象
  }
};

图片通知需要提供一个 image.PixelMap 对象,适用于截图分享、图片消息推送等场景。由于需要获取 PixelMap,这部分实现比文本通知复杂,本文 Demo 以三种文本类型为主,图片通知作为知识扩展。
在这里插入图片描述
在这里插入图片描述

四、权限管理 — 检测与授权

4.1 isNotificationEnabled() — 检测通知状态

notificationManager.isNotificationEnabled().then((enabled: boolean) => {
  if (enabled) {
    // 通知已启用,可以直接发布
  } else {
    // 通知未启用,需要引导用户开启
  }
}).catch((err: Error) => {
  console.error('检测失败: ' + err.message);
});

这个 API 返回一个 Promise<boolean>true 表示用户已允许通知,false 表示用户关闭了通知或从未授权。

最佳实践:在应用首次启动或关键操作前调用此方法,根据结果决定 UI 展示(显示"开启通知"引导按钮或正常的通知功能入口)。

4.2 requestEnableNotification() — 请求授权

notificationManager.requestEnableNotification().then(() => {
  // 用户同意了通知授权
}).catch((err: Error) => {
  // 用户拒绝了授权
  // 注意:用户拒绝后不会再次弹出系统对话框
  // 需要引导用户前往系统设置手动开启
});

重要行为说明

  • 第一次调用:弹出系统级对话框,显示"允许"和"禁止"两个选项
  • 用户拒绝后再次调用:不会弹出对话框(系统层面的防骚扰机制),直接进入 catch
  • 用户已经允许后调用:直接进入 then,不弹窗

因此,如果用户拒绝了通知权限,唯一的恢复方式是引导用户前往系统设置手动开启。

五、发布与取消 — 通知的完整生命周期

5.1 publish() — 发布通知

let request: notificationManager.NotificationRequest = {
  id: 100,
  content: {
    notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
    normal: {
      title: '新消息',
      text: '你有一条来自张三的未读消息'
    }
  }
};

notificationManager.publish(request).then(() => {
  console.log('通知发布成功');
}).catch((err: Error) => {
  console.error('发布失败: ' + err.message);
});

发布注意事项

  • ID 管理:同一 ID 的通知后发会覆盖先发。应用中应维护一个递增计数器或使用时间戳来生成唯一 ID
  • 立即生效publish() 调用成功后,通知几乎立即出现在通知栏(无 deliveryTime 的情况下)
  • 通知栏限流:系统对短时间内大量发布有流控机制,批量通知场景需要控制频率

5.2 cancel() — 按 ID 取消

notificationManager.cancel(100).then(() => {
  console.log('通知 #100 已取消');
});

关键点:只能取消当前应用发布的通知,不能取消其他应用的通知(这保证了系统安全)。

5.3 cancelAll() — 取消全部

notificationManager.cancelAll().then(() => {
  console.log('所有通知已清除');
});

cancelAll() 会清除当前应用在通知栏的所有通知,无需逐个指定 ID。

典型使用场景

  • 用户退出登录时,清除所有与该账户相关的通知
  • 应用启动时,清除旧会话的残留通知
  • "一键已读"功能,取消所有通知并更新角标

5.4 错误处理模式

所有 notificationManager API 都返回 Promise,推荐使用统一的错误处理:

notificationManager.publish(request)
  .then(() => {
    // 成功
  })
  .catch((err: Error) => {
    // 失败 — 常见原因:
    // 1. 通知权限被拒绝
    // 2. 通知 ID 非法(负数或 0)
    // 3. content 必填字段缺失
    console.error('通知操作失败: ' + err.message);
  });

六、实战 Demo:通知管理实验室

页面结构

通知管理实验室
├── 标题栏 — "通知管理实验室" + "@ohos.notificationManager"
├── 通知状态卡片
│   ├── 通知启用状态指示器(绿色圆点 + "已启用"/红色圆点 + "未启用")
│   └── 请求通知权限按钮(仅在未启用时显示)
├── 发布通知卡片
│   ├── 通知类型选择器(水平滚动标签:基础文本/长文本/多行文本)
│   ├── 标题输入框
│   ├── 正文内容输入框
│   ├── 条件内容区(按类型动态切换)
│   │   ├── 基础文本:无额外字段
│   │   ├── 长文本:长文本正文输入框(多行 TextArea)
│   │   └── 多行文本:动态行列表(每行可编辑/可删除,可添加新行)
│   ├── 发布按钮
│   └── 已发布计数和下一个 ID 显示
├── 通知管理卡片
│   ├── 取消最近一条按钮
│   ├── 取消全部通知按钮
│   └── 重新检测状态链接
├── 操作日志卡片
│   └── 时间 + 操作类型(颜色区分)+ 详情,最多 30 条
├── 通知内容类型参考卡片(4 种类型说明)
└── 核心 API 参考 — 8 个关键 API

4 个交互点

  1. 通知权限检测与请求 — 页面启动时自动检测通知状态,未启用时显示"请求通知权限"按钮,点击后弹出系统授权对话框
  2. 三种通知类型切换发布 — 顶部标签栏切换基础文本/长文本/多行文本,每种类型显示对应的内容输入区,填写后点击"发布通知"将通知发送到系统通知栏
  3. 通知取消管理 — "取消最近一条"按 ID 精确取消,"取消全部通知"一键清除所有通知,发布计数实时更新
  4. 操作日志追踪 — 每次发布/取消/权限操作都会生成时间戳日志,日志以颜色区分操作类型(蓝色=发布,红色=取消,绿色=权限),最多保留 30 条

核心代码实现

权限检测
aboutToAppear(): void {
  notificationManager.isNotificationEnabled().then((enabled: boolean) => {
    this.notifyEnabled = enabled ? '已启用' : '未启用';
  }).catch(() => {
    this.notifyEnabled = '检测失败';
  });
}

页面启动时自动检测,结果存入 @State notifyEnabled,UI 根据状态显示绿色/红色指示器和相应按钮。

按类型构造 NotificationContent
publishNotification(): void {
  let id = this.nextId;
  this.nextId++;

  let content: notificationManager.NotificationContent = {
    notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
    normal: { title: this.notifTitle, text: this.notifText }
  };

  if (this.activeType === 1) {
    content = {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_LONG_TEXT,
      longText: {
        title: this.notifTitle,
        text: this.notifText,
        briefText: this.notifText,
        longText: this.longText
      }
    };
  } else if (this.activeType === 2) {
    let lines = this.multilineLines.split('\n');
    content = {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,
      multiLine: {
        title: this.notifTitle,
        text: this.notifText,
        briefText: '共 ' + lines.length + ' 条信息',
        lines: lines
      }
    };
  }

  let request: notificationManager.NotificationRequest = {
    id: id,
    content: content
  };

  notificationManager.publish(request).then(() => {
    this.publishCount++;
    this.addLog('发布', '#' + id + ' — ' + this.notifTitle);
  }).catch((err: Error) => {
    this.addLog('失败', '#' + id + ' 发布失败: ' + err.message);
  });
}

核心逻辑:根据 activeType(0/1/2)选择对应的 notificationContentType 和内容字段,构造 NotificationContent,嵌入 NotificationRequest,调用 publish()

动态多行编辑

多行文本的通知需要用户编辑多行内容,Demo 通过 split('\n') 将字符串转换为数组,再通过 ForEach 渲染每一行为独立的 TextInput

ForEach(this.getLineArray(), (line: string, idx: number) => {
  Row() {
    TextInput({ text: line })
      .fontSize(11)
      .layoutWeight(1)
      .height(34)
      .onChange((v: string) => { this.updateLine(idx, v); })
    Text('✕')
      .fontColor('#EF4444')
      .width(28)
      .textAlign(TextAlign.Center)
      .onClick(() => { this.deleteLine(idx); })
  }
  .width('100%')
  .margin({ bottom: 4 })
})

addLine() 追加新行,deleteLine(index) 移除指定行(至少保留 1 行),updateLine(index, value) 更新指定行的内容。

操作日志追踪
addLog(action: string, detail: string): void {
  let now = new Date();
  let time = now.getHours().toString().padStart(2, '0') + ':' +
    now.getMinutes().toString().padStart(2, '0') + ':' +
    now.getSeconds().toString().padStart(2, '0');
  let copy: NotifyLog[] = [];
  for (let i = 0; i < this.logs.length; i++) {
    copy.push(this.logs[i]);
  }
  copy.push(new NotifyLog(time, action, detail));
  if (copy.length > 30) {
    copy = copy.slice(copy.length - 30);
  }
  this.logs = copy;
}

日志数组的更新遵循 ArkTS 不可变状态更新模式:创建新数组 → 拷贝旧元素 → push 新条目 → slice 限长 → 赋值给 @State

预览效果预期

  • 状态检测:页面加载后通知状态栏显示绿色"已启用"或红色"未启用",未启用时出现蓝色授权按钮
  • 基础文本通知:填写标题和内容后点击"发布通知",通知栏立即出现一条标准通知
  • 长文本通知:切换到"长文本"标签,填写长文本正文后发布,通知在通知栏展开后显示完整内容
  • 多行文本通知:切换到"多行文本"标签,动态添加/编辑/删除行,发布后通知栏显示多行列表
  • 取消操作:点击"取消最近一条"移除最新发布的通知,"取消全部通知"清除所有
  • 日志追踪:每次操作产生一条彩色日志,发布=蓝、取消=红、授权=绿

七、与 Android NotificationManager 的对比

维度 HarmonyOS notificationManager Android NotificationManager
导入 @kit.NotificationKit android.app.NotificationManager
权限检测 isNotificationEnabled() 返回 Promise areNotificationsEnabled() 同步返回
权限请求 requestEnableNotification() 弹系统对话框 无直接 API,需跳转到设置页
通知渠道 NotificationSlotType 枚举(简化) 必须创建 NotificationChannel
发布方式 publish(NotificationRequest) Promise notify(id, notification) 同步
内容类型 NotificationContent + 四种 contentType NotificationCompat.Builder + Style
Builder 模式 无 Builder,直接构造对象 NotificationCompat.Builder 流式 API
多行文本 multiLine.lines: string[] NotificationCompat.InboxStyle

HarmonyOS 的优势

  1. 无需 Builder:直接构造对象,代码更简洁
  2. 权限请求内置requestEnableNotification() 一键弹窗,Android 需要手动跳转设置
  3. 通知渠道简化:枚举值选择而非强制性创建,降低初学者的心智负担

Android 的优势

  1. 通知渠道的精细控制(重要性等级、振动模式、LED 颜色等可逐渠道独立配置)
  2. 通知组的折叠展开控制更灵活

八、实战技巧与常见问题

8.1 通知 ID 管理策略

推荐的 ID 生成方式:

// 方式一:递增计数器
private nextId: number = Date.now();  // 用时间戳初始化避免与旧通知冲突
nextId++;

// 方式二:业务 ID 映射(如消息 ID)
let notificationId = message.messageId;

注意:使用较小的固定数字作为 ID 容易导致覆盖。建议使用 4 位以上的递增整数或业务相关 ID。

8.2 被拒绝后的用户引导

requestEnableNotification() 被拒绝后不会再次弹窗。此时应:

  1. 检测 isNotificationEnabled() 返回 false
  2. 显示引导文字:“通知权限已被关闭,请前往系统设置 > 应用 > 通知管理中开启”
  3. 提供"去设置"按钮,通过 bundleManager.canOpenLinkopenLink 跳转到应用设置页

8.3 通知发布失败的常见原因

  1. 通知权限未开启isNotificationEnabled() 返回 false
  2. 必填字段缺失titletext 为空字符串
  3. contentType 与内容字段不匹配 — 声明了 BASIC_TEXT 但赋值了 longText 字段
  4. 通知 ID 非法 — 使用负数或 0 作为 ID

九、总结

@ohos.notificationManager 是 HarmonyOS 通知系统的统一入口,提供了一套简洁、Promise-first 的异步 API,覆盖了从权限管理到通知发布/取消的完整生命周期:

  1. 零权限起步:基础的通知发布/取消/检测无需任何权限声明,降低了接入门槛
  2. 四种内容类型:BASIC_TEXT / LONG_TEXT / MULTILINE / PICTURE 覆盖了从简单文本到富媒体的全场景
  3. Promise 驱动:所有 API 返回 Promise,天然适配 async/await 和链式处理
  4. 权限管理简单isNotificationEnabled() + requestEnableNotification() 两步完成检测与授权
  5. 取消灵活:支持按 ID 精确取消和全部清除,满足消息撤回、已读管理等需求
  6. 数据结构清晰NotificationRequestNotificationContent → 类型对应的内容字段,层次分明

对于 HarmonyOS 开发者而言,Notification Kit 是应用与用户保持连接的基础设施。无论是即时通讯的消息推送、协作工具的任务提醒、还是电商应用的活动通知,这套 API 都提供了足够灵活和强大的支持。

结合实战 Demo 中的三种通知类型切换、多行动态编辑、操作日志追踪等功能,开发者可以快速上手并集成到实际项目中。


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐