公共事件与通知——实现HarmonyOS应用间通信
1 公共事件与通知机制概述
在HarmonyOS应用生态中,公共事件与通知机制是实现应用间通信和设备间协同的重要基础。公共事件机制允许应用订阅系统或其他应用发布的事件,实现后台的事件驱动通信;而通知机制则专注于向用户提供可视化的消息提醒和交互接口。
1.1 核心架构组件
HarmonyOS通过两大系统服务实现事件通信能力:
- CES(公共事件服务):提供事件的订阅、发布和退订能力,支持系统公共事件和自定义公共事件。
- ANS(高级通知服务):负责通知的发布、管理和显示,支持多种通知样式和交互操作。
1.2 通信模式对比
| 特性 | 公共事件 | 通知 |
|---|---|---|
| 通信模式 | 订阅/发布:单向、匿名的后台通信 | 点对点/系统托管:面向用户的交互 |
| 可见性 | 后台执行,用户无感知 | 状态栏、通知中心可见 |
| 主要目的 | 系统内部通信、状态同步 | 人机交互、信息提醒 |
| 参与者 | 发布者、订阅者(应用或系统服务) | 发布者(应用)、系统服务、用户 |
2 公共事件机制详解
2.1 公共事件类型
公共事件按来源分为两大类:
2.1.1 系统公共事件
系统预定义的事件,由系统服务在状态变化时发布,常见的有:
usual.event.SCREEN_OFF(屏幕关闭)usual.event.WIFI_CONNECTED(Wi-Fi已连接)common.event.DEVICE_OFFLINE(设备下线)common.event.PACKAGE_REMOVED(应用包被移除)
2.1.2 自定义公共事件
应用为处理特定业务逻辑而定义的事件,主要用于实现跨进程的事件通信能力。
2.2 公共事件的发送方式
公共事件按发送方式可分为三种类型:
2.2.1 无序公共事件
CES转发事件时不考虑订阅者接收顺序,不保证顺序一致性。
2.2.2 有序公共事件
根据订阅者优先级顺序传递,高优先级订阅者可修改事件内容或终止事件传递。
2.2.3 粘性公共事件
支持先发布后订阅,事件会持久化在系统中供后续订阅者接收。
2.3 公共事件核心API
公共事件相关的基础类构成了完整的事件处理体系:
- CommonEventData:封装公共事件相关信息
- CommonEventPublishInfo:设置事件发布属性(有序、粘性等)
- CommonEventSubscribeInfo:配置订阅者信息和优先级
- CommonEventSubscriber:处理事件接收回调
- CommonEventManager:提供订阅、发布、退订的静态接口
3 实战:公共事件的订阅与发布
3.1 订阅公共事件
以下是一个完整的公共事件订阅示例,演示如何监听网络变化事件:
import commonEventManager from '@ohos.commonEventManager';
import Base from '@ohos.base';
import hilog from '@ohos.hilog';
const TAG = 'CommonEventDemo';
const DOMAIN_NUMBER = 0xFF00;
// 用于保存订阅者对象
let subscriber: commonEventManager.CommonEventSubscriber | null = null;
// 订阅者信息配置
let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
events: ['usual.event.network.CONNECTIVITY_CHANGE'] // 订阅网络连接变化事件
};
// 创建订阅者
commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, data: commonEventManager.CommonEventSubscriber) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `创建订阅者失败: code=${err.code}, message=${err.message}`);
return;
}
hilog.info(DOMAIN_NUMBER, TAG, '成功创建订阅者');
subscriber = data;
// 订阅公共事件
subscribeToEvent();
});
// 执行订阅
function subscribeToEvent(): void {
if (subscriber === null) {
hilog.error(DOMAIN_NUMBER, TAG, '订阅者未创建');
return;
}
commonEventManager.subscribe(subscriber, (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `订阅失败: code=${err.code}, message=${err.message}`);
return;
}
hilog.info(DOMAIN_NUMBER, TAG, '接收到网络变化事件');
// 处理网络变化逻辑
handleNetworkChange(data);
});
}
// 处理网络变化事件
function handleNetworkChange(eventData: commonEventManager.CommonEventData): void {
// 在这里实现具体的业务逻辑
// 例如检查当前网络类型并更新应用状态
hilog.info(DOMAIN_NUMBER, TAG, '处理网络状态变化事件');
}
// 退订公共事件
function unsubscribeEvent(): void {
if (subscriber !== null) {
commonEventManager.unsubscribe(subscriber, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `退订失败: ${JSON.stringify(err)}`);
} else {
hilog.info(DOMAIN_NUMBER, TAG, '成功退订公共事件');
subscriber = null;
}
});
}
}
3.2 发布公共事件
以下示例演示如何发布自定义公共事件:
import commonEventManager from '@ohos.commonEventManager';
import Base from '@ohos.base';
import hilog from '@ohos.hilog';
const TAG = 'CommonEventDemo';
const DOMAIN_NUMBER = 0xFF00;
// 发布无序公共事件
function publishDisorderedEvent(eventName: string, eventData?: string): void {
let options: commonEventManager.CommonEventPublishData = {
code: 0,
data: eventData || '默认事件数据'
};
commonEventManager.publish(eventName, options, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `发布事件失败: ${JSON.stringify(err)}`);
} else {
hilog.info(DOMAIN_NUMBER, TAG, '成功发布无序公共事件');
}
});
}
// 发布有序公共事件(需要权限)
function publishOrderedEvent(eventName: string): void {
let options: commonEventManager.CommonEventPublishData = {
code: 1,
data: '有序事件数据',
bundleName: 'com.example.publisher' // 指定订阅者包名
};
commonEventManager.publish(eventName, options, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `发布有序事件失败: ${JSON.stringify(err)}`);
} else {
hilog.info(DOMAIN_NUMBER, TAG, '成功发布有序公共事件');
}
});
}
// 实际使用示例
publishDisorderedEvent('com.example.custom.EVENT_1', '自定义事件数据');
3.3 权限配置
发布某些类型的公共事件需要在module.json5中配置相应权限:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.COMMON_EVENT_STICKY",
"reason": "发布粘性事件所需权限",
"usedScene": {
"abilities": [".MainAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.INTERNET",
"reason": "网络访问权限",
"usedScene": {
"abilities": [".MainAbility"],
"when": "always"
}
}
]
}
}
4 通知机制详解
4.1 通知的基本结构
HarmonyOS通知支持多种样式,创建通知时必须包含一种样式:
- 普通文本样式:基本的标题和内容
- 长文本样式:支持多行文本内容
- 图片样式:包含图标或大图
- 社交样式:聊天类应用的通知
- 多行文本样式:支持段落式内容
- 媒体样式:音乐、视频播放控制
4.2 发布通知实战
以下是一个完整的通知发布示例:
import notificationManager from '@ohos.notificationManager';
import WantAgent, { WantAgentInfo, Want } from '@ohos.app.ability.wantAgent';
import Base from '@ohos.base';
import hilog from '@ohos.hilog';
const TAG = 'NotificationDemo';
const DOMAIN_NUMBER = 0xFF00;
// 请求通知权限
async function requestNotificationPermission(): Promise<void> {
try {
await notificationManager.requestEnableNotification();
hilog.info(DOMAIN_NUMBER, TAG, '通知权限已获取');
} catch (err) {
hilog.error(DOMAIN_NUMBER, TAG, `通知权限获取失败: ${JSON.stringify(err)}`);
}
}
// 创建WantAgent用于通知点击行为
async function createWantAgent(): Promise<WantAgent> {
let wantAgentInfo: WantAgentInfo = {
wants: [
{
bundleName: 'com.example.myapp',
abilityName: 'EntryAbility',
} as Want
],
operationType: WantAgent.OperationType.START_ABILITY,
requestCode: 0,
wantAgentFlags: [WantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
return WantAgent.getWantAgent(wantAgentInfo);
}
// 发布基础通知
async function publishBasicNotification(title: string, text: string): Promise<void> {
try {
let wantAgent = await createWantAgent();
let notificationRequest: notificationManager.NotificationRequest = {
id: 1,
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: title,
text: text,
additionalText: '附加文本'
}
},
// 快捷操作按钮
actionButtons: [
{
title: '打开',
wantAgent: wantAgent
},
{
title: '取消',
wantAgent: wantAgent
}
],
tapDismissed: true, // 点击后消失
autoDeleted: true, // 点击后自动删除
deliveryTime: new Date(), // 发送时间
notificationSlotType: notificationManager.SlotType.SOCIAL_COMMUNICATION
};
await notificationManager.publish(notificationRequest);
hilog.info(DOMAIN_NUMBER, TAG, '通知发布成功');
} catch (err) {
const error = err as Base.BusinessError;
hilog.error(DOMAIN_NUMBER, TAG, `通知发布失败: code=${error.code}, message=${error.message}`);
}
}
// 发布带有进度的通知
async function publishProgressNotification(title: string, progress: number, maxProgress: number): Promise<void> {
let notificationRequest: notificationManager.NotificationRequest = {
id: 2,
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: title,
text: `进度: ${progress}/${maxProgress}`,
additionalText: `${Math.round((progress / maxProgress) * 100)}%`
}
},
// 进度条设置
progressBar: {
value: progress,
total: maxProgress
}
};
try {
await notificationManager.publish(notificationRequest);
hilog.info(DOMAIN_NUMBER, TAG, '进度通知发布成功');
} catch (err) {
const error = err as Base.BusinessError;
hilog.error(DOMAIN_NUMBER, TAG, `进度通知发布失败: ${error.message}`);
}
}
// 使用示例
requestNotificationPermission();
publishBasicNotification('下载完成', '文件《HarmonyOS开发指南.pdf》已下载完毕');
5 跨应用通信实战案例
5.1 跨设备文件传输场景
以下示例展示了一个完整的跨设备文件传输场景,结合了公共事件和通知机制:
import commonEventManager from '@ohos.commonEventManager';
import notificationManager from '@ohos.notificationManager';
import Base from '@ohos.base';
import hilog from '@ohos.hilog';
const TAG = 'CrossAppCommunication';
const DOMAIN_NUMBER = 0xFF00;
// 自定义事件类型
const CUSTOM_EVENTS = {
FILE_INCOMING: 'com.example.filetransfer.FILE_INCOMING',
FILE_PROCESSED: 'com.example.filetransfer.FILE_PROCESSED'
};
// 在接收端设备上订阅文件到达事件
class FileReceiver {
private subscriber: commonEventManager.CommonEventSubscriber | null = null;
// 订阅文件到达事件
async subscribeToFileEvents(): Promise<void> {
let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
events: [CUSTOM_EVENTS.FILE_INCOMING]
};
commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, data: commonEventManager.CommonEventSubscriber) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `创建文件事件订阅者失败: ${err.message}`);
return;
}
this.subscriber = data;
this.setupEventSubscription();
});
}
private setupEventSubscription(): void {
if (this.subscriber === null) return;
commonEventManager.subscribe(this.subscriber, (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `文件事件订阅失败: ${err.message}`);
return;
}
this.handleIncomingFile(data);
});
}
// 处理接收到的文件
private async handleIncomingFile(eventData: commonEventManager.CommonEventData): Promise<void> {
const filePath = eventData.parameters?.['filePath'];
const fileName = eventData.parameters?.['fileName'];
hilog.info(DOMAIN_NUMBER, TAG, `接收到文件: ${fileName}, 路径: ${filePath}`);
// 处理文件(校验、移动等)
await this.processFile(filePath, fileName);
// 发布处理完成事件
this.notifyFileProcessed(fileName);
// 发送用户通知
await this.showFileReceivedNotification(fileName);
}
private async processFile(filePath: string, fileName: string): Promise<void> {
// 文件处理逻辑
hilog.info(DOMAIN_NUMBER, TAG, `处理文件: ${fileName}`);
// 实际实现中可能包含文件校验、移动等操作
}
private async notifyFileProcessed(fileName: string): Promise<void> {
let options: commonEventManager.CommonEventPublishData = {
code: 0,
data: `文件${fileName}处理完成`,
parameters: {
fileName: fileName,
processedAt: new Date().toISOString()
}
};
commonEventManager.publish(CUSTOM_EVENTS.FILE_PROCESSED, options, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `发布文件处理事件失败: ${err.message}`);
}
});
}
private async showFileReceivedNotification(fileName: string): Promise<void> {
let notificationRequest: notificationManager.NotificationRequest = {
id: Date.now(), // 使用时间戳作为ID确保唯一性
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '文件传输完成',
text: `文件"${fileName}"已接收并保存至下载文件夹`,
additionalText: '刚刚'
}
},
deliveryTime: new Date()
};
try {
await notificationManager.publish(notificationRequest);
hilog.info(DOMAIN_NUMBER, TAG, '文件接收通知发送成功');
} catch (err) {
const error = err as Base.BusinessError;
hilog.error(DOMAIN_NUMBER, TAG, `通知发送失败: ${error.message}`);
}
}
// 清理资源
cleanup(): void {
if (this.subscriber !== null) {
commonEventManager.unsubscribe(this.subscriber, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `退订文件事件失败: ${err.message}`);
}
});
this.subscriber = null;
}
}
}
// 在发送端设备上发布文件传输事件
class FileSender {
// 发送文件传输事件
async sendFile(filePath: string, fileName: string, targetDevice: string): Promise<void> {
let options: commonEventManager.CommonEventPublishData = {
code: 0,
data: '文件传输事件',
parameters: {
filePath: filePath,
fileName: fileName,
sourceDevice: '发送设备ID',
targetDevice: targetDevice,
timestamp: new Date().toISOString()
},
bundleName: 'com.example.filetransfer' // 指定接收方包名
};
commonEventManager.publish(CUSTOM_EVENTS.FILE_INCOMING, options, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `发布文件传输事件失败: ${err.message}`);
this.showErrorNotification('文件发送失败');
} else {
hilog.info(DOMAIN_NUMBER, TAG, '文件传输事件发布成功');
this.showSuccessNotification(fileName);
}
});
}
private async showSuccessNotification(fileName: string): Promise<void> {
let notificationRequest: notificationManager.NotificationRequest = {
id: Date.now(),
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '文件发送成功',
text: `文件"${fileName}"已开始传输`,
additionalText: '发送中'
}
}
};
await notificationManager.publish(notificationRequest);
}
private async showErrorNotification(errorMessage: string): Promise<void> {
let notificationRequest: notificationManager.NotificationRequest = {
id: Date.now(),
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '传输错误',
text: errorMessage,
additionalText: '错误'
}
}
};
await notificationManager.publish(notificationRequest);
}
}
// 使用示例
const fileReceiver = new FileReceiver();
await fileReceiver.subscribeToFileEvents();
const fileSender = new FileSender();
await fileSender.sendFile('/path/to/file.pdf', 'document.pdf', '目标设备ID');
6 安全机制与最佳实践
6.1 权限控制与安全措施
在实现跨应用通信时,必须重视安全性:
// 安全配置示例
class SecureEventManager {
private allowedEvents: Set<string>;
private allowedPublishers: Set<string>;
constructor() {
this.allowedEvents = new Set(['safe.event.1', 'safe.event.2']);
this.allowedPublishers = new Set(['trusted.publisher.1', 'trusted.publisher.2']);
}
// 验证事件发布权限
private validateEventPublishing(eventName: string, publisherId: string): boolean {
if (!this.allowedEvents.has(eventName)) {
hilog.error(DOMAIN_NUMBER, TAG, `事件类型不被允许: ${eventName}`);
return false;
}
if (!this.allowedPublishers.has(publisherId)) {
hilog.error(DOMAIN_NUMBER, TAG, `发布者未经授权: ${publisherId}`);
return false;
}
return true;
}
// 安全的发布方法
async publishSecureEvent(eventName: string, data: any, publisherId: string): Promise<boolean> {
if (!this.validateEventPublishing(eventName, publisherId)) {
return false;
}
// 数据加密处理
const encryptedData = this.encryptData(data);
let options: commonEventManager.CommonEventPublishData = {
code: 0,
data: encryptedData
};
return new Promise((resolve) => {
commonEventManager.publish(eventName, options, (err: Base.BusinessError) => {
if (err) {
hilog.error(DOMAIN_NUMBER, TAG, `安全事件发布失败: ${err.message}`);
resolve(false);
} else {
hilog.info(DOMAIN_NUMBER, TAG, '安全事件发布成功');
resolve(true);
}
});
});
}
// 数据加密(示例)
private encryptData(data: any): string {
// 实际实现应使用鸿OS安全加密API
return JSON.stringify(data); // 示例中仅作序列化
}
}
6.2 性能优化建议
- 及时退订:在组件销毁时退订事件
- 事件去重:避免重复处理相同事件
- 异步处理:耗时操作使用goAsyncCommonEvent()
- 内存管理:避免事件回调中的内存泄漏
// 优化示例
class OptimizedEventSubscriber {
private subscriber: commonEventManager.CommonEventSubscriber | null = null;
private isSubscribed: boolean = false;
// 带错误重试的订阅
async subscribeWithRetry(eventName: string, maxRetries: number = 3): Promise<void> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await this.subscribeToEvent(eventName);
return;
} catch (err) {
hilog.warn(DOMAIN_NUMBER, TAG, `订阅失败,第${attempt}次重试`);
if (attempt === maxRetries) {
throw err;
}
await this.delay(1000 * attempt); // 指数退避
}
}
}
// 异步事件处理
private async handleEventAsync(eventData: commonEventManager.CommonEventData): Promise<void> {
const result = this.subscriber?.goAsyncCommonEvent();
try {
// 执行耗时操作
await this.processEventData(eventData);
result?.finishCommonEvent();
} catch (err) {
hilog.error(DOMAIN_NUMBER, TAG, `事件处理失败: ${err.message}`);
result?.finishCommonEvent();
}
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
7 总结
公共事件与通知机制是HarmonyOS应用间通信的核心技术,通过本文的详细讲解和实战示例,您应该掌握:
- 公共事件机制的理解和运用,包括系统事件和自定义事件
- 通知系统的完整使用流程,从权限申请到各种样式通知的发布
- 跨应用通信的安全实现方案,包括权限控制和数据验证
- 实战场景的应用能力,能够解决实际开发中的通信需求
这些技术为构建分布式、协同式的HarmonyOS应用生态奠定了坚实基础,是高级应用开发必备的核心技能。
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号