1# 多端协同 2 3 4## 功能描述 5 6多端协同主要包括如下场景: 7 8- [通过跨设备启动UIAbility和ServiceExtensionAbility组件实现多端协同(无返回数据)](#通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据) 9 10- [通过跨设备启动UIAbility组件实现多端协同(获取返回数据)](#通过跨设备启动uiability组件实现多端协同获取返回数据) 11 12- [通过跨设备连接ServiceExtensionAbility组件实现多端协同](#通过跨设备连接serviceextensionability组件实现多端协同) 13 14- [通过跨设备Call调用实现多端协同](#通过跨设备call调用实现多端协同) 15 16 17## 多端协同流程 18 19多端协同流程如下图所示。 20 21 **图1** 多端协同流程图 22 23 24 25## 约束限制 26 27- 由于“多端协同任务管理”能力尚未具备,开发者当前只能通过开发系统应用获取设备列表,不支持三方应用接入。 28 29- 多端协同需遵循[分布式跨设备组件启动规则](component-startup-rules.md#分布式跨设备组件启动规则)。 30 31- 为了获得最佳体验,使用want传输的数据建议在100KB以下。 32 33 34## 通过跨设备启动UIAbility和ServiceExtensionAbility组件实现多端协同(无返回数据) 35 36在设备A上通过发起端应用提供的启动按钮,启动设备B上指定的UIAbility与ServiceExtensionAbility。 37 38 39### 接口说明 40 41 **表1** 跨设备启动API接口功能介绍 42 43| **接口名** | **描述** | 44| -------- | -------- | 45| startAbility(want: Want, callback: AsyncCallback<void>): void; | 启动UIAbility和ServiceExtensionAbility(callback形式)。 | 46| stopServiceExtensionAbility(want: Want, callback: AsyncCallback<void>): void; | 退出启动的ServiceExtensionAbility(callback形式)。 | 47| stopServiceExtensionAbility(want: Want): Promise<void>; | 退出启动的ServiceExtensionAbility(Promise形式)。 | 48 49 50### 开发步骤 51 521. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 53 542. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 55 563. 获取目标设备的设备ID。 57 58 ```ts 59 import deviceManager from '@ohos.distributedDeviceManager'; 60 61 let dmClass: deviceManager.DeviceManager; 62 function initDmClass() { 63 // 其中createDeviceManager接口为系统API 64 try{ 65 dmClass = deviceManager.createDeviceManager('ohos.samples.demo'); 66 } catch(err) { 67 console.error("createDeviceManager err: " + JSON.stringify(err)); 68 } 69 } 70 function getRemoteDeviceId(): string | undefined { 71 if (typeof dmClass === 'object' && dmClass !== null) { 72 let list = dmClass.getAvailableDeviceListSync(); 73 if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') { 74 console.info('getRemoteDeviceId err: list is null'); 75 return; 76 } 77 if (list.length === 0) { 78 console.info("getRemoteDeviceId err: list is empty"); 79 return; 80 } 81 return list[0].networkId; 82 } else { 83 console.info('getRemoteDeviceId err: dmClass is null'); 84 return; 85 } 86 } 87 ``` 88 894. 设置目标组件参数,调用[`startAbility()`](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)接口,启动UIAbility或ServiceExtensionAbility。 90 91 ```ts 92 import { BusinessError } from '@ohos.base'; 93 import Want from '@ohos.app.ability.Want'; 94 let want: Want = { 95 deviceId: getRemoteDeviceId(), 96 bundleName: 'com.example.myapplication', 97 abilityName: 'EntryAbility', 98 moduleName: 'entry', // moduleName非必选 99 } 100 // context为发起端UIAbility的AbilityContext 101 this.context.startAbility(want).then(() => { 102 // ... 103 }).catch((err: BusinessError) => { 104 // ... 105 console.error("startAbility err: " + JSON.stringify(err)); 106 }) 107 ``` 108 1095. 当设备A发起端应用不需要设备B上的ServiceExtensionAbility时,可调用[stopServiceExtensionAbility](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstopserviceextensionability)接口退出。(该接口不支持UIAbility的退出,UIAbility由用户手动通过任务管理退出) 110 111 ```ts 112 import Want from '@ohos.app.ability.Want'; 113 import { BusinessError } from '@ohos.base'; 114 let want: Want = { 115 deviceId: getRemoteDeviceId(), 116 bundleName: 'com.example.myapplication', 117 abilityName: 'FuncAbility', 118 moduleName: 'module1', // moduleName非必选 119 } 120 // 退出由startAbility接口启动的ServiceExtensionAbility 121 this.context.stopServiceExtensionAbility(want).then(() => { 122 console.info("stop service extension ability success") 123 }).catch((err: BusinessError) => { 124 console.info("stop service extension ability err is " + JSON.stringify(err)) 125 }) 126 ``` 127 128## 通过跨设备启动UIAbility组件实现多端协同(获取返回数据) 129 130在设备A上通过应用提供的启动按钮,启动设备B上指定的UIAbility,当设备B上的UIAbility退出后,会将返回值发回设备A上的发起端应用。 131 132 133### 接口说明 134 135 **表2** 跨设备启动,返回结果数据API接口功能描述 136 137| 接口名 | 描述 | 138| -------- | -------- | 139| startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void; | 启动UIAbility并在该Ability退出的时候返回执行结果(callback形式)。 | 140| terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void; | 停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(callback形式)。 | 141| terminateSelfWithResult(parameter: AbilityResult): Promise<void>; | 停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(promise形式)。 | 142 143 144### 开发步骤 145 1461. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 147 1482. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 149 1503. 在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。getRemoteDeviceId方法参照[通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据](#通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据)。 151 152 ```ts 153 import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 154 import common from '@ohos.app.ability.common'; 155 import { BusinessError } from '@ohos.base'; 156 import Want from '@ohos.app.ability.Want'; 157 @Entry 158 @Component 159 struct PageName { 160 private context = getContext(this) as common.UIAbilityContext; 161 build() { 162 // ... 163 Button('StartAbilityForResult') 164 .onClick(()=>{ 165 let want: Want = { 166 deviceId: getRemoteDeviceId(), 167 bundleName: 'com.example.myapplication', 168 abilityName: 'FuncAbility', 169 moduleName: 'module1', // moduleName非必选 170 } 171 // context为发起端UIAbility的AbilityContext 172 this.context.startAbilityForResult(want).then((data) => { 173 // ... 174 }).catch((error: BusinessError) => { 175 console.info("startAbilityForResult err: " + JSON.stringify(error)); 176 }) 177 } 178 ) 179 } 180 } 181 ``` 182 1834. 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。 184 185 ```ts 186 import { BusinessError } from '@ohos.base'; 187 import common from '@ohos.app.ability.common'; 188 @Entry 189 @Component 190 struct PageName { 191 private context = getContext(this) as common.UIAbilityContext; 192 build() { 193 // ... 194 Button('terminateSelfWithResult') 195 .onClick(()=>{ 196 const RESULT_CODE: number = 1001; 197 // context为目标端UIAbility的AbilityContext 198 this.context.terminateSelfWithResult( 199 { 200 resultCode: RESULT_CODE, 201 want: { 202 bundleName: 'com.example.myapplication', 203 abilityName: 'FuncAbility', 204 moduleName: 'module1', 205 }, 206 }, 207 (err: BusinessError) => { 208 // ... 209 console.info("terminateSelfWithResult err: " + JSON.stringify(err)); 210 }); 211 } 212 // ... 213 ) 214 } 215 } 216 ``` 217 2185. 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。 219 220 ```ts 221 import common from '@ohos.app.ability.common'; 222 import { BusinessError } from '@ohos.base'; 223 import Want from '@ohos.app.ability.Want'; 224 @Entry 225 @Component 226 struct PageName { 227 private context = getContext(this) as common.UIAbilityContext; 228 build() { 229 // ... 230 Button('StartAbilityForResult') 231 .onClick(()=>{ 232 let want: Want = { 233 deviceId: getRemoteDeviceId(), 234 bundleName: 'com.example.myapplication', 235 abilityName: 'FuncAbility', 236 moduleName: 'module1', // moduleName非必选 237 } 238 const RESULT_CODE: number = 1001; 239 // ... 240 // context为调用方UIAbility的UIAbilityContext 241 this.context.startAbilityForResult(want).then((data) => { 242 if (data?.resultCode === RESULT_CODE) { 243 // 解析目标端UIAbility返回的信息 244 let info = data.want?.parameters?.info; 245 // ... 246 } 247 }).catch((error: BusinessError) => { 248 // ... 249 }) 250 } 251 ) 252 } 253 } 254 ``` 255 256 257## 通过跨设备连接ServiceExtensionAbility组件实现多端协同 258 259系统应用可以通过[connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability)跨设备连接一个服务,实现跨设备远程调用。比如:分布式游戏场景,平板作为遥控器,智慧屏作为显示器。 260 261 262### 接口说明 263 264 **表3** 跨设备连接API接口功能介绍 265 266| 接口名 | 描述 | 267| -------- | -------- | 268| connectServiceExtensionAbility(want: Want, options: ConnectOptions): number; | 连接ServiceExtensionAbility。 | 269| disconnectServiceExtensionAbility(connection: number, callback:AsyncCallback<void>): void; | 断开连接(callback形式)。 | 270| disconnectServiceExtensionAbility(connection: number): Promise<void>; | 断开连接(promise形式)。 | 271 272 273### 开发步骤 274 2751. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 276 2772. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 278 2793. 如果已有后台服务,请直接进入下一步;如果没有,则[实现一个后台服务](serviceextensionability.md#实现一个后台服务(仅对系统应用开放))。 280 2814. 连接一个后台服务。 282 - 实现IAbilityConnection接口。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常终止的回调,onFailed()是用来处理连接Service失败的回调。 283 - 设置目标组件参数,包括目标设备ID、Bundle名称、Ability名称。 284 - 调用connectServiceExtensionAbility发起连接。 285 - 连接成功,收到目标设备返回的服务句柄。 286 - 进行跨设备调用,获得目标端服务返回的结果。 287 288 ```ts 289 import rpc from '@ohos.rpc'; 290 import Want from '@ohos.app.ability.Want'; 291 import common from '@ohos.app.ability.common'; 292 import { BusinessError } from '@ohos.base'; 293 @Entry 294 @Component 295 struct PageName { 296 private context = getContext(this) as common.UIAbilityContext; 297 build() { 298 // ... 299 Button('connectServiceExtensionAbility') 300 .onClick(()=>{ 301 const REQUEST_CODE = 99; 302 let want: Want = { 303 "deviceId": getRemoteDeviceId(), 304 "bundleName": "com.example.myapplication", 305 "abilityName": "ServiceExtAbility" 306 }; 307 // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入 308 let connectionId = this.context.connectServiceExtensionAbility(want, 309 { 310 onConnect(elementName, remote) { 311 console.info('onConnect callback'); 312 if (remote === null) { 313 console.info(`onConnect remote is null`); 314 return; 315 } 316 let option = new rpc.MessageOption(); 317 let data = new rpc.MessageSequence(); 318 let reply = new rpc.MessageSequence(); 319 data.writeInt(1); 320 data.writeInt(99); // 开发者可发送data到目标端应用进行相应操作 321 // @param code 表示客户端发送的服务请求代码。 322 // @param data 表示客户端发送的{@link MessageSequence}对象。 323 // @param reply 表示远程服务发送的响应消息对象。 324 // @param options 指示操作是同步的还是异步的。 325 // 326 // @return 如果操作成功返回{@code true}; 否则返回 {@code false}。 327 remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => { 328 let msg = reply.readInt(); // 在成功连接的情况下,会收到来自目标端返回的信息(100) 329 console.info(`sendRequest ret:${ret} msg:${msg}`); 330 }).catch((error: BusinessError) => { 331 console.info('sendRequest failed'); 332 }); 333 }, 334 onDisconnect(elementName) { 335 console.info('onDisconnect callback'); 336 }, 337 onFailed(code) { 338 console.info('onFailed callback'); 339 } 340 }); 341 }) 342 } 343 } 344 ``` 345 346 getRemoteDeviceId方法参照[通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据](#通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据)。 347 3485. 断开连接。调用disconnectServiceExtensionAbility()断开与后台服务的连接。 349 350 ```ts 351 import common from '@ohos.app.ability.common'; 352 import { BusinessError } from '@ohos.base'; 353 @Entry 354 @Component 355 struct PageName { 356 private context = getContext(this) as common.UIAbilityContext; 357 build() { 358 // ... 359 Button('disconnectServiceExtensionAbility') 360 .onClick(()=>{ 361 let connectionId: number = 1 // 在通过connectServiceExtensionAbility绑定服务时返回的Id 362 this.context.disconnectServiceExtensionAbility(connectionId).then(() => { 363 console.info('disconnectServiceExtensionAbility success'); 364 }).catch((error: BusinessError) => { 365 console.error('disconnectServiceExtensionAbility failed'); 366 }) 367 }) 368 } 369 } 370 ``` 371 372 373## 通过跨设备Call调用实现多端协同 374 375跨设备Call调用的基本原理与设备内Call调用相同,请参见[通过Call调用实现UIAbility交互(仅对系统应用开放)](uiability-intra-device-interaction.md#通过call调用实现uiability交互仅对系统应用开放)。 376 377下面介绍跨设备Call调用实现多端协同的方法。 378 379 380### 接口说明 381 382 **表4** Call API接口功能介绍 383 384| 接口名 | 描述 | 385| -------- | -------- | 386| startAbilityByCall(want: Want): Promise<Caller>; | 启动指定UIAbility至前台或后台,同时获取其Caller通信接口,调用方可使用Caller与被启动的Ability进行通信。 | 387| on(method: string, callback: CalleeCallBack): void | 通用组件Callee注册method对应的callback方法。 | 388| off(method: string): void | 通用组件Callee解注册method的callback方法。 | 389| call(method: string, data: rpc.Parcelable): Promise<void> | 向通用组件Callee发送约定序列化数据。 | 390| callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence> | 向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。 | 391| release(): void | 释放通用组件的Caller通信接口。 | 392| on(type: "release", callback: OnReleaseCallback): void | 注册通用组件通信断开监听通知。 | 393 394 395### 开发步骤 396 3971. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 398 3992. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 400 4013. 创建被调用端UIAbility。 402 被调用端UIAbility需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。 403 404 1. 配置UIAbility的启动模式。 405 配置module.json5,将CalleeAbility配置为单实例"singleton"。 406 407 | Json字段 | 字段说明 | 408 | -------- | -------- | 409 | “launchType” | Ability的启动模式,设置为"singleton"类型。 | 410 411 UIAbility配置标签示例如下: 412 413 414 ```json 415 "abilities":[{ 416 "name": ".CalleeAbility", 417 "srcEntry": "./ets/CalleeAbility/CalleeAbility.ts", 418 "launchType": "singleton", 419 "description": "$string:CalleeAbility_desc", 420 "icon": "$media:icon", 421 "label": "$string:CalleeAbility_label", 422 "exported": true 423 }] 424 ``` 425 2. 导入UIAbility模块。 426 427 ```ts 428 import UIAbility from '@ohos.app.ability.UIAbility'; 429 ``` 430 3. 定义约定的序列化数据。 431 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。 432 433 434 ```ts 435 import rpc from '@ohos.rpc' 436 class MyParcelable { 437 num: number = 0; 438 str: string = ""; 439 440 constructor(num: number, string: string) { 441 this.num = num; 442 this.str = string; 443 } 444 445 marshalling(messageSequence: rpc.MessageSequence) { 446 messageSequence.writeInt(this.num); 447 messageSequence.writeString(this.str); 448 return true; 449 } 450 451 unmarshalling(messageSequence: rpc.MessageSequence) { 452 this.num = messageSequence.readInt(); 453 this.str = messageSequence.readString(); 454 return true; 455 } 456 } 457 ``` 458 4. 实现Callee.on监听及Callee.off解除监听。 459 如下示例在Ability的onCreate注册MSG_SEND_METHOD监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回。应用开发者根据实际业务需要做相应处理。 460 461 ```ts 462 import rpc from '@ohos.rpc'; 463 import Want from '@ohos.app.ability.Want'; 464 import UIAbility from '@ohos.app.ability.UIAbility'; 465 import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 466 const TAG: string = '[CalleeAbility]'; 467 const MSG_SEND_METHOD: string = 'CallSendMsg'; 468 469 function sendMsgCallback(data: rpc.MessageSequence): MyParcelable { 470 console.info('CalleeSortFunc called'); 471 472 // 获取Caller发送的序列化数据 473 let receivedData: MyParcelable = new MyParcelable(0, ''); 474 data.readParcelable(receivedData); 475 console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`); 476 477 // 作相应处理 478 // 返回序列化数据result给Caller 479 return new MyParcelable(Number(receivedData.num) + 1, `send ${receivedData.str} succeed`); 480 } 481 482 export default class CalleeAbility extends UIAbility { 483 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 484 try { 485 this.callee.on(MSG_SEND_METHOD, sendMsgCallback); 486 } catch (error) { 487 console.info(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`); 488 } 489 } 490 491 onDestroy() { 492 try { 493 this.callee.off(MSG_SEND_METHOD); 494 } catch (error) { 495 console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`); 496 } 497 } 498 } 499 ``` 500 5014. 获取Caller接口,访问被调用端UIAbility。 502 1. 导入UIAbility模块。 503 504 ```ts 505 import UIAbility from '@ohos.app.ability.UIAbility'; 506 ``` 507 2. 获取Caller通信接口。 508 Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease和onRemoteStateChange监听。应用开发者根据实际业务需要做相应处理。 509 510 511 ```ts 512 import UIAbility, { Caller } from '@ohos.app.ability.UIAbility'; 513 import { BusinessError } from '@ohos.base'; 514 export default class EntryAbility extends UIAbility { 515 // ... 516 async onButtonGetRemoteCaller() { 517 let caller: Caller | undefined; 518 let context = this.context; 519 520 context.startAbilityByCall({ 521 deviceId: getRemoteDeviceId(), 522 bundleName: 'com.samples.CallApplication', 523 abilityName: 'CalleeAbility' 524 }).then((data) => { 525 if (data != null) { 526 caller = data; 527 console.info('get remote caller success'); 528 // 注册caller的release监听 529 caller.onRelease((msg) => { 530 console.info(`remote caller onRelease is called ${msg}`); 531 }) 532 console.info('remote caller register OnRelease succeed'); 533 // 注册caller的协同场景下跨设备组件状态变化监听通知 534 try { 535 caller.onRemoteStateChange((str) => { 536 console.info('Remote state changed ' + str); 537 }); 538 } catch (error) { 539 console.info('Caller.onRemoteStateChange catch error, error.code: ${JSON.stringify(error.code)}, error.message: ${JSON.stringify(error.message)}'); 540 } 541 } 542 }).catch((error: BusinessError) => { 543 console.error(`get remote caller failed with ${error}`); 544 }) 545 } 546 // ... 547 } 548 ``` 549 550 getRemoteDeviceId方法参照[通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据](#通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据)。 551 5525. 向被调用端UIAbility发送约定序列化数据。 553 1. 向被调用端发送Parcelable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。 554 555 ```ts 556 import UIAbility, { Caller } from '@ohos.app.ability.UIAbility'; 557 import { BusinessError } from '@ohos.base'; 558 const MSG_SEND_METHOD: string = 'CallSendMsg'; 559 export default class EntryAbility extends UIAbility { 560 // ... 561 caller: Caller | undefined; 562 async onButtonCall() { 563 try { 564 let msg: MyParcelable = new MyParcelable(1, 'origin_Msg'); 565 if (this.caller) { 566 await this.caller.call(MSG_SEND_METHOD, msg); 567 } 568 } catch (error) { 569 console.info(`caller call failed with ${error}`); 570 } 571 } 572 // ... 573 } 574 ``` 575 2. 如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据originMsg,并将’CallSendMsg’方法处理完毕的数据赋值给backMsg。 576 577 ```ts 578 import UIAbility, { Caller } from '@ohos.app.ability.UIAbility'; 579 import rpc from '@ohos.rpc'; 580 const MSG_SEND_METHOD: string = 'CallSendMsg'; 581 let originMsg: string = ''; 582 let backMsg: string = ''; 583 export default class EntryAbility extends UIAbility { 584 // ... 585 caller: Caller | undefined; 586 async onButtonCallWithResult(originMsg: string, backMsg: string) { 587 try { 588 let msg: MyParcelable = new MyParcelable(1, originMsg); 589 if (this.caller) { 590 const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg); 591 console.info('caller callWithResult succeed'); 592 let result: MyParcelable = new MyParcelable(0, ''); 593 data.readParcelable(result); 594 backMsg = result.str; 595 console.info(`caller result is [${result.num}, ${result.str}]`); 596 } 597 } catch (error) { 598 console.info(`caller callWithResult failed with ${error}`); 599 } 600 } 601 // ... 602 } 603 ``` 604 6056. 释放Caller通信接口。 606 Caller不再使用后,应用开发者可以通过release接口释放Caller。 607 608 ```ts 609 import UIAbility, { Caller } from '@ohos.app.ability.UIAbility'; 610 export default class EntryAbility extends UIAbility { 611 caller: Caller | undefined; 612 releaseCall() { 613 try { 614 if (this.caller) { 615 this.caller.release(); 616 this.caller = undefined; 617 } 618 console.info('caller release succeed'); 619 } catch (error) { 620 console.info(`caller release failed with ${error}`); 621 } 622 } 623 } 624 ``` 625