1e41f4b71Sopenharmony_ci# Multi-device Collaboration
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ci## When to Use
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ciMulti-device collaboration involves the following scenarios:
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ci- [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned)
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci- [Starting UIAbility Across Devices (Data Returned)](#starting-uiability-across-devices-data-returned)
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci- [Connecting to ServiceExtensionAbility Across Devices](#connecting-to-serviceextensionability-across-devices)
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci- [Using Cross-Device Call](#using-cross-device-call)
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci## Multi-Device Collaboration Process
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ciThe figure below shows the multi-device collaboration process.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci**Figure 1** Multi-device collaboration process
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci![hop-multi-device-collaboration](figures/hop-multi-device-collaboration.png)
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci## Constraints
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci- Since multi-device collaboration mission management is not available, you can obtain the device list by developing system applications. Third-party applications cannot access the device list.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci- Multi-device collaboration must comply with [Inter-Device Component Startup Rules](component-startup-rules.md#inter-device-component-startup-rules).
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci- For better user experience, you are advised to use the [want](../reference/apis-ability-kit/js-apis-app-ability-want.md) parameter to transmit data smaller than 100 KB.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci## Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ciOn device A, touch the **Start** button provided by the initiator application to start a specified [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) or [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) on device B.
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci### Available APIs
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci**Table 1** Cross-device startup APIs
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ci| **API**| **Description**|
45e41f4b71Sopenharmony_ci| -------- | -------- |
46e41f4b71Sopenharmony_ci| startAbility(want: Want, callback: AsyncCallback<void>): void; | Starts a UIAbility or ServiceExtensionAbility. This API uses an asynchronous callback to return the result.|
47e41f4b71Sopenharmony_ci| stopServiceExtensionAbility(want: Want, callback: AsyncCallback<void>): void; | Stops a ServiceExtensionAbility. This API uses an asynchronous callback to return the result.|
48e41f4b71Sopenharmony_ci| stopServiceExtensionAbility(want: Want): Promise<void>; | Stops a ServiceExtensionAbility. This API uses a promise to return the result.|
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci### How to Develop
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci2. Display a dialog box to ask for authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md).
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci3. Obtain the device ID of the target device.
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci    ```ts
60e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
61e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
64e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci    function initDmClass(): void {
69e41f4b71Sopenharmony_ci      // createDeviceManager is a system API.
70e41f4b71Sopenharmony_ci      try {
71e41f4b71Sopenharmony_ci        dmClass = distributedDeviceManager.createDeviceManager('com.samples.stagemodelabilitydevelop');
72e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass) ?? '');
73e41f4b71Sopenharmony_ci      } catch (err) {
74e41f4b71Sopenharmony_ci        hilog.error(DOMAIN_NUMBER, TAG, 'createDeviceManager err: ' + JSON.stringify(err));
75e41f4b71Sopenharmony_ci      }
76e41f4b71Sopenharmony_ci    }
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
79e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
80e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
81e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
82e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
83e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
84e41f4b71Sopenharmony_ci          return;
85e41f4b71Sopenharmony_ci        }
86e41f4b71Sopenharmony_ci        if (list.length === 0) {
87e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
88e41f4b71Sopenharmony_ci          return;
89e41f4b71Sopenharmony_ci        }
90e41f4b71Sopenharmony_ci        return list[0].networkId;
91e41f4b71Sopenharmony_ci      } else {
92e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
93e41f4b71Sopenharmony_ci        return;
94e41f4b71Sopenharmony_ci      }
95e41f4b71Sopenharmony_ci    }
96e41f4b71Sopenharmony_ci    ```
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci4. Set the target component parameters, and call [startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to start a [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) or [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md).
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci    ```ts
101e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
102e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
103e41f4b71Sopenharmony_ci    import { Want, common } from '@kit.AbilityKit';
104e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
105e41f4b71Sopenharmony_ci    import { promptAction } from '@kit.ArkUI';
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
108e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
109e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
112e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
113e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
114e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
115e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
116e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
117e41f4b71Sopenharmony_ci          return;
118e41f4b71Sopenharmony_ci        }
119e41f4b71Sopenharmony_ci        if (list.length === 0) {
120e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
121e41f4b71Sopenharmony_ci          return;
122e41f4b71Sopenharmony_ci        }
123e41f4b71Sopenharmony_ci        return list[0].networkId;
124e41f4b71Sopenharmony_ci      } else {
125e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
126e41f4b71Sopenharmony_ci        return;
127e41f4b71Sopenharmony_ci      }
128e41f4b71Sopenharmony_ci    };
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci    @Entry
131e41f4b71Sopenharmony_ci    @Component
132e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
133e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci      build() {
136e41f4b71Sopenharmony_ci        Column() {
137e41f4b71Sopenharmony_ci          //...
138e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
139e41f4b71Sopenharmony_ci            //...
140e41f4b71Sopenharmony_ci            ListItem() {
141e41f4b71Sopenharmony_ci              Row() {
142e41f4b71Sopenharmony_ci                //...
143e41f4b71Sopenharmony_ci              }
144e41f4b71Sopenharmony_ci              .onClick(() => {
145e41f4b71Sopenharmony_ci                let want: Want = {
146e41f4b71Sopenharmony_ci                  deviceId: getRemoteDeviceId(),
147e41f4b71Sopenharmony_ci                  bundleName: 'com.samples.stagemodelabilityinteraction',
148e41f4b71Sopenharmony_ci                  abilityName: 'CollaborateAbility',
149e41f4b71Sopenharmony_ci                  moduleName: 'entry', // moduleName is optional.
150e41f4b71Sopenharmony_ci                };
151e41f4b71Sopenharmony_ci                // context is the AbilityContext of the initiator UIAbility.
152e41f4b71Sopenharmony_ci                this.context.startAbility(want).then(() => {
153e41f4b71Sopenharmony_ci                  promptAction.showToast({
154e41f4b71Sopenharmony_ci                    message: 'SuccessfulCollaboration'
155e41f4b71Sopenharmony_ci                  });
156e41f4b71Sopenharmony_ci                }).catch((err: BusinessError) => {
157e41f4b71Sopenharmony_ci                  hilog.error(DOMAIN_NUMBER, TAG, `startAbility err: ` + JSON.stringify(err));
158e41f4b71Sopenharmony_ci                });
159e41f4b71Sopenharmony_ci              })
160e41f4b71Sopenharmony_ci            }
161e41f4b71Sopenharmony_ci            //...
162e41f4b71Sopenharmony_ci          }
163e41f4b71Sopenharmony_ci          //...
164e41f4b71Sopenharmony_ci        }
165e41f4b71Sopenharmony_ci        //...
166e41f4b71Sopenharmony_ci      }
167e41f4b71Sopenharmony_ci    }
168e41f4b71Sopenharmony_ci    ```
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ci5. Call [stopServiceExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#uiabilitycontextstopserviceextensionability-1) to stop the [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) when it is no longer required on device B. (This API cannot be used to stop a [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md). Users must manually stop a UIAbility through mission management.)
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci    ```ts
173e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
174e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
175e41f4b71Sopenharmony_ci    import { Want, common } from '@kit.AbilityKit';
176e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
179e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
180e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
181e41f4b71Sopenharmony_ci
182e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
183e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
184e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
185e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
186e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
187e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
188e41f4b71Sopenharmony_ci          return;
189e41f4b71Sopenharmony_ci        }
190e41f4b71Sopenharmony_ci        if (list.length === 0) {
191e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
192e41f4b71Sopenharmony_ci          return;
193e41f4b71Sopenharmony_ci        }
194e41f4b71Sopenharmony_ci        return list[0].networkId;
195e41f4b71Sopenharmony_ci      } else {
196e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
197e41f4b71Sopenharmony_ci        return;
198e41f4b71Sopenharmony_ci      }
199e41f4b71Sopenharmony_ci    };
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci    @Entry
202e41f4b71Sopenharmony_ci    @Component
203e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
204e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci      build() {
207e41f4b71Sopenharmony_ci        // ...
208e41f4b71Sopenharmony_ci        Button('stopServiceExtensionAbility')
209e41f4b71Sopenharmony_ci          .onClick(() => {
210e41f4b71Sopenharmony_ci            let want: Want = {
211e41f4b71Sopenharmony_ci              deviceId: getRemoteDeviceId(),
212e41f4b71Sopenharmony_ci              bundleName: 'com.example.myapplication',
213e41f4b71Sopenharmony_ci              abilityName: 'FuncAbility',
214e41f4b71Sopenharmony_ci              moduleName: 'module1', // moduleName is optional.
215e41f4b71Sopenharmony_ci            }
216e41f4b71Sopenharmony_ci            // Stop the ServiceExtensionAbility started by calling startAbility().
217e41f4b71Sopenharmony_ci            this.context.stopServiceExtensionAbility(want).then(() => {
218e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, "stop service extension ability success")
219e41f4b71Sopenharmony_ci            }).catch((err: BusinessError) => {
220e41f4b71Sopenharmony_ci              hilog.error(DOMAIN_NUMBER, TAG, `stop service extension ability err is ` + JSON.stringify(err));
221e41f4b71Sopenharmony_ci            })
222e41f4b71Sopenharmony_ci          })
223e41f4b71Sopenharmony_ci      }
224e41f4b71Sopenharmony_ci    }
225e41f4b71Sopenharmony_ci    ```
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci## Starting UIAbility Across Devices (Data Returned)
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ciOn device A, touch the Start button provided by the initiator application to start a specified [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) on device B. When the UIAbility on device B exits, a value is returned to the initiator application.
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci### Available APIs
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci**Table 2** APIs for starting a UIAbility across devices and returning the result data
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci| API| Description|
237e41f4b71Sopenharmony_ci| -------- | -------- |
238e41f4b71Sopenharmony_ci| startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void; | Starts a UIAbility. This API uses an asynchronous callback to return the result when the UIAbility is terminated.|
239e41f4b71Sopenharmony_ci| terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void;| Terminates this UIAbility. This API uses an asynchronous callback to return the result. It is used together with **startAbilityForResult**.|
240e41f4b71Sopenharmony_ci| terminateSelfWithResult(parameter: AbilityResult): Promise<void>; | Terminates this UIAbility. This API uses a promise to return the result. It is used together with **startAbilityForResult**.|
241e41f4b71Sopenharmony_ci
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci### How to Develop
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci2. Display a dialog box to ask for authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md).
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ci3. Set the target component parameters on the initiator, and call [startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilityforresult) to start the target UIAbility. **data** in the asynchronous callback is used to receive the information returned by the target UIAbility to the initiator UIAbility after the target UIAbility terminates itself. For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci    ```ts
252e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
253e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
254e41f4b71Sopenharmony_ci    import { Want, common } from '@kit.AbilityKit';
255e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
256e41f4b71Sopenharmony_ci    import { promptAction } from '@kit.ArkUI';
257e41f4b71Sopenharmony_ci
258e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
259e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
260e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
261e41f4b71Sopenharmony_ci
262e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
263e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
264e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
265e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
266e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
267e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
268e41f4b71Sopenharmony_ci          return;
269e41f4b71Sopenharmony_ci        }
270e41f4b71Sopenharmony_ci        if (list.length === 0) {
271e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
272e41f4b71Sopenharmony_ci          return;
273e41f4b71Sopenharmony_ci        }
274e41f4b71Sopenharmony_ci        return list[0].networkId;
275e41f4b71Sopenharmony_ci      } else {
276e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
277e41f4b71Sopenharmony_ci        return;
278e41f4b71Sopenharmony_ci      }
279e41f4b71Sopenharmony_ci    };
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci    @Entry
282e41f4b71Sopenharmony_ci    @Component
283e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
284e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci      build() {
287e41f4b71Sopenharmony_ci        Column() {
288e41f4b71Sopenharmony_ci          //...
289e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
290e41f4b71Sopenharmony_ci            //...
291e41f4b71Sopenharmony_ci            ListItem() {
292e41f4b71Sopenharmony_ci              Row() {
293e41f4b71Sopenharmony_ci                //...
294e41f4b71Sopenharmony_ci              }
295e41f4b71Sopenharmony_ci              .onClick(() => {
296e41f4b71Sopenharmony_ci                let want: Want = {
297e41f4b71Sopenharmony_ci                  deviceId: getRemoteDeviceId(),
298e41f4b71Sopenharmony_ci                  bundleName: 'com.samples.stagemodelabilityinteraction',
299e41f4b71Sopenharmony_ci                  abilityName: 'ServiceExtAbility',
300e41f4b71Sopenharmony_ci                  moduleName: 'entry', // moduleName is optional.
301e41f4b71Sopenharmony_ci                };
302e41f4b71Sopenharmony_ci                // Stop the ServiceExtensionAbility started by calling startAbility().
303e41f4b71Sopenharmony_ci                this.context.stopServiceExtensionAbility(want).then(() => {
304e41f4b71Sopenharmony_ci                  hilog.info(DOMAIN_NUMBER, TAG, 'stop service extension ability success')
305e41f4b71Sopenharmony_ci                  promptAction.showToast({
306e41f4b71Sopenharmony_ci                    message: 'SuccessfullyStop'
307e41f4b71Sopenharmony_ci                  });
308e41f4b71Sopenharmony_ci                }).catch((err: BusinessError) => {
309e41f4b71Sopenharmony_ci                  hilog.error(DOMAIN_NUMBER, TAG, `stop service extension ability err is ` + JSON.stringify(err));
310e41f4b71Sopenharmony_ci                });
311e41f4b71Sopenharmony_ci              })
312e41f4b71Sopenharmony_ci            }
313e41f4b71Sopenharmony_ci            //...
314e41f4b71Sopenharmony_ci          }
315e41f4b71Sopenharmony_ci          //...
316e41f4b71Sopenharmony_ci        }
317e41f4b71Sopenharmony_ci        //...
318e41f4b71Sopenharmony_ci      }
319e41f4b71Sopenharmony_ci    }
320e41f4b71Sopenharmony_ci    ```
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ci4. After the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) mission on the target device is complete, call [terminateSelfWithResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextterminateselfwithresult) to return the data to the initiator UIAbility.
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci    ```ts
325e41f4b71Sopenharmony_ci    import { common } from '@kit.AbilityKit';
326e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
327e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
328e41f4b71Sopenharmony_ci
329e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
330e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_ci    @Entry
333e41f4b71Sopenharmony_ci    @Component
334e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
335e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
336e41f4b71Sopenharmony_ci
337e41f4b71Sopenharmony_ci      build() {
338e41f4b71Sopenharmony_ci        Column() {
339e41f4b71Sopenharmony_ci          //...
340e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
341e41f4b71Sopenharmony_ci            //...
342e41f4b71Sopenharmony_ci            ListItem() {
343e41f4b71Sopenharmony_ci              Row() {
344e41f4b71Sopenharmony_ci                //...
345e41f4b71Sopenharmony_ci              }
346e41f4b71Sopenharmony_ci              .onClick(() => {
347e41f4b71Sopenharmony_ci                const RESULT_CODE: number = 1001;
348e41f4b71Sopenharmony_ci                // context is the AbilityContext of the target UIAbility.
349e41f4b71Sopenharmony_ci                this.context.terminateSelfWithResult(
350e41f4b71Sopenharmony_ci                  {
351e41f4b71Sopenharmony_ci                    resultCode: RESULT_CODE,
352e41f4b71Sopenharmony_ci                    want: {
353e41f4b71Sopenharmony_ci                      bundleName: 'ohos.samples.stagemodelabilitydevelop',
354e41f4b71Sopenharmony_ci                      abilityName: 'CollaborateAbility',
355e41f4b71Sopenharmony_ci                      moduleName: 'entry',
356e41f4b71Sopenharmony_ci                      parameters: {
357e41f4b71Sopenharmony_ci                        info: 'From Page_CollaborateAbility'
358e41f4b71Sopenharmony_ci                      }
359e41f4b71Sopenharmony_ci                    }
360e41f4b71Sopenharmony_ci                  },
361e41f4b71Sopenharmony_ci                  (err: BusinessError) => {
362e41f4b71Sopenharmony_ci                    hilog.info(DOMAIN_NUMBER, TAG, `terminateSelfWithResult err: ` + JSON.stringify(err));
363e41f4b71Sopenharmony_ci                  });
364e41f4b71Sopenharmony_ci              })
365e41f4b71Sopenharmony_ci            }
366e41f4b71Sopenharmony_ci            //...
367e41f4b71Sopenharmony_ci          }
368e41f4b71Sopenharmony_ci          //...
369e41f4b71Sopenharmony_ci        }
370e41f4b71Sopenharmony_ci        //...
371e41f4b71Sopenharmony_ci      }
372e41f4b71Sopenharmony_ci    }
373e41f4b71Sopenharmony_ci    ```
374e41f4b71Sopenharmony_ci
375e41f4b71Sopenharmony_ci5. The initiator [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) receives the information returned by the target UIAbility and processes the information.
376e41f4b71Sopenharmony_ci
377e41f4b71Sopenharmony_ci    ```ts
378e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
379e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
380e41f4b71Sopenharmony_ci    import { Want, common } from '@kit.AbilityKit';
381e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
382e41f4b71Sopenharmony_ci    import { promptAction } from '@kit.ArkUI';
383e41f4b71Sopenharmony_ci
384e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
385e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
386e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
387e41f4b71Sopenharmony_ci
388e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
389e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
390e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
391e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
392e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
393e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
394e41f4b71Sopenharmony_ci          return;
395e41f4b71Sopenharmony_ci        }
396e41f4b71Sopenharmony_ci        if (list.length === 0) {
397e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
398e41f4b71Sopenharmony_ci          return;
399e41f4b71Sopenharmony_ci        }
400e41f4b71Sopenharmony_ci        return list[0].networkId;
401e41f4b71Sopenharmony_ci      } else {
402e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
403e41f4b71Sopenharmony_ci        return;
404e41f4b71Sopenharmony_ci      }
405e41f4b71Sopenharmony_ci    };
406e41f4b71Sopenharmony_ci
407e41f4b71Sopenharmony_ci    @Entry
408e41f4b71Sopenharmony_ci    @Component
409e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
410e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
411e41f4b71Sopenharmony_ci
412e41f4b71Sopenharmony_ci      build() {
413e41f4b71Sopenharmony_ci        Column() {
414e41f4b71Sopenharmony_ci          //...
415e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
416e41f4b71Sopenharmony_ci            //...
417e41f4b71Sopenharmony_ci            ListItem() {
418e41f4b71Sopenharmony_ci              Row() {
419e41f4b71Sopenharmony_ci                //...
420e41f4b71Sopenharmony_ci              }
421e41f4b71Sopenharmony_ci              .onClick(() => {
422e41f4b71Sopenharmony_ci                let want: Want = {
423e41f4b71Sopenharmony_ci                  deviceId: getRemoteDeviceId(),
424e41f4b71Sopenharmony_ci                  bundleName: 'com.samples.stagemodelabilityinteraction',
425e41f4b71Sopenharmony_ci                  abilityName: 'CollaborateAbility',
426e41f4b71Sopenharmony_ci                  moduleName: 'entry', // moduleName is optional.
427e41f4b71Sopenharmony_ci                };
428e41f4b71Sopenharmony_ci                const RESULT_CODE: number = 1001;
429e41f4b71Sopenharmony_ci                // context is the UIAbilityContext of the initiator UIAbility.
430e41f4b71Sopenharmony_ci                this.context.startAbilityForResult(want).then((data) => {
431e41f4b71Sopenharmony_ci                  if (data?.resultCode === RESULT_CODE) {
432e41f4b71Sopenharmony_ci                    // Parse the information returned by the target UIAbility.
433e41f4b71Sopenharmony_ci                    let info = data.want?.parameters?.info;
434e41f4b71Sopenharmony_ci                    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
435e41f4b71Sopenharmony_ci                    if (info !== null) {
436e41f4b71Sopenharmony_ci                      promptAction.showToast({
437e41f4b71Sopenharmony_ci                        message: JSON.stringify(info)
438e41f4b71Sopenharmony_ci                      });
439e41f4b71Sopenharmony_ci                    }
440e41f4b71Sopenharmony_ci                  }
441e41f4b71Sopenharmony_ci                }).catch((error: BusinessError) => {
442e41f4b71Sopenharmony_ci                  hilog.error(DOMAIN_NUMBER, TAG, `startAbilityForResult err: ` + JSON.stringify(error));
443e41f4b71Sopenharmony_ci                });
444e41f4b71Sopenharmony_ci              })
445e41f4b71Sopenharmony_ci            }
446e41f4b71Sopenharmony_ci            //...
447e41f4b71Sopenharmony_ci          }
448e41f4b71Sopenharmony_ci          //...
449e41f4b71Sopenharmony_ci        }
450e41f4b71Sopenharmony_ci        //...
451e41f4b71Sopenharmony_ci      }
452e41f4b71Sopenharmony_ci    }
453e41f4b71Sopenharmony_ci    ```
454e41f4b71Sopenharmony_ci
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci## Connecting to ServiceExtensionAbility Across Devices
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ciA system application can connect to a service on another device by calling [connectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability). For example, in the distributed game scenario, a tablet is used as the remote control and a smart TV is used as the display.
459e41f4b71Sopenharmony_ci
460e41f4b71Sopenharmony_ci
461e41f4b71Sopenharmony_ci### Available APIs
462e41f4b71Sopenharmony_ci
463e41f4b71Sopenharmony_ci**Table 3** APIs for cross-device connection
464e41f4b71Sopenharmony_ci
465e41f4b71Sopenharmony_ci| API| Description|
466e41f4b71Sopenharmony_ci| -------- | -------- |
467e41f4b71Sopenharmony_ci| connectServiceExtensionAbility(want: Want, options: ConnectOptions): number; | Connects to a ServiceExtensionAbility.|
468e41f4b71Sopenharmony_ci| disconnectServiceExtensionAbility(connection: number, callback: AsyncCallback<void>): void; | Disconnects a connection. This API uses an asynchronous callback to return the result.|
469e41f4b71Sopenharmony_ci| disconnectServiceExtensionAbility(connection: number): Promise<void>; | Disconnects a connection. This API uses a promise to return the result.|
470e41f4b71Sopenharmony_ci
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ci### How to Develop
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ci2. Display a dialog box to ask for authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md).
477e41f4b71Sopenharmony_ci
478e41f4b71Sopenharmony_ci3. (Optional) [Implement a background service](serviceextensionability.md#implementing-a-background-service-for-system-applications-only). Perform this operation only if no background service is available. This operation is available only for system applications.
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ci4. Connect to the background service.
481e41f4b71Sopenharmony_ci   - Implement the **IAbilityConnection** class. **IAbilityConnection** provides the following callbacks that you should implement: [onConnect()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#onconnect), [onDisconnect()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#ondisconnect), and [onFailed()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#onfailed). The **onConnect()** callback is invoked when a service is connected, **onDisconnect()** is invoked when a service is unexpectedly disconnected, and **onFailed()** is invoked when the connection to a service fails.
482e41f4b71Sopenharmony_ci   - Set the target component parameters, including the target device ID, bundle name, and ability name.
483e41f4b71Sopenharmony_ci   - Call **connectServiceExtensionAbility()** to initiate a connection.
484e41f4b71Sopenharmony_ci   - Receive the service handle returned by the target device when the connection is successful.
485e41f4b71Sopenharmony_ci   - Perform cross-device call and obtain the result returned by the target service.
486e41f4b71Sopenharmony_ci     
487e41f4b71Sopenharmony_ci    ```ts
488e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
489e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
490e41f4b71Sopenharmony_ci    import { Want, common } from '@kit.AbilityKit';
491e41f4b71Sopenharmony_ci    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
492e41f4b71Sopenharmony_ci    import { rpc } from '@kit.IPCKit';
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
495e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
496e41f4b71Sopenharmony_ci    const REQUEST_CODE = 1;
497e41f4b71Sopenharmony_ci    let dmClass: distributedDeviceManager.DeviceManager;
498e41f4b71Sopenharmony_ci    let connectionId: number;
499e41f4b71Sopenharmony_ci    let options: common.ConnectOptions = {
500e41f4b71Sopenharmony_ci      onConnect(elementName, remote): void {
501e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
502e41f4b71Sopenharmony_ci        if (remote === null) {
503e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
504e41f4b71Sopenharmony_ci          return;
505e41f4b71Sopenharmony_ci        }
506e41f4b71Sopenharmony_ci        let option = new rpc.MessageOption();
507e41f4b71Sopenharmony_ci        let data = new rpc.MessageSequence();
508e41f4b71Sopenharmony_ci        let reply = new rpc.MessageSequence();
509e41f4b71Sopenharmony_ci        data.writeInt(99); // You can send data to the target application for corresponding operations.
510e41f4b71Sopenharmony_ci        // @param code Indicates the service request code sent by the client.
511e41f4b71Sopenharmony_ci        // @param data Indicates the {@link MessageSequence} object sent by the client.
512e41f4b71Sopenharmony_ci        // @param reply Indicates the response message object sent by the remote service.
513e41f4b71Sopenharmony_ci        // @param options Specifies whether the operation is synchronous or asynchronous.
514e41f4b71Sopenharmony_ci        //
515e41f4b71Sopenharmony_ci        // @return Returns {@code true} if the operation is successful; returns {@code false} otherwise.
516e41f4b71Sopenharmony_ci        remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
517e41f4b71Sopenharmony_ci          let errCode = reply.readInt(); // Receive the information (100) returned by the target device if the connection is successful.
518e41f4b71Sopenharmony_ci          let msg: number = 0;
519e41f4b71Sopenharmony_ci          if (errCode === 0) {
520e41f4b71Sopenharmony_ci            msg = reply.readInt();
521e41f4b71Sopenharmony_ci          }
522e41f4b71Sopenharmony_ci          // The background service is connected.
523e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `sendRequest msg:${msg}`);
524e41f4b71Sopenharmony_ci        }).catch((error: BusinessError) => {
525e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`);
526e41f4b71Sopenharmony_ci        });
527e41f4b71Sopenharmony_ci      },
528e41f4b71Sopenharmony_ci      onDisconnect(elementName): void {
529e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
530e41f4b71Sopenharmony_ci      },
531e41f4b71Sopenharmony_ci      onFailed(code): void {
532e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback');
533e41f4b71Sopenharmony_ci      }
534e41f4b71Sopenharmony_ci    };
535e41f4b71Sopenharmony_ci
536e41f4b71Sopenharmony_ci    function getRemoteDeviceId(): string | undefined {
537e41f4b71Sopenharmony_ci      if (typeof dmClass === 'object' && dmClass !== null) {
538e41f4b71Sopenharmony_ci        let list = dmClass.getAvailableDeviceListSync();
539e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
540e41f4b71Sopenharmony_ci        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
541e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
542e41f4b71Sopenharmony_ci          return;
543e41f4b71Sopenharmony_ci        }
544e41f4b71Sopenharmony_ci        if (list.length === 0) {
545e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
546e41f4b71Sopenharmony_ci          return;
547e41f4b71Sopenharmony_ci        }
548e41f4b71Sopenharmony_ci        return list[0].networkId;
549e41f4b71Sopenharmony_ci      } else {
550e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
551e41f4b71Sopenharmony_ci        return;
552e41f4b71Sopenharmony_ci      }
553e41f4b71Sopenharmony_ci    }
554e41f4b71Sopenharmony_ci
555e41f4b71Sopenharmony_ci    @Entry
556e41f4b71Sopenharmony_ci    @Component
557e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
558e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
559e41f4b71Sopenharmony_ci
560e41f4b71Sopenharmony_ci      build() {
561e41f4b71Sopenharmony_ci        Column() {
562e41f4b71Sopenharmony_ci          //...
563e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
564e41f4b71Sopenharmony_ci            //...
565e41f4b71Sopenharmony_ci            ListItem() {
566e41f4b71Sopenharmony_ci              Row() {
567e41f4b71Sopenharmony_ci                //...
568e41f4b71Sopenharmony_ci              }
569e41f4b71Sopenharmony_ci              .onClick(() => {
570e41f4b71Sopenharmony_ci                let want: Want = {
571e41f4b71Sopenharmony_ci                  'deviceId': getRemoteDeviceId(),
572e41f4b71Sopenharmony_ci                  'bundleName': 'com.samples.stagemodelabilityinteraction',
573e41f4b71Sopenharmony_ci                  'abilityName': 'ServiceExtAbility'
574e41f4b71Sopenharmony_ci                };
575e41f4b71Sopenharmony_ci                // The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection.
576e41f4b71Sopenharmony_ci                connectionId = this.context.connectServiceExtensionAbility(want, options);
577e41f4b71Sopenharmony_ci              })
578e41f4b71Sopenharmony_ci            }
579e41f4b71Sopenharmony_ci            //...
580e41f4b71Sopenharmony_ci          }
581e41f4b71Sopenharmony_ci          //...
582e41f4b71Sopenharmony_ci        }
583e41f4b71Sopenharmony_ci        //...
584e41f4b71Sopenharmony_ci      }
585e41f4b71Sopenharmony_ci    }
586e41f4b71Sopenharmony_ci    ```
587e41f4b71Sopenharmony_ci
588e41f4b71Sopenharmony_ci    For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
589e41f4b71Sopenharmony_ci
590e41f4b71Sopenharmony_ci5. Disconnect the connection. Use [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextdisconnectserviceextensionability) to disconnect from the background service.
591e41f4b71Sopenharmony_ci
592e41f4b71Sopenharmony_ci    ```ts
593e41f4b71Sopenharmony_ci    import { BusinessError } from '@kit.BasicServicesKit';
594e41f4b71Sopenharmony_ci    import { hilog } from '@kit.PerformanceAnalysisKit';
595e41f4b71Sopenharmony_ci    import { common } from '@kit.AbilityKit';
596e41f4b71Sopenharmony_ci    import { promptAction } from '@kit.ArkUI';
597e41f4b71Sopenharmony_ci
598e41f4b71Sopenharmony_ci    let connectionId: number;
599e41f4b71Sopenharmony_ci    const TAG: string = '[Page_CollaborateAbility]';
600e41f4b71Sopenharmony_ci    const DOMAIN_NUMBER: number = 0xFF00;
601e41f4b71Sopenharmony_ci
602e41f4b71Sopenharmony_ci    @Entry
603e41f4b71Sopenharmony_ci    @Component
604e41f4b71Sopenharmony_ci    struct Page_CollaborateAbility {
605e41f4b71Sopenharmony_ci      private context = getContext(this) as common.UIAbilityContext;
606e41f4b71Sopenharmony_ci
607e41f4b71Sopenharmony_ci      build() {
608e41f4b71Sopenharmony_ci        Column() {
609e41f4b71Sopenharmony_ci          //...
610e41f4b71Sopenharmony_ci          List({ initialIndex: 0 }) {
611e41f4b71Sopenharmony_ci            //...
612e41f4b71Sopenharmony_ci            ListItem() {
613e41f4b71Sopenharmony_ci              Row() {
614e41f4b71Sopenharmony_ci                //...
615e41f4b71Sopenharmony_ci              }
616e41f4b71Sopenharmony_ci              .onClick(() => {
617e41f4b71Sopenharmony_ci                this.context.disconnectServiceExtensionAbility(connectionId).then(() => {
618e41f4b71Sopenharmony_ci                  hilog.info(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility success');
619e41f4b71Sopenharmony_ci                  // The background service is disconnected.
620e41f4b71Sopenharmony_ci                  promptAction.showToast({
621e41f4b71Sopenharmony_ci                    message: 'SuccessfullyDisconnectBackendService'
622e41f4b71Sopenharmony_ci                  })
623e41f4b71Sopenharmony_ci                }).catch((error: BusinessError) => {
624e41f4b71Sopenharmony_ci                  hilog.error(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility failed');
625e41f4b71Sopenharmony_ci                });
626e41f4b71Sopenharmony_ci              })
627e41f4b71Sopenharmony_ci            }
628e41f4b71Sopenharmony_ci            //...
629e41f4b71Sopenharmony_ci          }
630e41f4b71Sopenharmony_ci          //...
631e41f4b71Sopenharmony_ci        }
632e41f4b71Sopenharmony_ci        //...
633e41f4b71Sopenharmony_ci      }
634e41f4b71Sopenharmony_ci    }
635e41f4b71Sopenharmony_ci    ```
636e41f4b71Sopenharmony_ci
637e41f4b71Sopenharmony_ci
638e41f4b71Sopenharmony_ci## Using Cross-Device Call
639e41f4b71Sopenharmony_ci
640e41f4b71Sopenharmony_ciThe basic principle of cross-device call is the same as that of intra-device call. For details, see [Using Call to Implement UIAbility Interaction (for System Applications Only)](uiability-intra-device-interaction.md#using-call-to-implement-uiability-interaction-for-system-applications-only).
641e41f4b71Sopenharmony_ci
642e41f4b71Sopenharmony_ciThe following describes how to implement multi-device collaboration through cross-device call.
643e41f4b71Sopenharmony_ci
644e41f4b71Sopenharmony_ci
645e41f4b71Sopenharmony_ci### Available APIs
646e41f4b71Sopenharmony_ci
647e41f4b71Sopenharmony_ci**Table 4** Call APIs
648e41f4b71Sopenharmony_ci
649e41f4b71Sopenharmony_ci| API| Description|
650e41f4b71Sopenharmony_ci| -------- | -------- |
651e41f4b71Sopenharmony_ci| startAbilityByCall(want: Want): Promise<Caller>; | Starts a UIAbility in the foreground or background and obtains the caller object for communicating with the UIAbility.|
652e41f4b71Sopenharmony_ci| on(method: string, callback: CalleeCallBack): void | Callback invoked when the CalleeAbility registers a method.|
653e41f4b71Sopenharmony_ci| off(method: string): void | Callback invoked when the CalleeAbility deregisters a method.|
654e41f4b71Sopenharmony_ci| call(method: string, data: rpc.Parcelable): Promise<void> | Sends agreed parcelable data to the CalleeAbility.|
655e41f4b71Sopenharmony_ci| callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence>| Sends agreed parcelable data to the CalleeAbility and obtains the agreed parcelable data returned by the CalleeAbility.|
656e41f4b71Sopenharmony_ci| release(): void | Releases the caller object.|
657e41f4b71Sopenharmony_ci| on(type: "release", callback: OnReleaseCallback): void | Callback invoked when the caller object is released.|
658e41f4b71Sopenharmony_ci
659e41f4b71Sopenharmony_ci
660e41f4b71Sopenharmony_ci### How to Develop
661e41f4b71Sopenharmony_ci
662e41f4b71Sopenharmony_ci1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
663e41f4b71Sopenharmony_ci
664e41f4b71Sopenharmony_ci2. Display a dialog box to ask for authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md).
665e41f4b71Sopenharmony_ci
666e41f4b71Sopenharmony_ci3. Create the CalleeAbility.
667e41f4b71Sopenharmony_ci
668e41f4b71Sopenharmony_ci   For the CalleeAbility, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use [on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeon) to register a listener. When data does not need to be received, use [off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeoff) to deregister the listener.
669e41f4b71Sopenharmony_ci
670e41f4b71Sopenharmony_ci    1. Configure the launch type of the UIAbility.
671e41f4b71Sopenharmony_ci
672e41f4b71Sopenharmony_ci        Set **launchType** of the CalleeAbility to **singleton** in the [module.json5](../quick-start/module-configuration-file.md) file.
673e41f4b71Sopenharmony_ci
674e41f4b71Sopenharmony_ci        | JSON Field| Description|
675e41f4b71Sopenharmony_ci        | -------- | -------- |
676e41f4b71Sopenharmony_ci        | "launchType"| UIAbility launch type. Set this parameter to **singleton**.|
677e41f4b71Sopenharmony_ci
678e41f4b71Sopenharmony_ci        An example of the UIAbility configuration is as follows:
679e41f4b71Sopenharmony_ci
680e41f4b71Sopenharmony_ci        ```json
681e41f4b71Sopenharmony_ci        "abilities":[{
682e41f4b71Sopenharmony_ci            "name": ".CalleeAbility",
683e41f4b71Sopenharmony_ci            "srcEntry": "./ets/CalleeAbility/CalleeAbility.ets",
684e41f4b71Sopenharmony_ci            "launchType": "singleton",
685e41f4b71Sopenharmony_ci            "description": "$string:CalleeAbility_desc",
686e41f4b71Sopenharmony_ci            "icon": "$media:icon",
687e41f4b71Sopenharmony_ci            "label": "$string:CalleeAbility_label",
688e41f4b71Sopenharmony_ci            "exported": true
689e41f4b71Sopenharmony_ci        }]
690e41f4b71Sopenharmony_ci        ```
691e41f4b71Sopenharmony_ci    2. Import the **UIAbility** module.
692e41f4b71Sopenharmony_ci
693e41f4b71Sopenharmony_ci        ```ts
694e41f4b71Sopenharmony_ci        import { UIAbility } from '@kit.AbilityKit';
695e41f4b71Sopenharmony_ci        ```
696e41f4b71Sopenharmony_ci    3. Define the agreed parcelable data.
697e41f4b71Sopenharmony_ci
698e41f4b71Sopenharmony_ci        The data formats sent and received by the CallerAbility and CalleeAbility must be consistent. In the following example, the data formats are number and string.
699e41f4b71Sopenharmony_ci
700e41f4b71Sopenharmony_ci         
701e41f4b71Sopenharmony_ci        ```ts
702e41f4b71Sopenharmony_ci        import { rpc } from '@kit.IPCKit';
703e41f4b71Sopenharmony_ci
704e41f4b71Sopenharmony_ci        class MyParcelable {
705e41f4b71Sopenharmony_ci          num: number = 0;
706e41f4b71Sopenharmony_ci          str: string = '';
707e41f4b71Sopenharmony_ci
708e41f4b71Sopenharmony_ci          constructor(num: number, string: string) {
709e41f4b71Sopenharmony_ci            this.num = num;
710e41f4b71Sopenharmony_ci            this.str = string;
711e41f4b71Sopenharmony_ci          }
712e41f4b71Sopenharmony_ci
713e41f4b71Sopenharmony_ci          mySequenceable(num: number, string: string): void {
714e41f4b71Sopenharmony_ci            this.num = num;
715e41f4b71Sopenharmony_ci            this.str = string;
716e41f4b71Sopenharmony_ci          }
717e41f4b71Sopenharmony_ci
718e41f4b71Sopenharmony_ci          marshalling(messageSequence: rpc.MessageSequence): boolean {
719e41f4b71Sopenharmony_ci            messageSequence.writeInt(this.num);
720e41f4b71Sopenharmony_ci            messageSequence.writeString(this.str);
721e41f4b71Sopenharmony_ci            return true;
722e41f4b71Sopenharmony_ci          };
723e41f4b71Sopenharmony_ci
724e41f4b71Sopenharmony_ci          unmarshalling(messageSequence: rpc.MessageSequence): boolean {
725e41f4b71Sopenharmony_ci            this.num = messageSequence.readInt();
726e41f4b71Sopenharmony_ci            this.str = messageSequence.readString();
727e41f4b71Sopenharmony_ci            return true;
728e41f4b71Sopenharmony_ci          };
729e41f4b71Sopenharmony_ci        }
730e41f4b71Sopenharmony_ci        ```
731e41f4b71Sopenharmony_ci    4. Implement [Callee.on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeon) and [Callee.off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeoff).
732e41f4b71Sopenharmony_ci
733e41f4b71Sopenharmony_ci        In the following example, the **MSG_SEND_METHOD** listener is registered in [onCreate](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityoncreate) of the UIAbility and deregistered in [onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityondestroy). After receiving parcelable data, the application processes the data and returns the data result. You need to implement processing based on service requirements.
734e41f4b71Sopenharmony_ci           
735e41f4b71Sopenharmony_ci        ```ts
736e41f4b71Sopenharmony_ci        import { AbilityConstant, UIAbility, Want, Caller } from '@kit.AbilityKit';
737e41f4b71Sopenharmony_ci        import { hilog } from '@kit.PerformanceAnalysisKit';
738e41f4b71Sopenharmony_ci        import { rpc } from '@kit.IPCKit';
739e41f4b71Sopenharmony_ci
740e41f4b71Sopenharmony_ci
741e41f4b71Sopenharmony_ci        const TAG: string = '[CalleeAbility]';
742e41f4b71Sopenharmony_ci        const MSG_SEND_METHOD: string = 'CallSendMsg';
743e41f4b71Sopenharmony_ci        const DOMAIN_NUMBER: number = 0xFF00;
744e41f4b71Sopenharmony_ci
745e41f4b71Sopenharmony_ci        class MyParcelable {
746e41f4b71Sopenharmony_ci          num: number = 0;
747e41f4b71Sopenharmony_ci          str: string = '';
748e41f4b71Sopenharmony_ci
749e41f4b71Sopenharmony_ci          constructor(num: number, string: string) {
750e41f4b71Sopenharmony_ci            this.num = num;
751e41f4b71Sopenharmony_ci            this.str = string;
752e41f4b71Sopenharmony_ci          };
753e41f4b71Sopenharmony_ci
754e41f4b71Sopenharmony_ci          mySequenceable(num: number, string: string): void {
755e41f4b71Sopenharmony_ci            this.num = num;
756e41f4b71Sopenharmony_ci            this.str = string;
757e41f4b71Sopenharmony_ci          };
758e41f4b71Sopenharmony_ci
759e41f4b71Sopenharmony_ci          marshalling(messageSequence: rpc.MessageSequence): boolean {
760e41f4b71Sopenharmony_ci            messageSequence.writeInt(this.num);
761e41f4b71Sopenharmony_ci            messageSequence.writeString(this.str);
762e41f4b71Sopenharmony_ci            return true;
763e41f4b71Sopenharmony_ci          };
764e41f4b71Sopenharmony_ci
765e41f4b71Sopenharmony_ci          unmarshalling(messageSequence: rpc.MessageSequence): boolean {
766e41f4b71Sopenharmony_ci            this.num = messageSequence.readInt();
767e41f4b71Sopenharmony_ci            this.str = messageSequence.readString();
768e41f4b71Sopenharmony_ci            return true;
769e41f4b71Sopenharmony_ci          };
770e41f4b71Sopenharmony_ci        }
771e41f4b71Sopenharmony_ci
772e41f4b71Sopenharmony_ci        function sendMsgCallback(data: rpc.MessageSequence): rpc.Parcelable {
773e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'CalleeSortFunc called');
774e41f4b71Sopenharmony_ci
775e41f4b71Sopenharmony_ci          // Obtain the parcelable data sent by the CallerAbility.
776e41f4b71Sopenharmony_ci          let receivedData: MyParcelable = new MyParcelable(0, '');
777e41f4b71Sopenharmony_ci          data.readParcelable(receivedData);
778e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `receiveData[${receivedData.num}, ${receivedData.str}]`);
779e41f4b71Sopenharmony_ci          let num: number = receivedData.num;
780e41f4b71Sopenharmony_ci
781e41f4b71Sopenharmony_ci          // Process the data.
782e41f4b71Sopenharmony_ci          // Return the parcelable data result to the CallerAbility.
783e41f4b71Sopenharmony_ci          return new MyParcelable(num + 1, `send ${receivedData.str} succeed`) as rpc.Parcelable;
784e41f4b71Sopenharmony_ci        };
785e41f4b71Sopenharmony_ci
786e41f4b71Sopenharmony_ci        export default class CalleeAbility extends UIAbility {
787e41f4b71Sopenharmony_ci          caller: Caller | undefined;
788e41f4b71Sopenharmony_ci
789e41f4b71Sopenharmony_ci          onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
790e41f4b71Sopenharmony_ci            try {
791e41f4b71Sopenharmony_ci              this.callee.on(MSG_SEND_METHOD, sendMsgCallback);
792e41f4b71Sopenharmony_ci            } catch (error) {
793e41f4b71Sopenharmony_ci              hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`);
794e41f4b71Sopenharmony_ci            }
795e41f4b71Sopenharmony_ci          }
796e41f4b71Sopenharmony_ci
797e41f4b71Sopenharmony_ci          //...
798e41f4b71Sopenharmony_ci          releaseCall(): void {
799e41f4b71Sopenharmony_ci            try {
800e41f4b71Sopenharmony_ci              if (this.caller) {
801e41f4b71Sopenharmony_ci                this.caller.release();
802e41f4b71Sopenharmony_ci                this.caller = undefined;
803e41f4b71Sopenharmony_ci              }
804e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, 'caller release succeed');
805e41f4b71Sopenharmony_ci            } catch (error) {
806e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, `caller release failed with ${error}`);
807e41f4b71Sopenharmony_ci            }
808e41f4b71Sopenharmony_ci          }
809e41f4b71Sopenharmony_ci
810e41f4b71Sopenharmony_ci          //...
811e41f4b71Sopenharmony_ci          onDestroy(): void {
812e41f4b71Sopenharmony_ci            try {
813e41f4b71Sopenharmony_ci              this.callee.off(MSG_SEND_METHOD);
814e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Callee OnDestroy');
815e41f4b71Sopenharmony_ci              this.releaseCall();
816e41f4b71Sopenharmony_ci            } catch (error) {
817e41f4b71Sopenharmony_ci              hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`);
818e41f4b71Sopenharmony_ci            }
819e41f4b71Sopenharmony_ci          }
820e41f4b71Sopenharmony_ci        }
821e41f4b71Sopenharmony_ci        ```
822e41f4b71Sopenharmony_ci     
823e41f4b71Sopenharmony_ci4. Obtain the caller object and access the CalleeAbility.
824e41f4b71Sopenharmony_ci    1. Import the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) module.
825e41f4b71Sopenharmony_ci      
826e41f4b71Sopenharmony_ci        ```ts
827e41f4b71Sopenharmony_ci        import { UIAbility } from '@kit.AbilityKit';
828e41f4b71Sopenharmony_ci        ```
829e41f4b71Sopenharmony_ci    2. Obtain the caller object.
830e41f4b71Sopenharmony_ci
831e41f4b71Sopenharmony_ci        The **context** attribute of the UIAbility implements [startAbilityByCall](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilitybycall) to obtain the [Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller) object for communication. The following example uses **this.context** to obtain the **context** attribute of the UIAbility, uses **startAbilityByCall** to start [Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee), obtain the Caller object, and register the [onRelease](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleronrelease) and [onRemoteStateChange](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleronremotestatechange10) listeners of the CallerAbility. You need to implement processing based on service requirements.
832e41f4b71Sopenharmony_ci
833e41f4b71Sopenharmony_ci        ```ts
834e41f4b71Sopenharmony_ci        import { BusinessError } from '@kit.BasicServicesKit';
835e41f4b71Sopenharmony_ci        import { Caller, common } from '@kit.AbilityKit';
836e41f4b71Sopenharmony_ci        import { hilog } from '@kit.PerformanceAnalysisKit';
837e41f4b71Sopenharmony_ci        import { distributedDeviceManager } from '@kit.DistributedServiceKit';
838e41f4b71Sopenharmony_ci        import { promptAction } from '@kit.ArkUI';
839e41f4b71Sopenharmony_ci
840e41f4b71Sopenharmony_ci
841e41f4b71Sopenharmony_ci        const TAG: string = '[Page_CollaborateAbility]';
842e41f4b71Sopenharmony_ci        const DOMAIN_NUMBER: number = 0xFF00;
843e41f4b71Sopenharmony_ci        let caller: Caller | undefined;
844e41f4b71Sopenharmony_ci        let dmClass: distributedDeviceManager.DeviceManager;
845e41f4b71Sopenharmony_ci
846e41f4b71Sopenharmony_ci        function getRemoteDeviceId(): string | undefined {
847e41f4b71Sopenharmony_ci          if (typeof dmClass === 'object' && dmClass !== null) {
848e41f4b71Sopenharmony_ci            let list = dmClass.getAvailableDeviceListSync();
849e41f4b71Sopenharmony_ci            hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
850e41f4b71Sopenharmony_ci            if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
851e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');
852e41f4b71Sopenharmony_ci              return;
853e41f4b71Sopenharmony_ci            }
854e41f4b71Sopenharmony_ci            if (list.length === 0) {
855e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);
856e41f4b71Sopenharmony_ci              return;
857e41f4b71Sopenharmony_ci            }
858e41f4b71Sopenharmony_ci            return list[0].networkId;
859e41f4b71Sopenharmony_ci          } else {
860e41f4b71Sopenharmony_ci            hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');
861e41f4b71Sopenharmony_ci            return;
862e41f4b71Sopenharmony_ci          }
863e41f4b71Sopenharmony_ci        };
864e41f4b71Sopenharmony_ci
865e41f4b71Sopenharmony_ci        @Entry
866e41f4b71Sopenharmony_ci        @Component
867e41f4b71Sopenharmony_ci        struct Page_CollaborateAbility {
868e41f4b71Sopenharmony_ci          private context = getContext(this) as common.UIAbilityContext;
869e41f4b71Sopenharmony_ci
870e41f4b71Sopenharmony_ci          build() {
871e41f4b71Sopenharmony_ci            Column() {
872e41f4b71Sopenharmony_ci              //...
873e41f4b71Sopenharmony_ci              List({ initialIndex: 0 }) {
874e41f4b71Sopenharmony_ci                //...
875e41f4b71Sopenharmony_ci                ListItem() {
876e41f4b71Sopenharmony_ci                  Row() {
877e41f4b71Sopenharmony_ci                    //...
878e41f4b71Sopenharmony_ci                  }
879e41f4b71Sopenharmony_ci                  .onClick(() => {
880e41f4b71Sopenharmony_ci                    let caller: Caller | undefined;
881e41f4b71Sopenharmony_ci                    let context = this.context;
882e41f4b71Sopenharmony_ci
883e41f4b71Sopenharmony_ci                    context.startAbilityByCall({
884e41f4b71Sopenharmony_ci                      deviceId: getRemoteDeviceId(),
885e41f4b71Sopenharmony_ci                      bundleName: 'com.samples.stagemodelabilityinteraction',
886e41f4b71Sopenharmony_ci                      abilityName: 'CalleeAbility'
887e41f4b71Sopenharmony_ci                    }).then((data) => {
888e41f4b71Sopenharmony_ci                      if (data !== null) {
889e41f4b71Sopenharmony_ci                        caller = data;
890e41f4b71Sopenharmony_ci                        hilog.info(DOMAIN_NUMBER, TAG, 'get remote caller success');
891e41f4b71Sopenharmony_ci                        // Register the onRelease listener of the CallerAbility.
892e41f4b71Sopenharmony_ci                        caller.onRelease((msg) => {
893e41f4b71Sopenharmony_ci                          hilog.info(DOMAIN_NUMBER, TAG, `remote caller onRelease is called ${msg}`);
894e41f4b71Sopenharmony_ci                        });
895e41f4b71Sopenharmony_ci                        hilog.info(DOMAIN_NUMBER, TAG, 'remote caller register OnRelease succeed');
896e41f4b71Sopenharmony_ci                        promptAction.showToast({
897e41f4b71Sopenharmony_ci                          message: 'CallerSuccess'
898e41f4b71Sopenharmony_ci                        });
899e41f4b71Sopenharmony_ci                        // Register the onRemoteStateChange listener of the CallerAbility.
900e41f4b71Sopenharmony_ci                        try {
901e41f4b71Sopenharmony_ci                          caller.onRemoteStateChange((str) => {
902e41f4b71Sopenharmony_ci                            hilog.info(DOMAIN_NUMBER, TAG, 'Remote state changed ' + str);
903e41f4b71Sopenharmony_ci                          });
904e41f4b71Sopenharmony_ci                        } catch (error) {
905e41f4b71Sopenharmony_ci                          hilog.info(DOMAIN_NUMBER, TAG, `Caller.onRemoteStateChange catch error, error.code: ${JSON.stringify(error.code)}, error.message: ${JSON.stringify(error.message)}`);
906e41f4b71Sopenharmony_ci                        }
907e41f4b71Sopenharmony_ci                      }
908e41f4b71Sopenharmony_ci                    }).catch((error: BusinessError) => {
909e41f4b71Sopenharmony_ci                      hilog.error(DOMAIN_NUMBER, TAG, `get remote caller failed with ${error}`);
910e41f4b71Sopenharmony_ci                    });
911e41f4b71Sopenharmony_ci                  })
912e41f4b71Sopenharmony_ci                }
913e41f4b71Sopenharmony_ci                //...
914e41f4b71Sopenharmony_ci              }
915e41f4b71Sopenharmony_ci              //...
916e41f4b71Sopenharmony_ci            }
917e41f4b71Sopenharmony_ci            //...
918e41f4b71Sopenharmony_ci          }
919e41f4b71Sopenharmony_ci        }
920e41f4b71Sopenharmony_ci        ```
921e41f4b71Sopenharmony_ci       
922e41f4b71Sopenharmony_ci        For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
923e41f4b71Sopenharmony_ci
924e41f4b71Sopenharmony_ci5. Sends agreed parcelable data to the CalleeAbility.
925e41f4b71Sopenharmony_ci    1. The parcelable data can be sent to the CalleeAbility with or without a return value. The method and parcelable data must be consistent with those of the CalleeAbility. The following example describes how to use [Call](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callercall) to send data to [Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee).
926e41f4b71Sopenharmony_ci      
927e41f4b71Sopenharmony_ci        ```ts
928e41f4b71Sopenharmony_ci        import { UIAbility, Caller } from '@kit.AbilityKit';
929e41f4b71Sopenharmony_ci        import { rpc } from '@kit.IPCKit';
930e41f4b71Sopenharmony_ci        import { hilog } from '@kit.PerformanceAnalysisKit';
931e41f4b71Sopenharmony_ci
932e41f4b71Sopenharmony_ci        const TAG: string = '[CalleeAbility]';
933e41f4b71Sopenharmony_ci        const DOMAIN_NUMBER: number = 0xFF00;
934e41f4b71Sopenharmony_ci        const MSG_SEND_METHOD: string = 'CallSendMsg';
935e41f4b71Sopenharmony_ci
936e41f4b71Sopenharmony_ci        class MyParcelable {
937e41f4b71Sopenharmony_ci          num: number = 0;
938e41f4b71Sopenharmony_ci          str: string = '';
939e41f4b71Sopenharmony_ci
940e41f4b71Sopenharmony_ci          constructor(num: number, string: string) {
941e41f4b71Sopenharmony_ci            this.num = num;
942e41f4b71Sopenharmony_ci            this.str = string;
943e41f4b71Sopenharmony_ci          };
944e41f4b71Sopenharmony_ci
945e41f4b71Sopenharmony_ci          mySequenceable(num: number, string: string): void {
946e41f4b71Sopenharmony_ci            this.num = num;
947e41f4b71Sopenharmony_ci            this.str = string;
948e41f4b71Sopenharmony_ci          };
949e41f4b71Sopenharmony_ci
950e41f4b71Sopenharmony_ci          marshalling(messageSequence: rpc.MessageSequence): boolean {
951e41f4b71Sopenharmony_ci            messageSequence.writeInt(this.num);
952e41f4b71Sopenharmony_ci            messageSequence.writeString(this.str);
953e41f4b71Sopenharmony_ci            return true;
954e41f4b71Sopenharmony_ci          };
955e41f4b71Sopenharmony_ci
956e41f4b71Sopenharmony_ci          unmarshalling(messageSequence: rpc.MessageSequence): boolean {
957e41f4b71Sopenharmony_ci            this.num = messageSequence.readInt();
958e41f4b71Sopenharmony_ci            this.str = messageSequence.readString();
959e41f4b71Sopenharmony_ci            return true;
960e41f4b71Sopenharmony_ci          };
961e41f4b71Sopenharmony_ci        }
962e41f4b71Sopenharmony_ci
963e41f4b71Sopenharmony_ci        export default class EntryAbility extends UIAbility {
964e41f4b71Sopenharmony_ci          // ...
965e41f4b71Sopenharmony_ci          caller: Caller | undefined;
966e41f4b71Sopenharmony_ci
967e41f4b71Sopenharmony_ci          async onButtonCall(): Promise<void> {
968e41f4b71Sopenharmony_ci            try {
969e41f4b71Sopenharmony_ci              let msg: MyParcelable = new MyParcelable(1, 'origin_Msg');
970e41f4b71Sopenharmony_ci              if (this.caller) {
971e41f4b71Sopenharmony_ci                await this.caller.call(MSG_SEND_METHOD, msg);
972e41f4b71Sopenharmony_ci              }
973e41f4b71Sopenharmony_ci            } catch (error) {
974e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, `caller call failed with ${error}`);
975e41f4b71Sopenharmony_ci            }
976e41f4b71Sopenharmony_ci          }
977e41f4b71Sopenharmony_ci          // ...
978e41f4b71Sopenharmony_ci        }
979e41f4b71Sopenharmony_ci        ```
980e41f4b71Sopenharmony_ci    2. In the following, [CallWithResult](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callercallwithresult) is used to send data **originMsg** to the CalleeAbility and assign the data processed by the **CallSendMsg** method to **backMsg**.
981e41f4b71Sopenharmony_ci      
982e41f4b71Sopenharmony_ci        ```ts
983e41f4b71Sopenharmony_ci        import { UIAbility, Caller } from '@kit.AbilityKit';
984e41f4b71Sopenharmony_ci        import { rpc } from '@kit.IPCKit';
985e41f4b71Sopenharmony_ci        import { hilog } from '@kit.PerformanceAnalysisKit';
986e41f4b71Sopenharmony_ci
987e41f4b71Sopenharmony_ci        const TAG: string = '[CalleeAbility]';
988e41f4b71Sopenharmony_ci        const DOMAIN_NUMBER: number = 0xFF00;
989e41f4b71Sopenharmony_ci
990e41f4b71Sopenharmony_ci        const MSG_SEND_METHOD: string = 'CallSendMsg';
991e41f4b71Sopenharmony_ci        let originMsg: string = '';
992e41f4b71Sopenharmony_ci        let backMsg: string = '';
993e41f4b71Sopenharmony_ci
994e41f4b71Sopenharmony_ci        class MyParcelable {
995e41f4b71Sopenharmony_ci          num: number = 0;
996e41f4b71Sopenharmony_ci          str: string = '';
997e41f4b71Sopenharmony_ci
998e41f4b71Sopenharmony_ci          constructor(num: number, string: string) {
999e41f4b71Sopenharmony_ci            this.num = num;
1000e41f4b71Sopenharmony_ci            this.str = string;
1001e41f4b71Sopenharmony_ci          };
1002e41f4b71Sopenharmony_ci
1003e41f4b71Sopenharmony_ci          mySequenceable(num: number, string: string): void {
1004e41f4b71Sopenharmony_ci            this.num = num;
1005e41f4b71Sopenharmony_ci            this.str = string;
1006e41f4b71Sopenharmony_ci          };
1007e41f4b71Sopenharmony_ci
1008e41f4b71Sopenharmony_ci          marshalling(messageSequence: rpc.MessageSequence): boolean {
1009e41f4b71Sopenharmony_ci            messageSequence.writeInt(this.num);
1010e41f4b71Sopenharmony_ci            messageSequence.writeString(this.str);
1011e41f4b71Sopenharmony_ci            return true;
1012e41f4b71Sopenharmony_ci          };
1013e41f4b71Sopenharmony_ci
1014e41f4b71Sopenharmony_ci          unmarshalling(messageSequence: rpc.MessageSequence): boolean {
1015e41f4b71Sopenharmony_ci            this.num = messageSequence.readInt();
1016e41f4b71Sopenharmony_ci            this.str = messageSequence.readString();
1017e41f4b71Sopenharmony_ci            return true;
1018e41f4b71Sopenharmony_ci          };
1019e41f4b71Sopenharmony_ci        }
1020e41f4b71Sopenharmony_ci
1021e41f4b71Sopenharmony_ci        export default class EntryAbility extends UIAbility {
1022e41f4b71Sopenharmony_ci          // ...
1023e41f4b71Sopenharmony_ci          caller: Caller | undefined;
1024e41f4b71Sopenharmony_ci
1025e41f4b71Sopenharmony_ci          async onButtonCallWithResult(originMsg: string, backMsg: string): Promise<void> {
1026e41f4b71Sopenharmony_ci            try {
1027e41f4b71Sopenharmony_ci              let msg: MyParcelable = new MyParcelable(1, originMsg);
1028e41f4b71Sopenharmony_ci              if (this.caller) {
1029e41f4b71Sopenharmony_ci                const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg);
1030e41f4b71Sopenharmony_ci                hilog.info(DOMAIN_NUMBER, TAG, 'caller callWithResult succeed');
1031e41f4b71Sopenharmony_ci                let result: MyParcelable = new MyParcelable(0, '');
1032e41f4b71Sopenharmony_ci                data.readParcelable(result);
1033e41f4b71Sopenharmony_ci                backMsg = result.str;
1034e41f4b71Sopenharmony_ci                hilog.info(DOMAIN_NUMBER, TAG, `caller result is [${result.num}, ${result.str}]`);
1035e41f4b71Sopenharmony_ci              }
1036e41f4b71Sopenharmony_ci            } catch (error) {
1037e41f4b71Sopenharmony_ci              hilog.info(DOMAIN_NUMBER, TAG, `caller callWithResult failed with ${error}`);
1038e41f4b71Sopenharmony_ci            }
1039e41f4b71Sopenharmony_ci          }
1040e41f4b71Sopenharmony_ci          // ...
1041e41f4b71Sopenharmony_ci        }
1042e41f4b71Sopenharmony_ci        ```
1043e41f4b71Sopenharmony_ci   
1044e41f4b71Sopenharmony_ci6. Release the caller object.
1045e41f4b71Sopenharmony_ci
1046e41f4b71Sopenharmony_ci    When the [Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller) object is no longer required, use [release](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callerrelease) to release it.
1047e41f4b71Sopenharmony_ci
1048e41f4b71Sopenharmony_ci      ```ts
1049e41f4b71Sopenharmony_ci      import { UIAbility, Caller } from '@kit.AbilityKit';
1050e41f4b71Sopenharmony_ci      import { hilog } from '@kit.PerformanceAnalysisKit';
1051e41f4b71Sopenharmony_ci
1052e41f4b71Sopenharmony_ci      const TAG: string = '[CalleeAbility]';
1053e41f4b71Sopenharmony_ci      const DOMAIN_NUMBER: number = 0xFF00;
1054e41f4b71Sopenharmony_ci
1055e41f4b71Sopenharmony_ci      export default class EntryAbility extends UIAbility {
1056e41f4b71Sopenharmony_ci        caller: Caller | undefined;
1057e41f4b71Sopenharmony_ci
1058e41f4b71Sopenharmony_ci        releaseCall(): void {
1059e41f4b71Sopenharmony_ci          try {
1060e41f4b71Sopenharmony_ci            if (this.caller) {
1061e41f4b71Sopenharmony_ci              this.caller.release();
1062e41f4b71Sopenharmony_ci              this.caller = undefined;
1063e41f4b71Sopenharmony_ci            }
1064e41f4b71Sopenharmony_ci            hilog.info(DOMAIN_NUMBER, TAG, 'caller release succeed');
1065e41f4b71Sopenharmony_ci          } catch (error) {
1066e41f4b71Sopenharmony_ci            hilog.info(DOMAIN_NUMBER, TAG, `caller release failed with ${error}`);
1067e41f4b71Sopenharmony_ci          }
1068e41f4b71Sopenharmony_ci        }
1069e41f4b71Sopenharmony_ci      }
1070e41f4b71Sopenharmony_ci      ```
1071e41f4b71Sopenharmony_ci<!--no_check-->
1072