1# Cross-Device Sync of Distributed Data Objects (ArkTS) 2<!--Kit: ArkData--> 3<!--Subsystem: DistributedDataManager--> 4<!--Owner: @lvcong_oh--> 5<!--Designer: @hollokin; @yuchaozhng--> 6<!--Tester: @lj_liujing; @yippo; @logic42--> 7<!--Adviser: @ge-yafang--> 8 9 10## When to Use 11 12The traditional implementation of data sync between devices involves heavy workload. You need to design the message processing logic for setting up a communication link, sending, receiving, and processing messages, and resolving data conflicts, as well as retry mechanism upon errors. In addition, the debugging complexity increases with the number of devices. 13 14The device status, message sending progress, and data transmitted are variables. If these variables support global access, they can be accessed as local variables by difference devices. This simplifies data sync across devices. 15 16The distributed data object (**distributedDataObject**) module implements global access to variables. It provides basic data object management capabilities, including creating, querying, deleting, and modifying in-memory objects and subscribing to data or status changes. It also provides distributed capabilities. OpenHarmony provides easy-to-use JS APIs for distributed application scenarios. With these APIs, you can easily implement data collaboration for an application across devices and listening for status and data changes between devices. The **distributedDataObject** module implements data object collaboration for the same application across multiple devices that form a Super Device. It greatly reduces the development workloads compared with the traditional implementation. 17 18Currently, <!--RP2-->distributed data objects can be used only in [cross-device migration](../application-models/hop-cross-device-migration.md) and [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).<!--RP2End--> 19 20## Basic Concepts 21 22- Distributed in-memory database: The distributed in-memory database caches data in the memory so that applications can quickly access the data. However, the data is not persisted. If the database is closed, the data is not retained. 23 24- Distributed data object: A distributed data object is encapsulation of a JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading and writing a distributed data object are mapped to the **get** and **put** operations in the corresponding database, respectively. 25 26 The distributed data object has the following states in its lifecycle: 27 28 - **Uninitialized**: The distributed data object is not instantiated or is destroyed. 29 - **Local**: A data table is created, but the data cannot be synced. 30 - **Distributed**: A data table is created, and data can be synced (there are at least two online devices with the same session ID). If a device is offline or the session ID is empty, the distributed data object changes to the local state. 31 32 33## Working Principles 34 35**Figure 1** Working mechanism 36 37 38 39The distributed data objects are encapsulated JS objects in distributed in-memory databases, and can be operated in the same way as local variables. The system automatically implements data sync across devices. 40 41 42### Encapsulation and Storage of JS Objects 43 44- An in-memory database is created for each distributed data object instance and identified by a session ID (**SessionId**). The in-memory databases created for different applications are isolated from each other. 45 46- When a distributed data object is instantiated, all properties of the object are traversed recursively. **Object.defineProperty** is used to define the **set()** and **get()** methods for all properties. The **set()** and **get()** methods correspond to the **put** and **get** operations of a record in the database, respectively. **Key** specifies the property name, and **Value** specifies the property value. 47 48- When a distributed data object is read or written, the **get()** or **set()** method is automatically called to perform the related operation on data in the database. 49 50**Table 1** Correspondence between a distributed data object and a distributed database 51 52| Distributed Data Object Instance| Object Instance| Property Name| Property Value| 53| -------- | -------- | -------- | -------- | 54| Distributed in-memory database| Database identified by **sessionID**| Key of a record in the database| Value of a record in the database| 55 56 57### Cross-Device Sync and Data Change Notification 58 59One of the most important functions of distributed data objects is to implement data sync between objects. Distributed data objects are created locally for the devices on a trusted network. If the distributed data objects on different devices are set with the same **sessionID**, data can be synced between them. 60 61As shown in the following figure, distributed data object 1 of device A and distributed data object 1 of device B are set with the same session ID **session1**, and sync relationship of session 1 is established between the two objects. 62 63 **Figure 2** Object sync relationship 64 65 66 67For each device, only one distributed data object can be added to a sync relationship. As shown in the preceding figure, distributed data object 2 of device A cannot be added to session 1 because distributed data object 1 of device A has been added to session 1. 68 69After the sync relationship is established, each session has a copy of shared object data. The distributed data objects added to a session support the following operations: 70 71(1) Reading or modifying the data in the session. 72 73(2) Listening for data changes made by other devices. 74 75(3) Listening for status changes, such as the addition and removal of other devices. 76 77When a distributed data object is added to a session, if its data is different from that of the session, the distributed data object updates data of the session. If you do not want to update the data of the session when adding a distributed data object to a session and obtain the data of the session, set the attribute value of the object to **undefined** (for an asset, set each attribute of the asset to an empty string). 78 79### Minimum Sync Unit 80 81Property is the minimum unit to synchronize in distributed data objects. For example, object 1 in the following figure has three properties: name, age, and parents. If one of the properties is changed, only the changed property needs to be synced. 82 83The object properties support basic types (number, Boolean, and string) and complex types (array and nested basic types). For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified. 84 85```ts 86dataObject['parents'] = {mom: "amy"}; // Supported modification 87dataObject['parents']['mom'] = "amy"; // Unsupported modification 88``` 89 90**Figure 3** Sync of distributed data objects 91 92 93 94 95 96### Persistence of Distributed Data Objects 97 98Distributed data objects run in the process space of applications. After the data of a distributed data object is persisted in the distributed database, the data will not be lost after the application exits. 99 100You need to persist distributed data objects in the following scenarios: 101 102- Enable an application to retrieve the exact same data after it starts again. In this case, you need to persist the distributed data object (for example, object 1 with session ID 1). After the application starts again, create a distributed data object (for example, object 2) and set the session ID to 1. Then, the application can retrieve the data of object 1. 103 104- Enable an application started on another device to retrieve the exact same data. In this case, you need to persist the distributed data object (for example, object 1 with session ID 1) on device A and synchronize the data to device B. Then, create a distributed data object (for example, object 2) and set the session ID to 1. When the application is started on device B, it can retrieve the same application data used on device A before the application is closed. 105 106### Asset Sync Mechanism 107 108In a distributed data object, [asset](../reference/apis-arkdata/js-apis-data-commonType.md#asset) is used to describe a local entity asset file. When the distributed data object is synced across devices, the file is also synced to other devices with it. 109 110In versions earlier than API version 20, only asset is supported, and [assets](../reference/apis-arkdata/js-apis-data-commonType.md#assets) are not supported. To synchronize multiple assets, use each asset as a root property of the distributed data object. 111 112Since API version 20, synchronization of [assets](../reference/apis-arkdata/js-apis-data-commonType.md#assets) is supported. 113 114## Constraints 115<!--RP5--> 116- Currently, distributed data objects can be used only in [cross-device migration](../application-models/hop-cross-device-migration.md) and [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call). 117 118- Currently, the cross-device continuation capability supports the following scenarios: 119 - [Migrating between abilities in the same application across devices](../application-models/hop-cross-device-migration.md#migrating-between-abilities-in-the-same-application-across-devices) 120 - [Migrating abilities with different bundle names in the same application across devices](../application-models/hop-cross-device-migration.md#migrating-abilities-with-different-bundle-names-in-the-same-application-across-devices) 121<!--RP5End--> 122- Data can be synced for the distributed data objects with the same session ID. 123 124- Each distributed data object occupies 100 KB to 150 KB of memory. Therefore, you are advised not to create too many distributed data objects. 125 126- The maximum size of a distributed data object is 500 KB. 127 128- If data of 1 KB data is modified on device A, device B can complete data update within 50 ms after receiving a data change notification. 129 130- A maximum of 16 distributed data object instances can be created for an application. 131 132- For the sake of performance and user experience, the maximum number of devices for data collaboration is 3. 133 134- For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified. In [asset sync mechanism](#asset-sync-mechanism), the data of the asset type must support modification of its lower-level properties. 135 136- Currently, only JS APIs are supported. 137 138## Available APIs 139 140Most of the APIs for cross-device sync of distributed data objects are executed asynchronously in callback or promise mode. The following table uses the callback-based APIs as an example. For more information about the APIs, see [Distributed Data Object](../reference/apis-arkdata/js-apis-data-distributedobject.md). 141 142| API| Description| 143| -------- | -------- | 144| create(context: Context, source: object): DataObject | Creates a distributed data object instance.| 145| genSessionId(): string | Generates a session ID for distributed data objects.| 146| setSessionId(sessionId: string, callback: AsyncCallback<void>): void | Sets a session ID for data sync. Automatic sync is performed for devices with the same session ID on a trusted network.| 147| setSessionId(callback: AsyncCallback<void>): void | Exits all sessions.| 148| on(type: 'change', callback: (sessionId: string, fields: Array<string>) => void): void | Subscribes to data changes of the distributed data object.| 149| off(type: 'change', callback?: (sessionId: string, fields: Array<string>) => void): void | Unsubscribes from data changes of the distributed data object.| 150| on(type: 'status', callback: (sessionId: string, networkId: string, status: 'online' \| 'offline' ) => void): void | Subscribes to status changes of the distributed data object.| 151| off(type: 'status', callback?: (sessionId: string, networkId: string, status: 'online' \|'offline' ) => void): void | Unsubscribes from status changes of the distributed data object.| 152| save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void | Saves a distributed data object.| 153| revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void | Revokes the saving of the distributed data object.| 154| bindAssetStore(assetKey: string, bindInfo: BindInfo, callback: AsyncCallback<void>): void | Binds an asset and its RDB store.| 155| setAsset(assetKey: string, uri: string): void | Sets an asset.| 156| setAssets(assetKey: string, uris: Array<string>): void | Sets assets.| 157| on(type: 'change', callback: DataObserver<void>): void | Subscribes to data changes of this distributed data object.| 158| off(type: 'change', callback?: DataObserver<void>): void | Unsubscribes from data changes of this distributed data object.| 159| on(type: 'status', callback: StatusObserver<void>): void | Subscribes to the status changes of this distributed data object.| 160| off(type: 'status', callback?: StatusObserver<void>): void | Unsubscribes from status changes of this distributed data object.| 161 162 163## How to Develop 164 165### Using Distributed Data Objects in Cross-Device Migration 166 1671. Create a distributed data object in **onContinue()** for the application on the source device, and save data. 168 169 1.1 Call **create()** to create a distributed data object instance. 170 171 1.2 Call **genSessionId()** to generate a **sessionId**, call **setSessionId()** to set a **sessionId**, and add the **sessionId** to **wantParam**. The distributed data objects with the same **sessionId** can connect to the same network. 172 173 1.3 Obtain the **networkId** from **wantParam** for the application on the target device and call **save()** with this **networkId** to save data to the target device. 174 1752. Create a distributed data object in **onCreate()** and **onNewWant()** for the application on the target device, and register a listener for the "restored" state. 176 177 2.1 Call **create()** to create a distributed data object instance for the application on the target device. 178 179 2.2 Register a listener callback for the data recovery state. If "restored" is returned by the listener callback registered, the distributed data object of the target device has obtained the data transferred from the source device. 180 181 2.3 Obtain the **sessionId** of the source device from **want.parameters** and call **setSessionId** to set the same **sessionId** for the target device. 182 183> **NOTE** 184> 185> - In cross-device migration, after **setSessionId()** is called on the source device to set **sessionId**, you should call **save()** to save data to the target device. 186> - When an application is launched as a result of a migration, the [onWindowStageRestore()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagerestore) lifecycle callback function, rather than [onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate), is triggered following **onCreate()** or **onNewWant()**. This sequence occurs for both cold and hot starts. If you have performed some necessary initialization operations during application launch in **onWindowStageCreate()**, you must perform the same initialization operations in **onWindowStageRestore()** after the migration to avoid application exceptions. 187> 188<!--RP1--> 189> - The **continuable** tag must be set for cross-device migration. For details, see [How to Develop](../application-models/hop-cross-device-migration.md#how-to-develop).<!--RP1End--> 190> 191> - The **sessionId** field in **wantParam** is used by other services. You are advised to customize a key for accessing the **sessionId** field. 192> 193> - Use data of the Asset type to record information about assets (such as documents, images, and videos). When asset data is migrated, the corresponding asset is also migrated to the target device. 194> 195> - The initial value of the service data must be set to **undefined** on the target device so that the data saved on the source device can be restored on the target device. Otherwise, the data on the source device will be overwritten by the data set on the target device. For asset data, you need to set each attribute of the asset data to an empty string instead of setting the entire asset data to **undefined**. 196> 197> - Currently, the asset array is not supported. If multiple files need to be migrated, define an asset data record for each file to migrate. 198> 199> - Currently, only files in distributed file directory can be migrated. Files in other directories can be copied or moved to distributed file directory before migration. For details about how to move or copy files and obtain URIs, see [File Management](../reference/apis-core-file-kit/js-apis-file-fs.md) and [File URI](../reference/apis-core-file-kit/js-apis-file-fileuri.md). 200 201```ts 202import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 203import { commonType, distributedDataObject } from '@kit.ArkData'; 204import { BusinessError } from '@kit.BasicServicesKit'; 205 206// Define service data. 207export class ContentInfo { 208 mainTitle: string | undefined; 209 textContent: string | undefined; 210 imageUriArray: Array<ImageInfo> | undefined; 211 isShowLocalInfo: boolean | undefined; 212 isAddLocalInfo: boolean | undefined; 213 selectLocalInfo: string | undefined; 214 attachments?: commonType.Assets | undefined; 215 216 constructor( 217 mainTitle: string | undefined, 218 textContent: string | undefined, 219 imageUriArray: Array<ImageInfo>| undefined, 220 isShowLocalInfo: boolean | undefined, 221 isAddLocalInfo: boolean | undefined, 222 selectLocalInfo: string | undefined, 223 attachments?: commonType.Assets | undefined 224 ) { 225 this.mainTitle = mainTitle; 226 this.textContent = textContent; 227 this.imageUriArray = imageUriArray; 228 this.isShowLocalInfo = isShowLocalInfo; 229 this.isAddLocalInfo = isAddLocalInfo; 230 this.selectLocalInfo = selectLocalInfo; 231 this.attachments = attachments; 232 } 233 234 flatAssets(): object { 235 let obj: object = this; 236 if (!this.attachments) { 237 return obj; 238 } 239 for (let i = 0; i < this.attachments.length; i++) { 240 obj[`attachments${i}`] = this.attachments[i]; 241 } 242 return obj; 243 } 244} 245 246export interface ImageInfo { 247 /** 248 * image PixelMap. 249 */ 250 imagePixelMap: PixelMap; 251 252 /** 253 * Image name. 254 */ 255 imageName: string; 256} 257 258const TAG = '[DistributedDataObject]'; 259let dataObject: distributedDataObject.DataObject; 260 261export default class EntryAbility extends UIAbility { 262 private imageUriArray: Array<ImageInfo> = []; 263 private distributedObject: distributedDataObject.DataObject | undefined = undefined; 264 // 1. Create a distributed data object in **onContinue()** for the application on the source device, and save data to the target device. 265 async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> { 266 // 1.1 Obtain the key URI of the distributed data object to be set. 267 try { 268 let sessionId: string = distributedDataObject.genSessionId(); 269 wantParam.distributedSessionId = sessionId; 270 271 let distrUriArray: Array<string> = []; 272 let assetUriArray = AppStorage.get<Array<string>>('assetUriArray'); 273 if (assetUriArray) { 274 distrUriArray = assetUriArray; 275 } 276 // 1.2 Create a distributed data object. 277 let contentInfo: ContentInfo = new ContentInfo( 278 AppStorage.get('mainTitle'), 279 AppStorage.get('textContent'), 280 AppStorage.get('imageUriArray'), 281 AppStorage.get('isShowLocalInfo'), 282 AppStorage.get('isAddLocalInfo'), 283 AppStorage.get('selectLocalInfo'), 284 ); 285 let source = contentInfo.flatAssets(); 286 this.distributedObject = distributedDataObject.create(this.context, source); 287 288 // 1.3 Set the asset or assets of the distributed data object. 289 if (assetUriArray?.length == 1) { 290 this.distributedObject?.setAsset('attachments', distrUriArray[0]). then(() => { 291 console.info('OnContinue setAsset'); 292 }) 293 } else { 294 this.distributedObject?.setAssets('attachments', distrUriArray). then(() => { 295 console.info('OnContinue setAssets'); 296 }) 297 } 298 // 1.4 Save the asset or assets to the source device. 299 this.distributedObject?.setSessionId(sessionId); 300 this.distributedObject?.save(wantParam.targetDevice as string).catch((err: BusinessError) => { 301 console.error('OnContinue failed to save. code: ', err.code); 302 console.error('OnContinue failed to save. message: ', err.message); 303 }); 304 } catch (error) { 305 console.error('OnContinue faild code: ', error.code); 306 console.error('OnContinue faild message: ', error.message); 307 } 308 console.info("OnContinue success!"); 309 return AbilityConstant.OnContinueResult.AGREE; 310 } 311 312 // 2. Create a distributed data object in onCreate() for the application on the target device (for cold start), and add it to the network for data migration. 313 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 314 if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 315 if (want.parameters && want.parameters.distributedSessionId) { 316 this.restoreDistributedObject(want); 317 } 318 } 319 } 320 321 // 2. Create a distributed data object in onNewWant() for the application on the target device (for hot start), and add it to the network for data migration. 322 onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { 323 if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 324 if (want.parameters && want.parameters.distributedSessionId) { 325 this.restoreDistributedObject(want); 326 } 327 } 328 } 329 330 async restoreDistributedObject(want: Want): Promise<void> { 331 if (!want.parameters || !want.parameters.distributedSessionId) { 332 console.error(TAG + 'missing sessionId'); 333 return; 334 } 335 336 // 2.1 Call create() to create a distributed data object instance for the application on the target device. 337 let mailInfo: ContentInfo = new ContentInfo(undefined, undefined, [], undefined, undefined, undefined, undefined); 338 dataObject = distributedDataObject.create(this.context, mailInfo); 339 340 // 2.2 Register a listener callback for the data recovery state. If "restored" is returned by the listener callback registered, the distributed data object of the target device has obtained the data transferred from the source device. If asset data is migrated, the file is also transferred to the target device. 341 dataObject.on('status', (sessionId: string, networkId: string, status: string) => { 342 console.log(TAG + `status change, sessionId: ${sessionId}`); 343 console.log(TAG + `status change, networkId: ${networkId}`); 344 if (status == 'restored') { // "restored" indicates that the data saved on the source device is restored on the target device. 345 console.log(TAG + `title: ${dataObject['title']}, text: ${dataObject['text']}`); 346 AppStorage.setOrCreate('mainTitle', dataObject['mainTitle']); 347 AppStorage.setOrCreate('textContent', dataObject['textContent']); 348 AppStorage.setOrCreate('imageUriArray', dataObject['imageUriArray']); 349 AppStorage.setOrCreate('isShowLocalInfo', dataObject['isShowLocalInfo']); 350 AppStorage.setOrCreate('isAddLocalInfo', dataObject['isAddLocalInfo']); 351 AppStorage.setOrCreate('selectLocalInfo', dataObject['selectLocalInfo']); 352 AppStorage.setOrCreate<Array<ImageInfo>>('imageUriArray', this.imageUriArray); 353 } 354 }); 355 356 // 2.3 Obtain the sessionId of the source device from want.parameters and call setSessionId to set the same sessionId for the target device. 357 let sessionId = want.parameters.distributedSessionId as string; 358 console.log(TAG + `get sessionId: ${sessionId}`); 359 dataObject.setSessionId(sessionId); 360 } 361} 362``` 363 364### Using Distributed Data Objects in Multi-Device Collaboration 365 3661. Call **startAbilityByCall()** to start an ability on another device. 367 368 1.1 Call **genSessionId()** to create a **sessionId** and obtain a **networkId** of the peer device through the distributed device management API. 369 370 1.2 Assemble **want** and put **sessionId** into **want**. 371 372 1.3 Call **startAbilityByCall()** to start the peer ability. 373 3742. Create a distributed data object on the caller device and adds it to the network. 375 376 2.1 Create a distributed data object instance. 377 378 2.2 Register a listener callback for data changes. 379 380 2.3 Set a **sessionId** for the distributed data object and add it to the network. 381 3823. Create a distributed data object on the peer device and restore the data saved on the caller device. 383 384 3.1 Create a distributed data object instance on the peer device. 385 386 3.2 Register a listener callback for data changes. 387 388 3.3 Obtain **sessionId** of the caller device from **want** and add the distributed data object instance to the network with the **sessionId**. 389 390> **NOTE** 391> 392> - Currently, <!--RP3-->distributed data objects can be used only in [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call) to sync data.<!--RP3End--> 393> 394> - To implement multi-device collaboration using the cross-device call, <!--RP4-->you need to apply for the ohos.permission.DISTRIBUTED_DATASYNC permission and set **launchType** to **singleton**. For details, see [How to Develop](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).<!--RP4End--> 395> 396> - The **sessionId** field in **wantParam** is used by other services. You are advised to customize a key for accessing the **sessionId** field. 397> 398> - For details about how to obtain the **networkId** of the peer device, see [Querying Device Information](../distributedservice/devicemanager-guidelines.md#querying-device-information). 399 400 The sample code is as follows: 401 402```ts 403import { AbilityConstant, Caller, UIAbility, Want } from '@kit.AbilityKit'; 404import { distributedDataObject } from '@kit.ArkData'; 405import { distributedDeviceManager } from '@kit.DistributedServiceKit'; 406import { BusinessError } from '@kit.BasicServicesKit'; 407import { JSON } from '@kit.ArkTS'; 408 409// Define service data. 410class Data { 411 title: string | undefined; 412 text: string | undefined; 413 414 constructor(title: string | undefined, text: string | undefined) { 415 this.title = title; 416 this.text = text; 417 } 418} 419 420const TAG = '[DistributedDataObject]'; 421 422let sessionId: string; 423let caller: Caller; 424let dataObject: distributedDataObject.DataObject; 425const changeCallBack: distributedDataObject.DataObserver = (sessionId: string, fields: Array<string>) => { 426 console.info(`change, sessionId: ${sessionId}, fields: ${JSON.stringify(fields)}`); 427} 428 429export default class EntryAbility extends UIAbility { 430 // 1. Call startAbilityByCall() to start an ability on another device. 431 callRemote() { 432 if (caller) { 433 console.error(TAG + 'call remote already'); 434 return; 435 } 436 437 // 1.1 Call genSessionId() to create a sessionId and call getRemoteDeviceId() to obtain the networkId of the peer device. 438 sessionId = distributedDataObject.genSessionId(); 439 console.log(TAG + `gen sessionId: ${sessionId}`); 440 let deviceId = getRemoteDeviceId(); 441 if (deviceId == "") { 442 console.warn(TAG + 'no remote device'); 443 return; 444 } 445 console.log(TAG + `get remote deviceId: ${deviceId}`); 446 447 // 1.2 Assemble want and put sessionId into want. 448 let want: Want = { 449 bundleName: 'com.example.collaboration', 450 abilityName: 'EntryAbility', 451 deviceId: deviceId, 452 parameters: { 453 'ohos.aafwk.param.callAbilityToForeground': true, // Start the ability in the foreground. This parameter is optional. 454 'distributedSessionId': sessionId 455 } 456 } 457 try { 458 // 1.3 Call startAbilityByCall() to start the peer ability. 459 this.context.startAbilityByCall(want).then((res) => { 460 if (!res) { 461 console.error(TAG + 'startAbilityByCall failed'); 462 } 463 caller = res; 464 }) 465 } catch (e) { 466 let err = e as BusinessError; 467 console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 468 } 469 } 470 471 // 2. Create a distributed data object after starting the peer ability. 472 createDataObject() { 473 if (!caller) { 474 console.error(TAG + 'call remote first'); 475 return; 476 } 477 if (dataObject) { 478 console.error(TAG + 'create dataObject already'); 479 return; 480 } 481 482 // 2.1 Create a distributed data object instance. 483 let data = new Data('The title', 'The text'); 484 dataObject = distributedDataObject.create(this.context, data); 485 486 // 2.2 Register a listener callback for data changes. 487 dataObject.on('change', changeCallBack); 488 // 2.3 Set a sessionId for the distributed data object and add it to the network. 489 dataObject.setSessionId(sessionId); 490 } 491 492 // 3. Create a distributed data object on the peer device and restore the data saved on the caller device. 493 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 494 if (want.parameters && want.parameters.distributedSessionId) { 495 // 3.1 Create a distributed data object instance on the peer device. 496 let data = new Data(undefined, undefined); 497 dataObject = distributedDataObject.create(this.context, data); 498 499 // 3.2 Register a listener callback for data changes. 500 dataObject.on('change', changeCallBack); 501 // 3.3 Obtain sessionId of the caller device from **want** and add the distributed data object instance to the network with the sessionId. 502 let sessionId = want.parameters.distributedSessionId as string; 503 console.log(TAG + `onCreate get sessionId: ${sessionId}`); 504 dataObject.setSessionId(sessionId); 505 } 506 } 507} 508 509// Obtain devices on the trusted network. 510function getRemoteDeviceId() { 511 let deviceId = ""; 512 try { 513 let deviceManager = distributedDeviceManager.createDeviceManager('com.example.collaboration'); 514 let devices = deviceManager.getAvailableDeviceListSync(); 515 if (devices[0] && devices[0].networkId) { 516 deviceId = devices[0].networkId; 517 } 518 } catch (e) { 519 let err = e as BusinessError; 520 console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 521 } 522 return deviceId; 523} 524```