鸿蒙Notification Kit通知服务开发快速指南

鸿蒙Notification Kit通知服务开发快速指南

一、Notification Kit概述

Notification Kit为开发者提供本地通知发布能力,可以在应用运行时向用户推送通知,包括文本、进度条、角标等多种样式。

1.1 核心能力

  • ✅ 发布文本类型通知(普通文本、多行文本)
  • ✅ 发布进度条通知
  • ✅ 管理应用角标
  • ✅ 取消和查询通知
  • ✅ 请求用户授权

1.2 业务流程

sequenceDiagram participant App as 应用 participant NM as NotificationManager participant User as 用户 participant NC as 通知中心 App->>NM: 请求授权 NM->>User: 弹窗询问 User->>NM: 允许/拒绝 NM-->>App: 授权结果 App->>NM: publish(通知) NM->>NC: 展示通知 NC->>User: 显示通知

1.3 约束限制

限制项 说明
留存数量 单个应用最多24条
通知大小 不超过200KB
发布频次 单应用≤10条/秒
更新频次 单应用≤20条/秒

二、请求通知授权

应用首次发布通知前必须获取用户授权。

2.1 授权流程

typescript 复制代码
import { notificationManager } from '@kit.NotificationKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

class NotificationAuth {
  async requestPermission(context: common.UIAbilityContext) {
    try {
      // 1. 检查是否已授权
      let isEnabled = await notificationManager.isNotificationEnabled();

      if (!isEnabled) {
        // 2. 请求授权(首次会弹窗)
        await notificationManager.requestEnableNotification(context);
        console.info('通知授权成功');
      } else {
        console.info('已获得通知授权');
      }
    } catch (err) {
      let error = err as BusinessError;
      if (error.code === 1600004) {
        console.error('用户拒绝授权');
        // 3. 可选:拉起设置页面再次请求
        this.openSettings(context);
      } else {
        console.error(`授权失败: ${error.message}`);
      }
    }
  }

  async openSettings(context: common.UIAbilityContext) {
    try {
      await notificationManager.openNotificationSettings(context);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`打开设置失败: ${error.message}`);
    }
  }
}

三、发布文本通知

3.1 普通文本通知

typescript 复制代码
import { notificationManager } from '@kit.NotificationKit';
import { BusinessError } from '@kit.BasicServicesKit';

async function publishTextNotification() {
  let notificationRequest: notificationManager.NotificationRequest = {
    id: 1,
    content: {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
      normal: {
        title: '新消息',
        text: '您有一条新消息',
        additionalText: '刚刚'
      }
    }
  };

  try {
    await notificationManager.publish(notificationRequest);
    console.info('通知发布成功');
  } catch (err) {
    let error = err as BusinessError;
    console.error(`通知发布失败: ${error.message}`);
  }
}

3.2 多行文本通知

typescript 复制代码
async function publishMultiLineNotification() {
  let notificationRequest: notificationManager.NotificationRequest = {
    id: 2,
    content: {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,
      multiLine: {
        title: '会议提醒',
        text: '团队会议',
        briefText: '3条新通知',
        longTitle: '今日会议安排',
        lines: [
          '上午10:00 - 产品评审会',
          '下午14:00 - 技术分享会',
          '下午16:00 - 周报会议'
        ]
      }
    }
  };

  try {
    await notificationManager.publish(notificationRequest);
  } catch (err) {
    let error = err as BusinessError;
    console.error(`发布失败: ${error.message}`);
  }
}

四、进度条通知

4.1 下载进度示例

typescript 复制代码
class DownloadNotification {
  private notificationId = 100;

  async showDownloadProgress(fileName: string, progress: number) {
    let notificationRequest: notificationManager.NotificationRequest = {
      id: this.notificationId,
      content: {
        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
        normal: {
          title: `下载中: ${fileName}`,
          text: `进度: ${progress}%`,
          additionalText: ''
        }
      },
      // 进度条配置
      template: {
        name: 'downloadTemplate',
        data: {
          progressValue: progress,
          progressMaxValue: 100
        }
      }
    };

    try {
      await notificationManager.publish(notificationRequest);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`更新进度失败: ${error.message}`);
    }
  }

  async completeDownload(fileName: string) {
    let notificationRequest: notificationManager.NotificationRequest = {
      id: this.notificationId,
      content: {
        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
        normal: {
          title: '下载完成',
          text: fileName,
          additionalText: '点击查看'
        }
      }
    };

    await notificationManager.publish(notificationRequest);
  }

  async cancelDownload() {
    await notificationManager.cancel(this.notificationId);
  }
}

