积分582 / 贡献0

提问0答案被采纳0文章52

[经验分享] OpenHarmony公共事件基本原理解 原创

Laval社区小助手 显示全部楼层 发表于 2024-1-8 11:25:01

简介

OpenHarmony通过CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力。

公共事件根据发送方不同可分为系统公共事件和自定义公共事件。

  • 系统公共事件:系统将收集到的事件信息,根据系统策略发送给订阅该事件的用户程序。 例如:系统关键服务发布的系统事件(例如:hap安装,更新,卸载等)。
  • 自定义公共事件:应用自定义一些公共事件用来实现跨应用的事件通信能力。

每个应用都可以按需订阅公共事件,订阅成功且公共事件发布,系统会把其发送给应用。这些公共事件可能来自系统、其他应用和应用自身。

commonEvent接口的方法如下:

名词解释

订阅者信息(CommonEventSubscribeInfo)

用于设置订阅的一些基本信息,在创建订阅者时使用。

名称 读写属性 类型 必填 描述
events 只读 Array<string> 表示订阅的公共事件,一个订阅者可以订阅多个公共事件。
publisherPermission 只读 string 表示发布者的权限。发布者必须具有该权限才可以发布公共事件给该订阅者,该订阅者只接收具有该权限的发布者发布的公共事件。
publisherDeviceId 只读 string 表示设备ID,该值必须是同一ohos网络上的现有设备ID。
userId 只读 number 表示用户ID。此参数是可选的,默认值当前用户的ID。如果指定了此参数,则该值必须是系统中现有的用户ID。
priority 只读 number 表示订阅者的优先级,值的范围是-100到1000。数值越大,订阅者的优先级别越高,在有序公共事件发布时越先接收到发布信息。

写法示例:

let subscribeInfo: any = {
    events: ["event1","event2"],
    userId: 100,
    priority: 200,
    ...
}

订阅者(Subscriber)

用于作为订阅公共事件的载体,订阅公共事件并获取公共事件传递而来的参数。详细信息请参考CommonEvent文档/CommonEventSubscriber

方法名称 描述
getCode 获取公共事件的结果代码
setCode 设置公共事件的结果代码
getData 获取公共事件的结果数据
setData 设置公共事件的结果数据
setCodeAndData 设置公共事件的结果代码和结果数据
isOrderedCommonEvent 查询当前公共事件的是否为有序公共事件
isStickyCommonEvent 检查当前公共事件是否为一个粘性事件
abortCommonEvent 取消当前的公共事件,仅对有序公共事件有效,取消后,公共事件不再向下一个订阅者传递
clearAbortCommonEvent 清除当前公共事件的取消状态,仅对有序公共事件有效
getAbortCommonEvent 获取当前有序公共事件是否取消的状态
getSubscribeInfo 获取订阅者的订阅信息
finishCommonEvent 结束当前有序公共事件

公共事件数据(CommonEventData)

通过订阅者成功订阅公共事件之后,返回的订阅的公共事件的一些基本信息。

名称 读写属性 类型 必填 描述
event 只读 string 表示当前接收的公共事件名称。
bundleName 只读 string 表示包名称。
code 只读 number 表示公共事件的结果代码,用于传递int类型的数据,默认为0。
data 只读 string 表示公共事件的自定义结果数据,用于传递string类型的数据。
parameters 只读 {[key: string]: any} 表示公共事件的附加信息。

公共事件发布信息(CommonEventPublishData)

在发布公共事件时使用,用于设置发布的公共事件的一些基本信息。

名称 类型 必填 描述
bundleName string 表示包名称。
code number 表示公共事件的结果代码。
data string 表示公共事件的自定义结果数据。
subscriberPermissions Array<string> 表示订阅者的权限。
isOrdered boolean 表示是否是有序事件。
isSticky boolean 表示是否是粘性事件。
parameters {[key: string]: any} 表示公共事件的附加信息。

有序公共事件:

当一个无序公共事件发布时,该公共事件的所有订阅者会同时收到发布信息。

当一个有序公共事件发布时,该公共事件的所有订阅者会根据优先级高低依次收到发布信息。

粘性公共事件:

非粘性公共事件: 公共事件的订阅动作必须在公共事件发布之前进行。

必须订阅者先订阅,然后公共事件发布,订阅者才可以接收到公共事件发布的信息。

粘性公共事件: 公共事件的订阅动作可以在公共事件发布之后进行。

可以先发布公共事件,然后订阅者再订阅,依然可以收到公共事件发布的信息。

公共事件开发指导:

订阅、退订公共事件

  1. 设置订阅信息(公共事件名称、订阅者优先级等)
  2. 使用订阅信息创建订阅者
  3. 使用订阅者订阅、退订

系统公共事件名称请参考CommonEvent文档/公共事件列表

//步骤一: 导入commonEvent模块
import commonEvent from "@ohos.commonEvent";

