news 2026/6/10 12:23:38

Harmony开发之公共事件与通知——应用间的沟通桥梁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Harmony开发之公共事件与通知——应用间的沟通桥梁

Harmony开发之公共事件与通知——应用间的沟通桥梁

引入:跨应用协同的魔法

在日常使用手机时,我们经常会遇到这样的场景:当Wi-Fi连接成功后,多个应用会同时弹出"网络已连接"的提示;当收到新消息时,即使应用在后台运行,也能在通知栏看到提醒。这些看似简单的功能背后,正是HarmonyOS公共事件与通知机制在发挥作用。它们如同应用间的"神经系统",让不同的应用能够感知系统状态变化,实现跨应用的协同工作。

一、公共事件与通知机制概述

1.1 核心概念

**公共事件(Common Event)**是HarmonyOS提供的应用间通信机制,允许应用订阅系统或其他应用发布的事件,实现后台的事件驱动通信。公共事件服务(CES)负责事件的订阅、发布和退订管理。

**通知(Notification)**是应用向用户传递信息的主要方式,通过通知增强服务(ANS)系统服务来为应用程序提供发布通知的能力。通知会在状态栏、通知中心等位置显示给用户,支持多种样式和交互操作。

1.2 通信模式对比

特性公共事件通知
通信模式订阅/发布:单向、匿名的后台通信点对点/系统托管:面向用户的交互
可见性后台执行,用户无感知状态栏、通知中心可见
主要目的系统内部通信、状态同步人机交互、信息提醒
参与者发布者、订阅者(应用或系统服务)发布者(应用)、系统服务、用户

二、公共事件开发详解

2.1 公共事件类型

系统公共事件

系统预定义的事件,由系统服务在状态变化时发布,常见的有:

  • usual.event.SCREEN_OFF(屏幕关闭)
  • usual.event.WIFI_CONNECTED(Wi-Fi已连接)
  • common.event.DEVICE_OFFLINE(设备下线)
  • common.event.PACKAGE_REMOVED(应用包被移除)
自定义公共事件

应用为处理特定业务逻辑而定义的事件,主要用于实现跨进程的事件通信能力。

2.2 公共事件发送方式

无序公共事件

CES转发事件时不考虑订阅者接收顺序,不保证顺序一致性。

有序公共事件

根据订阅者优先级顺序传递,高优先级订阅者可修改事件内容或终止事件传递。

粘性公共事件

支持先发布后订阅,事件会持久化在系统中供后续订阅者接收。

2.3 核心接口类

公共事件相关基础类包含:

  • CommonEventData:封装公共事件相关信息
  • CommonEventPublishInfo:封装公共事件发布相关属性
  • CommonEventSubscribeInfo:封装公共事件订阅相关信息
  • CommonEventSubscriber:封装公共事件订阅者及相关参数
  • CommonEventManager:提供订阅、退订和发布公共事件的静态接口

三、公共事件实战开发

3.1 订阅公共事件

import commonEvent from '@ohos.commonEventManager'; import { BusinessError } from '@ohos.BasicServicesKit'; // 订阅网络连接变化事件 async function subscribeNetworkEvent(): Promise<void> { try { const subscribeInfo = { events: ["usual.event.network.CONNECTIVITY_CHANGE"] }; const subscriber = await commonEvent.createSubscriber(subscribeInfo); commonEvent.subscribe(subscriber, (err: BusinessError, data: commonEvent.CommonEventData) => { if (err) { console.error(`订阅失败: ${err.code}, ${err.message}`); return; } console.info('收到网络变化事件'); // 处理网络状态变化逻辑 this.handleNetworkChange(); }); } catch (error) { console.error('创建订阅者失败:', error); } }

3.2 发布自定义公共事件

import commonEvent from '@ohos.commonEventManager'; import { BusinessError } from '@ohos.BasicServicesKit'; // 发布自定义公共事件 async function publishCustomEvent(): Promise<void> { try { const options: commonEvent.CommonEventPublishData = { code: 1, data: "自定义事件数据" }; await commonEvent.publish("com.example.MY_CUSTOM_EVENT", options); console.info('自定义事件发布成功'); } catch (error) { console.error('发布事件失败:', error); } } // 发布带权限的公共事件 async function publishPermissionEvent(): Promise<void> { try { const options: commonEvent.CommonEventPublishData = { code: 1, data: "带权限的事件数据", subscriberPermissions: ["com.example.permission.MY_PERMISSION"] }; await commonEvent.publish("com.example.PERMISSION_EVENT", options); console.info('带权限事件发布成功'); } catch (error) { console.error('发布带权限事件失败:', error); } }