// 使用示例
let downloader = new DownloadNotification();
// 模拟下载进度
for (let i = 0; i <= 100; i += 10) {
  await downloader.showDownloadProgress('document.pdf', i);
  await new Promise(resolve => setTimeout(resolve, 500));
}
await downloader.completeDownload('document.pdf');

五、通知角标管理

5.1 设置和更新角标

typescript 复制代码
class BadgeManager {
  async setBadgeNumber(count: number) {
    let notificationRequest: notificationManager.NotificationRequest = {
      id: 1,
      content: {
        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
        normal: {
          title: '新消息',
          text: `您有${count}条未读消息`
        }
      },
      // 设置角标数字
      badgeNumber: count
    };

    try {
      await notificationManager.publish(notificationRequest);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`设置角标失败: ${error.message}`);
    }
  }

  async clearBadge() {
    // 取消所有通知即可清除角标
    await notificationManager.cancelAll();
  }
}

六、通知管理操作

6.1 取消通知

typescript 复制代码
class NotificationControl {
  // 取消指定通知
  async cancelNotification(id: number) {
    try {
      await notificationManager.cancel(id);
      console.info(`通知${id}已取消`);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`取消失败: ${error.message}`);
    }
  }

  // 取消所有通知
  async cancelAllNotifications() {
    try {
      await notificationManager.cancelAll();
      console.info('所有通知已清除');
    } catch (err) {
      let error = err as BusinessError;
      console.error(`清除失败: ${error.message}`);
    }
  }

  // 查询活跃通知
  async getActiveNotifications() {
    try {
      let notifications = await notificationManager.getActiveNotifications();
      console.info(`当前有${notifications.length}条活跃通知`);
      return notifications;
    } catch (err) {
      let error = err as BusinessError;
      console.error(`查询失败: ${error.message}`);
      return [];
    }
  }
}

七、实战示例:消息通知管理器

7.1 完整通知管理器

typescript 复制代码
import { notificationManager } from '@kit.NotificationKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

export enum NotificationType {
  MESSAGE = 'message',
  SYSTEM = 'system',
  PROGRESS = 'progress'
}

export interface NotificationConfig {
  id: number;
  type: NotificationType;
  title: string;
  content: string;
  badgeNumber?: number;
}

export class NotificationManager {
  private static instance: NotificationManager;
  private isAuthorized: boolean = false;

  private constructor() {}

  static getInstance(): NotificationManager {
    if (!NotificationManager.instance) {
      NotificationManager.instance = new NotificationManager();
    }
    return NotificationManager.instance;
  }

  // 初始化并请求授权
  async init(context: common.UIAbilityContext): Promise<boolean> {
    try {
      this.isAuthorized = await notificationManager.isNotificationEnabled();

      if (!this.isAuthorized) {
        await notificationManager.requestEnableNotification(context);
        this.isAuthorized = true;
      }
      return this.isAuthorized;
    } catch (err) {
      let error = err as BusinessError;
      console.error(`初始化失败: ${error.message}`);
      return false;
    }
  }

