• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![hop-multi-device-collaboration](figures/hop-multi-device-collaboration.png)
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