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 性能优化建议
- 合理使用公共事件:避免频繁发布不必要的事件,减少系统负担
- 及时退订事件:在不需要时及时退订公共事件,避免内存泄漏
- 优化通知频率:避免过于频繁的通知,影响用户体验
- 使用适当的重要级别:根据通知内容的重要性选择合适的通知级别
- 处理权限拒绝:优雅处理用户拒绝通知权限的情况
八、总结与最佳实践
8.1 核心要点回顾
- 公共事件机制:实现应用间后台通信,支持系统事件和自定义事件
- 通知机制:向用户提供可视化的消息提醒,支持多种样式和交互
- 跨设备协同:通过公共事件实现设备间的数据同步和状态感知
- 权限管理:合理申请和使用所需权限,确保应用正常运行
8.2 最佳实践
- 场景选择: 需要后台通信时使用公共事件 需要用户交互时使用通知 需要跨设备协同时结合使用两者
- 权限申请: 在
module.json5中声明所需权限 运行时动态请求用户授权 优雅处理权限拒绝的情况 - 性能优化: 避免频繁发布事件和通知 及时清理不再需要的订阅和通知 使用适当的事件类型和通知级别
- 用户体验: 提供清晰的通知内容 支持通知操作按钮 合理控制通知频率
通过合理运用公共事件与通知机制,可以构建出响应迅速、体验流畅的HarmonyOS应用,实现真正的跨设备协同体验。

浙公网安备 33010602011771号