3.3 发布有序公共事件

import commonEvent from '@ohos.commonEventManager'; import { BusinessError } from '@ohos.BasicServicesKit'; // 发布有序公共事件 async function publishOrderedEvent(): Promise<void> { try { const options: commonEvent.CommonEventPublishData = { code: 1, data: "有序事件数据", isOrdered: true }; await commonEvent.publish("com.example.ORDERED_EVENT", options); console.info('有序事件发布成功'); } catch (error) { console.error('发布有序事件失败:', error); } }

3.4 发布粘性公共事件

import commonEvent from '@ohos.commonEventManager'; import { BusinessError } from '@ohos.BasicServicesKit'; // 发布粘性公共事件 async function publishStickyEvent(): Promise<void> { try { const options: commonEvent.CommonEventPublishData = { code: 1, data: "粘性事件数据", isSticky: true }; await commonEvent.publish("com.example.STICKY_EVENT", options); console.info('粘性事件发布成功'); } catch (error) { console.error('发布粘性事件失败:', error); } }

3.5 权限配置

module.json5中配置所需权限:

{ "module": { "reqPermissions": [ { "name": "ohos.permission.COMMONEVENT_STICKY", "reason": "发布粘性公共事件", "usedScene": { "ability": [".MainAbility"], "when": "inuse" } }, { "name": "com.example.permission.MY_PERMISSION", "reason": "自定义权限", "usedScene": { "ability": [".MainAbility"], "when": "inuse" } } ] } }

四、通知开发详解

4.1 通知类型

HarmonyOS支持六种通知样式:

  • 普通文本(NOTIFICATION_CONTENT_BASIC_TEXT)
  • 长文本(NOTIFICATION_CONTENT_LONG_TEXT)
  • 图片(NOTIFICATION_CONTENT_PICTURE)
  • 社交(NOTIFICATION_CONVERSATIONAL_CONTENT)
  • 多行文本(NOTIFICATION_MULTILINE_CONTENT)
  • 媒体(NOTIFICATION_MEDIA_CONTENT)

4.2 通知重要级别

NotificationSlot的级别支持:

  • LEVEL_NONE:通知不发布
  • LEVEL_MIN:通知可以发布,但不显示在通知栏
  • LEVEL_LOW:通知显示在通知栏,不自动弹出
  • LEVEL_DEFAULT:通知显示在通知栏,触发提示音
  • LEVEL_HIGH:通知显示在通知栏,自动弹出,触发提示音

4.3 核心接口类

通知相关基础类包含:

  • NotificationSlot:设置提示音、振动、锁屏显示和重要级别
  • NotificationRequest:设置具体的通知对象
  • NotificationHelper:封装发布、更新、删除通知等静态方法

五、通知实战开发

5.1 创建通知渠道

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 创建通知渠道 async function createNotificationSlot(): Promise<void> { try { const slot = { id: "slot_001", name: "默认通知渠道", level: notificationManager.SlotLevel.LEVEL_DEFAULT, enableVibration: true, lockscreenVisibleness: notificationManager.VisibilityType.VISIBILITY_TYPE_PUBLIC, enableLight: true, ledLightColor: Color.RED }; await notificationManager.addSlot(slot); console.info('通知渠道创建成功'); } catch (error) { console.error('创建通知渠道失败:', error); } }