  // 发布普通通知
  async publishNotification(config: NotificationConfig) {
    if (!this.isAuthorized) {
      console.error('未获得通知授权');
      return;
    }

    let notificationRequest: notificationManager.NotificationRequest = {
      id: config.id,
      content: {
        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
        normal: {
          title: config.title,
          text: config.content
        }
      }
    };

    if (config.badgeNumber !== undefined) {
      notificationRequest.badgeNumber = config.badgeNumber;
    }

    try {
      await notificationManager.publish(notificationRequest);
      console.info(`通知${config.id}发布成功`);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`发布失败: ${error.message}`);
    }
  }

  // 发布可点击通知
  async publishClickableNotification(
    config: NotificationConfig,
    context: common.UIAbilityContext,
    targetAbility: string
  ) {
    try {
      // 创建WantAgent
      let wantAgentInfo: wantAgent.WantAgentInfo = {
        wants: [
          {
            bundleName: context.abilityInfo.bundleName,
            abilityName: targetAbility
          }
        ],
        requestCode: 0,
        operationType: wantAgent.OperationType.START_ABILITY,
        wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
      };

      let wantAgentObj = await wantAgent.getWantAgent(wantAgentInfo);

      let notificationRequest: notificationManager.NotificationRequest = {
        id: config.id,
        content: {
          notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
          normal: {
            title: config.title,
            text: config.content
          }
        },
        wantAgent: wantAgentObj
      };

      await notificationManager.publish(notificationRequest);
      console.info('可点击通知发布成功');
    } catch (err) {
      let error = err as BusinessError;
      console.error(`发布失败: ${error.message}`);
    }
  }

  // 更新通知
  async updateNotification(config: NotificationConfig) {
    // 更新通知只需使用相同ID重新发布
    await this.publishNotification(config);
  }

  // 取消通知
  async cancelNotification(id: number) {
    try {
      await notificationManager.cancel(id);
    } catch (err) {
      let error = err as BusinessError;
      console.error(`取消失败: ${error.message}`);
    }
  }

  // 清除所有通知
  async cancelAll() {
    try {
      await notificationManager.cancelAll();
    } catch (err) {
      let error = err as BusinessError;
      console.error(`清除失败: ${error.message}`);
    }
  }

  // 获取活跃通知数量
  async getActiveCount(): Promise<number> {
    try {
      let notifications = await notificationManager.getActiveNotifications();
      return notifications.length;
    } catch (err) {
      return 0;
    }
  }
}

7.2 使用示例页面

