1# Call调用开发指导 2## 场景介绍 3Ability Call调用是Ability能力的扩展,它为Ability提供一种能够被外部调用的能力,使Ability既能被拉起到前台展示UI,也支持Ability在后台被创建并运行。应用开发者可通过Call调用,使用IPC通信实现不同Ability之间的数据共享。Call调用的场景主要包括: 4- 创建Callee被调用端。 5- 访问Callee被调用端。 6 7本文中的Caller和Callee分别表示调用者和被调用者,IPC表示进程间通信,Call调用流程示意图如下。 8 9 10 11>  **说明:** 12> Callee被调用端所在的Ability,启动模式需要为单实例。 13> 当前仅支持系统应用及ServiceExtensionAbility使用Call访问Callee。 14 15## 接口说明 16Caller及Callee功能如下:具体的API详见[接口文档](../reference/apis/js-apis-application-ability.md#caller)。 17 18**表1** Call API接口功能介绍 19|接口名|描述| 20|:------|:------| 21|startAbilityByCall(want: Want): Promise\<Caller>|获取指定通用组件的Caller通信接口,拉起指定通用组件并将其切换到后台。| 22|on(method: string, callback: CaleeCallBack): void|通用组件Callee注册method对应的callback方法。| 23|off(method: string): void|通用组件Callee去注册method的callback方法。| 24|call(method: string, data: rpc.Sequenceable): Promise\<void>|向通用组件Callee发送约定序列化数据。| 25|callWithResult(method: string, data: rpc.Sequenceable): Promise\<rpc.MessageParcel>|向通用组件Callee发送约定序列化数据, 并将返回的约定序列化数据带回。| 26|release(): void|释放通用组件的Caller通信接口。| 27|onRelease(callback: OnReleaseCallBack): void|注册通用组件通信断开监听通知。| 28 29## 开发步骤 30>  **说明:** 31> 开发步骤章节中的示例代码片段是开发过程的步骤化展示,部分代码可能无法单独运行,完整工程代码请参考[相关实例](#相关实例)。 32### 创建Callee被调用端 33Callee被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。 341. 配置Ability的启动模式 35 36 配置module.json5,将Callee被调用端所在的Ability配置为单实例"singleton"。 37 38|Json字段|字段说明| 39|:------|:------| 40|"launchType"|Ability的启动模式,设置为"singleton"类型。 | 41 42Ability配置标签示例如下: 43```json 44"abilities":[{ 45 "name": ".CalleeAbility", 46 "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", 47 "launchType": "singleton", 48 "description": "$string:CalleeAbility_desc", 49 "icon": "$media:icon", 50 "label": "$string:CalleeAbility_label", 51 "visible": true 52}] 53``` 542. 导入Ability模块。 55``` 56import Ability from '@ohos.application.Ability' 57``` 583. 定义约定的序列化数据。 59 60 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。具体示例代码如下: 61```ts 62export default class MySequenceable { 63 num: number = 0 64 str: String = "" 65 66 constructor(num, string) { 67 this.num = num 68 this.str = string 69 } 70 71 marshalling(messageParcel) { 72 messageParcel.writeInt(this.num) 73 messageParcel.writeString(this.str) 74 return true 75 } 76 77 unmarshalling(messageParcel) { 78 this.num = messageParcel.readInt() 79 this.str = messageParcel.readString() 80 return true 81 } 82} 83``` 844. 实现Callee.on监听及Callee.off解除监听。 85 86 被调用端Callee的监听函数注册时机, 取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在Ability的onCreate注册'MSG_SEND_METHOD'监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下: 87```ts 88const TAG: string = '[CalleeAbility]' 89const MSG_SEND_METHOD: string = 'CallSendMsg' 90 91function sendMsgCallback(data) { 92 Logger.log(TAG, 'CalleeSortFunc called') 93 94 // 获取Caller发送的序列化数据 95 let receivedData = new MySequenceable(0, '') 96 data.readSequenceable(receivedData) 97 Logger.log(TAG, `receiveData[${receivedData.num}, ${receivedData.str}]`) 98 99 // 作相应处理 100 // 返回序列化数据result给Caller 101 return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`) 102} 103 104export default class CalleeAbility extends Ability { 105 onCreate(want, launchParam) { 106 try { 107 this.callee.on(MSG_SEND_METHOD, sendMsgCallback) 108 } catch (error) { 109 Logger.error(TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) 110 } 111 } 112 113 onDestroy() { 114 try { 115 this.callee.off(MSG_SEND_METHOD) 116 } catch (error) { 117 console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`) 118 } 119 } 120} 121``` 122 123### 访问Callee被调用端 1241. 导入Ability模块。 125``` 126import Ability from '@ohos.application.Ability' 127``` 1282. 获取Caller通信接口。 129 130 Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过`this.context`获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease监听。应用开发者根据实际需要做相应处理。具体示例代码如下: 131```ts 132async onButtonGetCaller() { 133 try { 134 this.caller = await context.startAbilityByCall({ 135 bundleName: 'com.samples.CallApplication', 136 abilityName: 'CalleeAbility' 137 }) 138 if (this.caller === undefined) { 139 Logger.error(TAG, 'get caller failed') 140 return 141 } 142 Logger.log(TAG, 'get caller success') 143 this.regOnRelease(this.caller) 144 } catch (error) { 145 Logger.error(TAG, `get caller failed with ${error}`) 146 } 147}.catch((error) => { 148 console.error(TAG + 'get caller failed with ' + error) 149}) 150``` 151 在跨设备场景下,需指定对端设备deviceId。具体示例代码如下: 152```ts 153let TAG = '[MainAbility] ' 154var caller = undefined 155let context = this.context 156 157context.startAbilityByCall({ 158 deviceId: getRemoteDeviceId(), 159 bundleName: 'com.samples.CallApplication', 160 abilityName: 'CalleeAbility' 161}).then((data) => { 162 if (data != null) { 163 caller = data 164 console.log(TAG + 'get remote caller success') 165 // 注册caller的release监听 166 caller.onRelease((msg) => { 167 console.log(TAG + 'remote caller onRelease is called ' + msg) 168 }) 169 console.log(TAG + 'remote caller register OnRelease succeed') 170 } 171}).catch((error) => { 172 console.error(TAG + 'get remote caller failed with ' + error) 173}) 174``` 175 从DeviceManager获取指定设备的deviceId,getTrustedDeviceListSync接口仅对系统应用开放。具体示例代码如下: 176```ts 177import deviceManager from '@ohos.distributedHardware.deviceManager'; 178var dmClass; 179function getRemoteDeviceId() { 180 if (typeof dmClass === 'object' && dmClass != null) { 181 var list = dmClass.getTrustedDeviceListSync(); 182 if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { 183 console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); 184 return; 185 } 186 console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); 187 return list[0].deviceId; 188 } else { 189 console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); 190 } 191} 192``` 193 在跨设备场景下,需要向用户申请数据同步的权限。具体示例代码如下: 194```ts 195let context = this.context 196let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC'] 197context.requestPermissionsFromUser(permissions).then((data) => { 198 console.log("Succeed to request permission from user with data: "+ JSON.stringify(data)) 199}).catch((error) => { 200 console.log("Failed to request permission from user with error: "+ JSON.stringify(error)) 201}) 202``` 2033. 发送约定序列化数据 204 205 向被调用端发送Sequenceable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。具体示例代码如下: 206```ts 207const MSG_SEND_METHOD: string = 'CallSendMsg' 208async onButtonCall() { 209 try { 210 let msg = new MySequenceable(1, 'origin_Msg') 211 await this.caller.call(MSG_SEND_METHOD, msg) 212 } catch (error) { 213 Logger.error(TAG, `caller call failed with ${error}`) 214 } 215} 216``` 217 218 如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据`originMsg`,并将'CallSendMsg'方法处理完毕的数据赋值给`backMsg`。具体示例代码如下: 219```ts 220const MSG_SEND_METHOD: string = 'CallSendMsg' 221originMsg: string = '' 222backMsg: string = '' 223async onButtonCallWithResult(originMsg, backMsg) { 224 try { 225 let msg = new MySequenceable(1, originMsg) 226 const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg) 227 Logger.log(TAG, 'caller callWithResult succeed') 228 229 let result = new MySequenceable(0, '') 230 data.readSequenceable(result) 231 backMsg(result.str) 232 Logger.log(TAG, `caller result is [${result.num}, ${result.str}]`) 233 } catch (error) { 234 Logger.error(TAG, `caller callWithResult failed with ${error}`) 235 } 236} 237``` 2384. 释放Caller通信接口 239 240 Caller不再使用后,应用开发者可以通过release接口释放Caller。具体示例代码如下: 241```ts 242try { 243 this.caller.release() 244 this.caller = undefined 245 Logger.log(TAG, 'caller release succeed') 246} catch (error) { 247 Logger.error(TAG, `caller release failed with ${error}`) 248} 249``` 250 251