5.2 发布普通文本通知

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 发布普通文本通知 async function publishTextNotification(): Promise<void> { try { const notificationRequest: notificationManager.NotificationRequest = { id: 1, slotId: "slot_001", content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: "通知标题", text: "这是通知内容", additionalText: "附加信息" } }, badgeNumber: 1, autoDeletedTime: Date.now() + 3000 // 3秒后自动删除 }; await notificationManager.publish(notificationRequest); console.info('文本通知发布成功'); } catch (error) { console.error('发布通知失败:', error); } }

5.3 发布图片通知

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { image } from '@kit.ImageKit'; // 发布图片通知 async function publishImageNotification(): Promise<void> { try { // 获取图片资源 const resourceManager = getContext().resourceManager; const imageArray = await resourceManager.getMediaContent($r('app.media.notification_icon').id); const imageResource = image.createImageSource(imageArray.buffer); const imagePixelMap = await imageResource.createPixelMap(); const notificationRequest: notificationManager.NotificationRequest = { id: 2, slotId: "slot_001", largeIcon: imagePixelMap, content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_PICTURE, picture: { title: "图片通知", text: "这是一张图片通知", bigPicture: imagePixelMap } } }; await notificationManager.publish(notificationRequest); console.info('图片通知发布成功'); } catch (error) { console.error('发布图片通知失败:', error); } }

5.4 发布进度条通知

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { request } from '@kit.NetworkKit'; // 发布进度条通知 async function publishProgressNotification(): Promise<void> { try { const notificationRequest: notificationManager.NotificationRequest = { id: 3, slotId: "slot_001", content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: "文件下载", text: "正在下载文件..." } }, template: { name: 'downloadTemplate', data: { title: 'PDF文件下载', fileName: 'test.pdf', progressValue: 0 } } }; // 发布初始通知 await notificationManager.publish(notificationRequest); // 模拟下载进度更新 let progress = 0; const interval = setInterval(async () => { progress += 10; if (progress > 100) { clearInterval(interval); return; } // 更新通知 notificationRequest.template!.data!.progressValue = progress; notificationRequest.template!.data!.fileName = `test.pdf 下载进度: ${progress}%`; await notificationManager.publish(notificationRequest); }, 1000); } catch (error) { console.error('发布进度通知失败:', error); } }

5.5 带操作按钮的通知

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { WantAgent } from '@kit.AbilityKit'; // 发布带操作按钮的通知 async function publishActionNotification(): Promise<void> { try { // 创建WantAgent(点击通知后要触发的意图) const wantAgentInfo: WantAgent.WantAgentInfo = { wants: [ { bundleName: 'com.example.myapp', abilityName: 'MainAbility' } ], actionType: WantAgent.OperationType.START_ABILITIES, requestCode: 0 }; const wantAgent = await WantAgent.getWantAgent(wantAgentInfo); const notificationRequest: notificationManager.NotificationRequest = { id: 4, slotId: "slot_001", content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: "带操作的通知", text: "点击查看详情或执行操作" } }, wantAgent: wantAgent, actionButtons: [ { title: '打开应用', wantAgent: wantAgent }, { title: '取消', wantAgent: { wants: [ { action: 'com.example.CANCEL_ACTION' } ], actionType: WantAgent.OperationType.SEND_COMMON_EVENT } } ] }; await notificationManager.publish(notificationRequest); console.info('带操作按钮的通知发布成功'); } catch (error) { console.error('发布带操作通知失败:', error); } }

5.6 取消通知

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 取消指定通知 async function cancelNotification(): Promise<void> { try { await notificationManager.cancelNotification(1); console.info('通知取消成功'); } catch (error) { console.error('取消通知失败:', error); } } // 取消所有通知 async function cancelAllNotifications(): Promise<void> { try { await notificationManager.cancelAllNotifications(); console.info('所有通知取消成功'); } catch (error) { console.error('取消所有通知失败:', error); } }

5.7 权限申请

在发布通知前,需要申请通知权限:

import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 请求通知权限 async function requestNotificationPermission(): Promise<void> { try { await notificationManager.requestEnableNotification(); console.info('通知权限申请成功'); } catch (error) { if (error.code === 1600004) { console.info('用户拒绝了通知权限'); } else { console.error('请求通知权限失败:', error); } } }

六、综合实战:跨设备文件传输

6.1 场景描述

用户在手机上启动文件发送操作,将大文件发送到同一账号下的平板电脑。平板上的文件传输应用在后台订阅自定义公共事件,当文件传输完成后,手机应用发布公共事件,平板应用接收事件并处理文件,最后通过通知告知用户。

6.2 代码实现

手机端(发送方)
import commonEvent from '@ohos.commonEventManager'; import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 文件传输完成后发布公共事件 async function publishFileTransferComplete(filePath: string): Promise<void> { try { const options: commonEvent.CommonEventPublishData = { code: 200, data: JSON.stringify({ filePath: filePath, fileName: "test.pdf", fileSize: "10MB", transferTime: new Date().toISOString() }), isOrdered: true }; await commonEvent.publish("com.example.FILE_TRANSFER_COMPLETE", options); console.info('文件传输完成事件发布成功'); // 发送本地通知 await publishTransferCompleteNotification(); } catch (error) { console.error('发布文件传输事件失败:', error); } } // 发布传输完成通知 async function publishTransferCompleteNotification(): Promise<void> { try { const notificationRequest: notificationManager.NotificationRequest = { id: 1001, slotId: "slot_transfer", content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: "文件传输完成", text: "文件已成功发送到平板设备" } } }; await notificationManager.publish(notificationRequest); } catch (error) { console.error('发布通知失败:', error); } }
平板端(接收方)
import commonEvent from '@ohos.commonEventManager'; import { notificationManager } from '@kit.NotificationKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 订阅文件传输完成事件 async function subscribeFileTransferEvent(): Promise<void> { try { const subscribeInfo = { events: ["com.example.FILE_TRANSFER_COMPLETE"] }; const subscriber = await commonEvent.createSubscriber(subscribeInfo); commonEvent.subscribe(subscriber, async (err: BusinessError, data: commonEvent.CommonEventData) => { if (err) { console.error(`订阅失败: ${err.code}, ${err.message}`); return; } // 解析事件数据 const eventData = JSON.parse(data.data as string); console.info('收到文件传输完成事件:', eventData); // 处理文件 await handleFileTransfer(eventData); }); } catch (error) { console.error('创建订阅者失败:', error); } } // 处理文件传输 async function handleFileTransfer(eventData: any): Promise<void> { try { // 模拟文件处理逻辑 console.info(`开始处理文件: ${eventData.fileName}`); // 模拟文件处理耗时 await new Promise(resolve => setTimeout(resolve, 2000)); console.info('文件处理完成'); // 发送处理完成通知 await publishFileProcessedNotification(eventData.fileName); } catch (error) { console.error('处理文件失败:', error); } } // 发布文件处理完成通知 async function publishFileProcessedNotification(fileName: string): Promise<void> { try { const notificationRequest: notificationManager.NotificationRequest = { id: 2001, slotId: "slot_transfer", content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: "文件接收完成", text: `${fileName} 已保存至下载文件夹` } } }; await notificationManager.publish(notificationRequest); console.info('文件处理完成通知发布成功'); } catch (error) { console.error('发布通知失败:', error); } }

七、调试与优化

7.1 调试工具

HarmonyOS提供了调试助手工具,帮助开发者调试公共事件和通知:

  • CEM调试助手:用于调试公共事件
  • ANM调试助手:用于调试通知

7.2 性能优化建议

  1. 合理使用公共事件:避免频繁发布不必要的事件,减少系统负担
  2. 及时退订事件:在不需要时及时退订公共事件,避免内存泄漏
  3. 优化通知频率:避免过于频繁的通知,影响用户体验
  4. 使用适当的重要级别:根据通知内容的重要性选择合适的通知级别
  5. 处理权限拒绝:优雅处理用户拒绝通知权限的情况

八、总结与最佳实践

8.1 核心要点回顾

  1. 公共事件机制:实现应用间后台通信,支持系统事件和自定义事件
  2. 通知机制:向用户提供可视化的消息提醒,支持多种样式和交互
  3. 跨设备协同:通过公共事件实现设备间的数据同步和状态感知
  4. 权限管理:合理申请和使用所需权限,确保应用正常运行

8.2 最佳实践

  1. 场景选择: 需要后台通信时使用公共事件 需要用户交互时使用通知 需要跨设备协同时结合使用两者
  2. 权限申请: 在module.json5中声明所需权限 运行时动态请求用户授权 优雅处理权限拒绝的情况
  3. 性能优化: 避免频繁发布事件和通知 及时清理不再需要的订阅和通知 使用适当的事件类型和通知级别
  4. 用户体验: 提供清晰的通知内容 支持通知操作按钮 合理控制通知频率

通过合理运用公共事件与通知机制,可以构建出响应迅速、体验流畅的HarmonyOS应用,实现真正的跨设备协同体验。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!