//步骤二: 创建订阅信息,订阅者信息的数据类型及包含的参数请参考名词解释
let subscribeInfo : any = {
    events : ["testEvent"],     //要订阅的公共事件
    userId : 100,               //用户Id
    priority : 1,               //该订阅者的优先级
    ...
}

let subscriberA = undefined
    
//步骤三:创建订阅者
commonEvent.createSubscriber(subscribeInfo, (err, subscriber) => {
              if (err?.code) {
                console.log("[CommonEvent] CreateSubscriber CallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] CreateSubscriber")
                this.subscriberA = subscriber   //将创建订阅者回调生成的订阅者赋给subscriberA
              }
            })
            
//步骤四: 订阅公共事件
commonEvent.subscribe(subscriberA, (err, data) => {
              if (err?.code) {
                console.log("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data))
              }
            })
            
//退订公共事件
commonEvent.unsubscribe(subscriberA, err=>{
    if(err?.code){
       console.log("[CommonEvent] unSubscribeCallBack err=" + JSON.stringify(err))
    }else{
        console.log("[CommonEvent] unSubscribeCallBack succeed")
    }
})

发布公共事件

开发者可以发布四种公共事件:无序的公共事件、有序的公共事件、带权限的公共事件、粘性的公共事件。

import commonEvent from "@ohos.commonEvent";

//步骤一:设置公共事件发布信息,具体参数信息请参考名词解释
let commonEventPublishData = {
        data : "test data",
        isOrdered: true,        //设置为有序公共事件
        code : 13178,
        isSticky : true,        //设置为粘性公共事件
        parameters : {          //公共事件发布时,携带的参数
                a : "aa",
                b : 'bb',
                c : 'cc'
        }
    }

//步骤二:发布公共事件testEvent
commonEvent.publish("testEvent", commonEventPublishData,(err) => {
              if (err?.code) {
                Logger.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
              } else {
                Logger.info("[CommonEvent] Publish testEvent succeed ")
              }
            })

开发示例

此处以应用间的公共事件发布、订阅为例,应用A发布公共事件,应用B订阅公共事件。

时序图如下:

应用A中代码如下:

三个操作: 创建订阅者、订阅、发布公共事件testEvent

import commonEvent from '@ohos.commonEvent';

@Entry
@Component
struct TestA {
  @State publishCount: number = 0
  @State createSubscriberCount: number = 0
  @State SubscribetestEventCount: number = 0

  subscriberOftestEvent : any = undefined

  build() {
    Row() {
      Column() {

          //步骤一:创建订阅者
        Button('Create Subscriber Of testEvent: '+ this.createSubscriberCount).type(ButtonType.Capsule).fontSize(30).margin({bottom: 15})
          .onClick(()=>{
            this.createSubscriberCount+=1

            let subscribeInfo: any= {
              events: ["testEvent"]
            }

            commonEvent.createSubscriber(subscribeInfo, (err, subscriber) => {
              if (err.code) {
                console.log("[CommonEvent]CreateSubscriberCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent]CreateSubscriber")
                this.subscriberOftestEvent = subscriber
              }
            })

          })

        //步骤二:订阅公共事件testEvent
        Button('Subscribe testEvent: '+ this.SubscribetestEventCount).type(ButtonType.Capsule).fontSize(30).margin({bottom: 30})
          .onClick(()=>{
            console.log("come in !!!")
            this.SubscribetestEventCount+=1

            console.log(`this.subscriberOftestEvent : ${JSON.stringify(this.subscriberOftestEvent)}`)
            commonEvent.subscribe(this.subscriberOftestEvent, (err, data) => {

              if (err?.code) {
                console.log("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                this.SubscribetestEventCount+=1
                console.log("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data))
              }
            })

          })

        //步骤三:发布公共事件testEvent
        Button('Publish testEvent : ' + this.publishCount).fontSize(30).margin({bottom: 15})
          .onClick(()=>{
            this.publishCount+=1
            commonEvent.publish("testEvent", (err) => {
              console.log(`err${JSON.stringify(err)}`)
              if (err?.code) {
                console.log("[CommonEvent] PublishCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] Publish Succeed ")
              }
            })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

应用B中代码如下:

只订阅应用A发布的公共事件testEvent

import commonEvent from '@ohos.commonEvent';

@Component
@Entry
struct TestB{

  @State dCount : number = 0
  @State result : string = "待订阅"
  @State createSubscriberInfo : string = "待创建"
  subscriber : any = undefined
  subscribeInfo: any= {
    events: ["testEvent"],
  }

  build(){
    Column(){
      Column(){

        //步骤一:创建订阅者
        Button('创建订阅者: '+ this.createSubscriberInfo).type(ButtonType.Capsule).fontSize(40)
          .onClick(()=>{

            //创建订阅者回调
            commonEvent.createSubscriber(this.subscribeInfo, (err, subscriber) => {
              if (err?.code) {
                console.log("[CommonEvent] CreateSubscriberCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] CreateSubscriber")
                this.subscriber = subscriber
                this.createSubscriberInfo = "Create subscriber succeed"
              }
            })

          })

        //步骤二:订阅
        Button('订阅公共事件testEvent: '+ this.dCount+this.result).type(ButtonType.Capsule).fontSize(40)
          .onClick(()=>{
            
            commonEvent.subscribe(this.subscriber, (err, data) => {
              if (err?.code) {
                console.log("[CommonEvent]SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                this.dCount+=1
                console.log("[CommonEvent]SubscribeCallBack data=" + JSON.stringify(data))
                this.result = "receive, event = " + data.event + ", data = " + data.data + ", code = " + data.code
              }
            })
          })
      }
    }

  }

}

操作流程:

  1. A应用创建订阅者、订阅
  2. B应用创建订阅者、订阅
  3. A应用发布公共事件testEvent (顺序不能乱,因为这里发布的不是粘性公共事件)

公共事件调试助手cem

公共事件与通知提供了供开发者查看公共事件信息及通知信息、发布公共事件等一些调试功能的工具。

这些工具已经随系统集成,开发者进入shell环境,可以直接调用相关命令。

publish发布公共事件

参数如下表所示

参数 参数说明
-e/--event 必选参数,发布事件名称
-s/--sticky 可选参数,发布粘性事件,默认发布非粘性事件
-o/--ordered 可选参数,发布有序事件,默认发布无序事件
-c/--code 可选参数,公共事件结果码
-d/--data 可选参数,公共事件携带数据
-h/--help 帮助信息

用法示例:

# 发布名称为testevent的公共事件
cem publish --event "testevent"

# 发布名称为testevent的粘性有序公共事件,该事件的结果码为100,携带数据内容为“this is data”
cem publish -e "testevent" -s -o -c 100 -d "this is data"

dump打印公共事件相关信息

参数如下表所示

参数 参数说明
-a/--all 打印开机以来所有已发送的公共事件及其具体信息
-e/--event 查询特定名称事件的具体信息
-h/--help 帮助信息

用法示例:

# 打印公共事件名称为testevent的具体信息
cem dump -e "testevent"

打印出来的信息如下:

Subscribers:    No information
Sticky Events:  No information
Pending Events: No information
History Events: Total 1 information
NO 1
        Time: 20170805 10:12 AM
        PID: 2099
        UID: 20010037
        USERID: ALL_USER                                  
        BundleName: com.ohos.dtest
        RequiredPermission:                         # 发布者所要求的权限
        IsSticky: false                             # 发布的事件是否是粘性事件
        IsOrdered: false                            # 发布的事件是否是有序事件
        IsSystemApp: false                          # 发布者是否是系统应用
        IsSystemEvent: false                        # 发布的事件是否是系统事件
        Want:
                Action: testevent                   # 发布的事件名称
                Entity:
                Scheme:
                Uri:
                Flags: 0
                Type:
                BundleName:
                AbilityName:
                DevicedID:
        Code: 0                                     # 有序事件的结果码,仅在有序事件下有效
        Data:                                       # 事件携带的数据
        HasLastSubscriber: false                    # 是否有最终订阅者,仅在有序事件下有效
        EventState: RECEIVED                        # 事件发送状态
        ReceiverTime: 0
        DispatchTime: 0
        ResultAbort: false                          # 事件是否被终止,仅在有序事件下有效
        Subscribers:    Total 1 subscribers         # 所有可以接收该事件的订阅者信息
        NO 1
                Time: 20170805 10:11 AM
                BundleName: com.ohos.dtest          # 事件订阅者的包名
                Priority: 0                         # 订阅者的优先级,仅在订阅有序
                USERID: ALL_USER                    # 作为子系统订阅者,没有指定用户ID的情况下,默认订阅所有的用户;                                                                          # 如果是三方应用,则只能订阅这个包对应的用户ID,且不允许订阅其他的用户。
                Permission:                         # 订阅者所要求的权限
                DevicedID:
                IsFreeze: false                     # 订阅者是否被冻结,被冻结的订阅者将无法收到事件
                FreezeTime:  -
                EventState: DELIVERED                # 订阅者接收状态
  • 发布者EventState有三种状态:
    • IDLE表示没有订阅者或者有序事件正在等待处理下一个订阅者;
    • RECEIVEING表示该订阅者们仍然在处理该事件;
    • RECEIVED表示所有订阅已经处理完成,事件发送完成。
  • 订阅者EventState有四种状态:
    • PENDING表示订阅者仍在等待处理事件;
    • DELIVERED表示订阅者已经完成接收;
    • SKIPPED表示该订阅者不能接收该事件,常见于权限不匹配或者订阅者被冻结的情况下;
    • TIMEOUT仅出现在有序事件下,表示该订阅者处理事件超时。

参考文献

[1]OpenHarmony公共事件.https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-commonEvent.md

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部