typescript 复制代码
import { NotificationManager, NotificationType } from '../model/NotificationManager';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct NotificationDemo {
  private notificationMgr: NotificationManager = NotificationManager.getInstance();
  private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
  @State messageCount: number = 0;
  @State activeNotifications: number = 0;

  async aboutToAppear() {
    await this.notificationMgr.init(this.context);
    this.updateActiveCount();
  }

  async updateActiveCount() {
    this.activeNotifications = await this.notificationMgr.getActiveCount();
  }

  async sendTextNotification() {
    this.messageCount++;
    await this.notificationMgr.publishNotification({
      id: 1,
      type: NotificationType.MESSAGE,
      title: '新消息',
      content: `您有${this.messageCount}条新消息`,
      badgeNumber: this.messageCount
    });
    this.updateActiveCount();
  }

  async sendClickableNotification() {
    await this.notificationMgr.publishClickableNotification(
      {
        id: 2,
        type: NotificationType.SYSTEM,
        title: '系统通知',
        content: '点击查看详情'
      },
      this.context,
      'EntryAbility'
    );
    this.updateActiveCount();
  }

  async clearNotifications() {
    await this.notificationMgr.cancelAll();
    this.messageCount = 0;
    this.activeNotifications = 0;
  }

  build() {
    Column({ space: 20 }) {
      // 标题
      Text('通知服务演示')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      // 状态显示
      Row({ space: 20 }) {
        Text(`未读消息: ${this.messageCount}`)
          .fontSize(16)
        Text(`活跃通知: ${this.activeNotifications}`)
          .fontSize(16)
      }
      .padding(15)
      .backgroundColor('#f0f0f0')
      .borderRadius(8)
      .width('90%')

      // 操作按钮
      Column({ space: 15 }) {
        Button('发送文本通知')
          .width('100%')
          .onClick(() => this.sendTextNotification())

        Button('发送可点击通知')
          .width('100%')
          .onClick(() => this.sendClickableNotification())

        Button('发送多行通知')
          .width('100%')
          .onClick(async () => {
            let notificationRequest: notificationManager.NotificationRequest = {
              id: 3,
              content: {
                notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,
                multiLine: {
                  title: '待办事项',
                  text: '今日待办',
                  lines: [
                    '完成项目文档',
                    '参加团队会议',
                    '代码review'
                  ]
                }
              }
            };
            await notificationManager.publish(notificationRequest);
            this.updateActiveCount();
          })

        Button('清除所有通知')
          .width('100%')
          .backgroundColor('#ff6b6b')
          .onClick(() => this.clearNotifications())
      }
      .width('90%')
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

八、最佳实践

8.1 通知频率控制

typescript 复制代码
class NotificationRateLimiter {
  private lastPublishTime: number = 0;
  private minInterval: number = 1000; // 最小间隔1秒

  async publishWithLimit(request: notificationManager.NotificationRequest) {
    let now = Date.now();
    if (now - this.lastPublishTime < this.minInterval) {
      console.warn('发布频率过高,请稍后再试');
      return false;
    }

    try {
      await notificationManager.publish(request);
      this.lastPublishTime = now;
      return true;
    } catch (err) {
      return false;
    }
  }
}

8.2 通知分组管理

typescript 复制代码
class NotificationGroup {
  private groupedNotifications: Map<string, number[]> = new Map();

  async publishToGroup(group: string, request: notificationManager.NotificationRequest) {
    await notificationManager.publish(request);

    if (!this.groupedNotifications.has(group)) {
      this.groupedNotifications.set(group, []);
    }
    this.groupedNotifications.get(group)?.push(request.id);
  }

  async cancelGroup(group: string) {
    let ids = this.groupedNotifications.get(group);
    if (ids) {
      for (let id of ids) {
        await notificationManager.cancel(id);
      }
      this.groupedNotifications.delete(group);
    }
  }
}

8.3 错误处理

typescript 复制代码
class RobustNotification {
  async publishWithRetry(
    request: notificationManager.NotificationRequest,
    maxRetries: number = 3
  ): Promise<boolean> {
    for (let i = 0; i < maxRetries; i++) {
      try {
        await notificationManager.publish(request);
        return true;
      } catch (err) {
        let error = err as BusinessError;
        console.error(`第${i + 1}次发布失败: ${error.message}`);

        if (i < maxRetries - 1) {
          await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        }
      }
    }
    return false;
  }
}

九、总结

本文介绍了HarmonyOS通知服务开发的核心内容:

功能 API 使用场景
请求授权 requestEnableNotification 首次使用通知
文本通知 NOTIFICATION_CONTENT_BASIC_TEXT 普通消息提醒
多行通知 NOTIFICATION_CONTENT_MULTILINE 列表消息
进度通知 template配置 下载/上传进度
通知角标 badgeNumber 未读消息数
可点击通知 wantAgent 跳转到详情页

开发要点:

  1. ✅ 首次使用必须请求授权
  2. ✅ 控制通知发布频率
  3. ✅ 及时取消无用通知
  4. ✅ 合理使用通知ID管理
  5. ✅ 做好错误处理和重试

通过本文学习,您应该能够:

  • 熟练请求和管理通知授权
  • 发布各种类型的通知
  • 实现进度类通知
  • 管理通知角标
  • 开发完整的通知管理系统

参考资料

相关推荐
T___T2 小时前
全方位解释 JavaScript 执行机制(从底层到实战)
前端·面试
lcanfly2 小时前
Mysql作业5
android·数据库·mysql
阳懿2 小时前
meta-llama-3-8B下载失败解决。
前端·javascript·html
Qinana2 小时前
🌊 深入理解 CSS:从选择器到层叠的艺术
前端·css·程序员
IT_陈寒2 小时前
Python 3.12新特性实测:10个让你的代码提速30%的隐藏技巧 🚀
前端·人工智能·后端
闲人编程2 小时前
从零开发一个简单的Web爬虫(使用Requests和BeautifulSoup)
前端·爬虫·beautifulsoup·bs4·web·request·codecapsule
紫小米3 小时前
Vue 2 和 Vue 3 的区别
前端·javascript·vue.js
dllxhcjla3 小时前
三大特性+盒子模型
java·前端·css
Cache技术分享3 小时前
233. Java 集合 - 遍历 Collection 中的元素
前端·后端