1# 分布式数据对象跨设备数据同步 (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## 场景介绍 11 12传统方式下,设备之间的数据同步,需要开发者完成消息处理逻辑,包括:建立通信链接、消息收发处理、错误重试、数据冲突解决等操作,工作量非常大。而且设备越多,调试复杂度也将同步增加。 13 14其实设备之间的状态、消息发送进度、发送的数据等都是“变量”。如果这些变量支持“全局”访问,那么开发者跨设备访问这些变量就能像操作本地变量一样,从而能够自动高效、便捷地实现数据多端同步。 15 16分布式数据对象即实现了对“变量”的“全局”访问。向应用开发者提供内存对象的创建、查询、删除、修改、订阅等基本数据对象的管理能力,同时具备分布式能力。为开发者在分布式应用场景下提供简单易用的JS接口,轻松实现多设备间同应用的数据协同,同时设备间可以监听对象的状态和数据变更。满足超级终端场景下,相同应用多设备间的数据对象协同需求。与传统方式相比,分布式数据对象大大减少了开发者的工作量。 17 18目前<!--RP2-->分布式数据对象只能在[跨端迁移](../application-models/hop-cross-device-migration.md)和[通过跨设备Call调用实现的多端协同](../application-models/hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)场景中使用。<!--RP2End--> 19 20## 基本概念 21 22- **分布式内存数据库**:分布式内存数据库将数据缓存在内存中,以便应用获得更快的数据存取速度,不会将数据进行持久化。若数据库关闭,则数据不会保留。 23 24- **分布式数据对象**:分布式数据对象是一个JS对象型的封装。每一个分布式数据对象实例会创建一个内存数据库中的数据表,每个应用程序创建的内存数据库相互隔离,对分布式数据对象的“读取”或“赋值”会自动映射到对应数据库的get/put操作。 25 26 分布式数据对象的生命周期包括以下状态: 27 28 - 未初始化:未实例化,或已被销毁。 29 - 本地数据对象:已创建对应的数据表,但是还无法进行数据同步。 30 - 分布式数据对象:已创建对应的数据表,设备在线且组网内设置同样sessionId的对象数>=2,可以跨设备同步数据。若设备掉线或将sessionId置为空,分布式数据对象退化为本地数据对象。 31 32 33## 运作机制 34 35**图1** 分布式数据对象运作机制 36 37 38 39分布式数据对象生长在分布式内存数据库之上,在分布式内存数据库上进行了JS对象型的封装,能像操作本地变量一样操作分布式数据对象,数据的跨设备同步由系统自动完成。 40 41 42### JS对象型存储与封装机制 43 44- 为每个分布式数据对象实例创建一个内存数据库,通过SessionId标识,每个应用程序创建的内存数据库相互隔离。 45 46- 在分布式数据对象实例化的时候,(递归)遍历对象所有属性,使用“Object.defineProperty”定义所有属性的set和get方法,set和get中分别对应数据库一条记录的put和get操作,Key对应属性名,Value对应属性值。 47 48- 在开发者对分布式数据对象进行“读取”或者“赋值”的时候,都会自动调用到set和get方法,映射到对应数据库的操作。 49 50**表1** 分布式数据对象和分布式数据库的对应关系 51 52| 分布式对象实例 | 对象实例 | 属性名称 | 属性值 | 53| -------- | -------- | -------- | -------- | 54| 分布式内存数据库 | 一个数据库(sessionID标识) | 一条数据库记录的key | 一条数据库记录的value | 55 56 57### 跨设备同步和数据变更通知机制 58 59分布式数据对象,最重要的功能就是对象之间的数据同步。可信组网内的设备可以在本地创建分布式数据对象,并设置sessionID。不同设备上的分布式数据对象,通过设置相同的sessionID,建立对象之间的同步关系。 60 61如下图所示,设备A和设备B上的“分布式数据对象1”,其sessionID均为session1,这两个对象建立了session1的同步关系。 62 63 **图2** 对象的同步关系 64 65 66 67一个同步关系中,一个设备只能有一个对象加入。比如上图中,设备A的“分布式数据对象1”已经加入了session1的同步关系,所以设备A的“分布式数据对象2”就加入失败了。 68 69建立同步关系后,每个Session有一份共享对象数据。加入了同一个Session的对象,支持以下操作: 70 71(1)读取/修改Session中的数据。 72 73(2)监听数据变更,感知其他设备对共享对象数据的修改。 74 75(3)监听状态变更,感知其他设备的加入和退出。 76 77分布式数据对象加入session时,如果它的数据与session中的数据不同,则它会更新session中的数据。如果希望分布式数据对象加入sessionId时不更新session中的数据,并且得到session中的数据,需要将对象的属性的值设置为undefined(资产类型的属性则是将它的各个属性值设置为空字符串)。 78 79### 同步的最小单位 80 81关于分布式数据对象的数据同步,值得注意的是,同步的最小单位是“属性”。比如,下图中对象1包含三个属性:name、age和parents。当其中一个属性变更时,则数据同步时只需同步此变更的属性。 82 83对象属性支持基本类型(数字类型、布尔类型、字符串类型)以及复杂类型(数组、基本类型嵌套)。针对复杂类型的数据修改,目前仅支持对根属性的修改,暂不支持对下级属性的修改。 84 85```ts 86dataObject['parents'] = {mom: "amy"}; // 支持的修改 87dataObject['parents']['mom'] = "amy"; // 不支持的修改 88``` 89 90**图3** 数据同步视图 91 92 93 94 95 96### 对象持久化缓存机制 97 98分布式对象主要运行在应用程序的进程空间。当调用分布式对象持久化接口时,通过分布式数据库对对象进行持久化和同步,进程退出后数据也不会丢失。 99 100该场景是分布式对象的扩展场景,主要用于以下情况: 101 102- 在设备上创建持久化对象后APP退出,重新打开APP,创建持久化对象,加入同一个Session,数据可以恢复到APP退出前的数据。 103 104- 在设备A上创建持久化对象并同步后持久化到设备B后,A设备的APP退出,设备B打开APP,创建持久化对象,加入同一个Session,数据可以恢复到A设备退出前的数据。 105 106### 资产同步机制 107 108在分布式对象中,可以使用[资产类型](../reference/apis-arkdata/js-apis-data-commonType.md#asset)来描述本地实体资产文件,分布式对象跨设备同步时,该文件会和数据一起同步到其他设备上。 109 110在API version 20之前版本,仅支持资产类型,不支持[资产类型数组](../reference/apis-arkdata/js-apis-data-commonType.md#assets)。如需同步多个资产,可将每个资产作为分布式对象的一个根属性实现。 111 112从API version 20开始,支持[资产类型数组](../reference/apis-arkdata/js-apis-data-commonType.md#assets)的同步。 113 114## 约束限制 115<!--RP5--> 116- 目前分布式数据对象只能在[跨端迁移](../application-models/hop-cross-device-migration.md)和[通过跨设备Call调用实现的多端协同](../application-models/hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)场景中使用。 117 118- 当前跨设备接续能力支持以下两种场景的 Ability 跨端迁移 119 - [支持同应用中不同Ability跨端迁移](../application-models/hop-cross-device-migration.md#支持同应用中不同ability跨端迁移) 120 - [支持同应用不同BundleName的Ability跨端迁移](../application-models/hop-cross-device-migration.md#支持同应用不同bundlename的ability跨端迁移) 121<!--RP5End--> 122- 分布式数据对象的数据同步发生在同一个应用程序下,且同sessionID之间。 123 124- 不建议创建过多的分布式数据对象,每个分布式数据对象将占用100-150KB内存。 125 126- 每个分布式数据对象大小不超过500KB。 127 128- 设备A修改1KB数据,设备B收到变更通知,50ms内完成。 129 130- 单个应用程序最多只能创建16个分布式数据对象实例。 131 132- 考虑到性能和用户体验,最多不超过3个设备进行数据协同。 133 134- 如对复杂类型的数据进行修改,仅支持修改根属性,暂不支持下级属性修改。[资产同步机制](#资产同步机制)中,资产类型的数据支持下一级属性修改。 135 136- 支持JS接口间的互通,与其他语言不互通。 137 138## 接口说明 139 140以下是分布式对象跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[分布式数据对象](../reference/apis-arkdata/js-apis-data-distributedobject.md)。 141 142 143 144| 接口名称 | 描述 | 145| -------- | -------- | 146| create(context: Context, source: object): DataObject | 创建并得到一个分布式数据对象实例。 | 147| genSessionId(): string | 创建一个sessionId,可作为分布式数据对象的sessionId。 | 148| setSessionId(sessionId: string, callback: AsyncCallback<void>): void | 设置同步的sessionId,当可信组网中有多个设备时,多个设备间的对象如果设置为同一个sessionId,就能自动同步。 | 149| setSessionId(callback: AsyncCallback<void>): void | 退出所有已加入的session。 | 150| on(type: 'change', callback: (sessionId: string, fields: Array<string>) => void): void | 监听分布式数据对象的数据变更。 | 151| off(type: 'change', callback?: (sessionId: string, fields: Array<string>) => void): void | 取消监听分布式数据对象的数据变更。 | 152| on(type: 'status', callback: (sessionId: string, networkId: string, status: 'online' \| 'offline' ) => void): void | 监听分布式数据对象的上下线。 | 153| off(type: 'status', callback?: (sessionId: string, networkId: string, status: 'online' \|'offline' ) => void): void | 取消监听分布式数据对象的上下线。 | 154| save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void | 保存分布式数据对象。 | 155| revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void | 撤回保存的分布式数据对象。 | 156| bindAssetStore(assetKey: string, bindInfo: BindInfo, callback: AsyncCallback<void>): void | 绑定融合资产。 | 157| setAsset(assetKey: string, uri: string): void | 设置单个资产。 | 158| setAssets(assetKey: string, uris: Array<string>): void | 设置资产数组。 | 159| on(type: 'change', callback: DataObserver<void>): void | 监听分布式对象的数据变更。 | 160| off(type: 'change', callback?: DataObserver<void>): void | 删除分布式对象数据变更监听的回调实例。 | 161| on(type: 'status', callback: StatusObserver<void>): void | 监听分布式对象的状态变更。 | 162| off(type: 'status', callback?: StatusObserver<void>): void | 删除分布式对象状态变更监听的回调实例。 | 163 164 165## 开发步骤 166 167### 在跨端迁移中使用分布式数据对象迁移数据 168 1691. 迁移发起端在onContinue接口中创建分布式数据对象并保存数据到接收端: 170 171 1.1 调用create接口创建并得到一个分布式数据对象实例。 172 173 1.2 调用genSessionId接口创建一个sessionId,调用setSessionId接口设置同步的sessionId,并将这个sessionId放入wantParam。 174 175 1.3 从wantParam获取接收端设备networkId,使用这个networkId调用save接口保存数据到接收端。 176 1772. 接收端在onCreate和onNewWant接口中创建分布式数据对象并注册恢复状态监听: 178 179 2.1 调用create接口创建并得到一个分布式数据对象实例。 180 181 2.2 注册恢复状态监听。收到状态为'restored'的回调通知时,表示接收端分布式数据对象已恢复发起端保存过来的数据。 182 183 2.3 从want.parameters中获取发起端放入的sessionId,调用setSessionId接口设置同步的sessionId。 184 185> **说明:** 186> 187> - 跨端迁移时,在迁移发起端调用setSessionId接口设置同步的sessionId后,必须再调用save接口保存数据到接收端。 188> - 在应用迁移启动时,无论是冷启动还是热启动,都会在执行完onCreate()/onNewWant()后,触发[onWindowStageRestore()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagerestore)生命周期函数,不执行[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate)生命周期函数。开发者如果在`onWindowStageCreate()`中进行了一些应用启动时必要的初始化,那么迁移后需要在`onWindowStageRestore()`中执行同样的初始化操作,避免应用异常 189> 190<!--RP1--> 191> - 跨端迁移需要配置`continuable`标签,详见[跨端迁移开发步骤](../application-models/hop-cross-device-migration.md#开发步骤)。<!--RP1End--> 192> 193> - wantParam中的"sessionId"字段可能被其他服务占用,建议自定义一个key存取sessionId。 194> 195> - 可以使用资产类型记录资产附件(文件、图片、视频等类型文件)的相关信息,迁移资产类型数据时,对应的资产附件会一起迁移到对端。 196> 197> - 接收端需要将业务数据的初始值设置为undefined,才能恢复发起端保存的数据,否则接收端的数据会覆盖同步到发起端。如果是资产数据,需要将资产数据的各个属性设置为空字符串而不是将整个资产数据设置为undefined。 198> 199> - 暂不支持资产类型数组,如果要迁移多个文件,在业务数据中定义多条资产数据来记录。 200> 201> - 目前仅支持迁移分布式文件目录下的文件,非分布式文件目录下的文件可以复制或移动到分布式文件目录下再进行迁移。文件的操作和URI的获取详见[文件管理](../reference/apis-core-file-kit/js-apis-file-fs.md)和[文件URI](../reference/apis-core-file-kit/js-apis-file-fileuri.md)。 202 203```ts 204import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 205import { commonType, distributedDataObject } from '@kit.ArkData'; 206import { BusinessError } from '@kit.BasicServicesKit'; 207 208// 业务数据定义 209export class ContentInfo { 210 mainTitle: string | undefined; 211 textContent: string | undefined; 212 imageUriArray: Array<ImageInfo> | undefined; 213 isShowLocalInfo: boolean | undefined; 214 isAddLocalInfo: boolean | undefined; 215 selectLocalInfo: string | undefined; 216 attachments?: commonType.Assets | undefined; 217 218 constructor( 219 mainTitle: string | undefined, 220 textContent: string | undefined, 221 imageUriArray: Array<ImageInfo>| undefined, 222 isShowLocalInfo: boolean | undefined, 223 isAddLocalInfo: boolean | undefined, 224 selectLocalInfo: string | undefined, 225 attachments?: commonType.Assets | undefined 226 ) { 227 this.mainTitle = mainTitle; 228 this.textContent = textContent; 229 this.imageUriArray = imageUriArray; 230 this.isShowLocalInfo = isShowLocalInfo; 231 this.isAddLocalInfo = isAddLocalInfo; 232 this.selectLocalInfo = selectLocalInfo; 233 this.attachments = attachments; 234 } 235 236 flatAssets(): object { 237 let obj: object = this; 238 if (!this.attachments) { 239 return obj; 240 } 241 for (let i = 0; i < this.attachments.length; i++) { 242 obj[`attachments${i}`] = this.attachments[i]; 243 } 244 return obj; 245 } 246} 247 248export interface ImageInfo { 249 /** 250 * image PixelMap. 251 */ 252 imagePixelMap: PixelMap; 253 254 /** 255 * Image name. 256 */ 257 imageName: string; 258} 259 260const TAG = '[DistributedDataObject]'; 261let dataObject: distributedDataObject.DataObject; 262 263export default class EntryAbility extends UIAbility { 264 private imageUriArray: Array<ImageInfo> = []; 265 private distributedObject: distributedDataObject.DataObject | undefined = undefined; 266 // 1. 迁移发起端在onContinue接口中创建分布式数据对象并保存数据到接收端 267 async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> { 268 // 1.1 获取需要设置的分布式对象的资产关键uri 269 try { 270 let sessionId: string = distributedDataObject.genSessionId(); 271 wantParam.distributedSessionId = sessionId; 272 273 let distrUriArray: Array<string> = []; 274 let assetUriArray = AppStorage.get<Array<string>>('assetUriArray'); 275 if (assetUriArray) { 276 distrUriArray = assetUriArray; 277 } 278 // 1.2 创建分布式数据对象 279 let contentInfo: ContentInfo = new ContentInfo( 280 AppStorage.get('mainTitle'), 281 AppStorage.get('textContent'), 282 AppStorage.get('imageUriArray'), 283 AppStorage.get('isShowLocalInfo'), 284 AppStorage.get('isAddLocalInfo'), 285 AppStorage.get('selectLocalInfo'), 286 ); 287 let source = contentInfo.flatAssets(); 288 this.distributedObject = distributedDataObject.create(this.context, source); 289 290 // 1.3 将需要设置的分布式对象的资产或资产数组填充完成 291 if (assetUriArray?.length == 1) { 292 this.distributedObject?.setAsset('attachments', distrUriArray[0]). then(() => { 293 console.info('OnContinue setAsset'); 294 }) 295 } else { 296 this.distributedObject?.setAssets('attachments', distrUriArray). then(() => { 297 console.info('OnContinue setAssets'); 298 }) 299 } 300 // 1.4 将设置的资产或资产数组保存至迁移发起端 301 this.distributedObject?.setSessionId(sessionId); 302 this.distributedObject?.save(wantParam.targetDevice as string).catch((err: BusinessError) => { 303 console.error('OnContinue failed to save. code: ', err.code); 304 console.error('OnContinue failed to save. message: ', err.message); 305 }); 306 } catch (error) { 307 console.error('OnContinue faild code: ', error.code); 308 console.error('OnContinue faild message: ', error.message); 309 } 310 console.info("OnContinue success!"); 311 return AbilityConstant.OnContinueResult.AGREE; 312 } 313 314 // 2. 接收端在onCreate和onNewWant接口中创建分布式数据对象并加入组网进行数据恢复 315 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 316 if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 317 if (want.parameters && want.parameters.distributedSessionId) { 318 this.restoreDistributedObject(want); 319 } 320 } 321 } 322 323 // 2. 接收端在onCreate和onNewWant接口中创建分布式数据对象并加入组网进行数据恢复 324 onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { 325 if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 326 if (want.parameters && want.parameters.distributedSessionId) { 327 this.restoreDistributedObject(want); 328 } 329 } 330 } 331 332 async restoreDistributedObject(want: Want): Promise<void> { 333 if (!want.parameters || !want.parameters.distributedSessionId) { 334 console.error(TAG + 'missing sessionId'); 335 return; 336 } 337 338 // 2.1 调用create接口创建并得到一个分布式数据对象实例 339 let mailInfo: ContentInfo = new ContentInfo(undefined, undefined, [], undefined, undefined, undefined, undefined); 340 dataObject = distributedDataObject.create(this.context, mailInfo); 341 342 // 2.2 注册恢复状态监听。收到状态为'restored'的回调通知时,表示接收端分布式数据对象已恢复发起端保存过来的数据(有资产数据时,对应的文件也迁移过来了) 343 dataObject.on('status', (sessionId: string, networkId: string, status: string) => { 344 console.log(TAG + `status change, sessionId: ${sessionId}`); 345 console.log(TAG + `status change, networkId: ${networkId}`); 346 if (status == 'restored') { // 收到'restored'的状态通知表示已恢复发起端保存的数据 347 console.log(TAG + `title: ${dataObject['title']}, text: ${dataObject['text']}`); 348 AppStorage.setOrCreate('mainTitle', dataObject['mainTitle']); 349 AppStorage.setOrCreate('textContent', dataObject['textContent']); 350 AppStorage.setOrCreate('imageUriArray', dataObject['imageUriArray']); 351 AppStorage.setOrCreate('isShowLocalInfo', dataObject['isShowLocalInfo']); 352 AppStorage.setOrCreate('isAddLocalInfo', dataObject['isAddLocalInfo']); 353 AppStorage.setOrCreate('selectLocalInfo', dataObject['selectLocalInfo']); 354 AppStorage.setOrCreate<Array<ImageInfo>>('imageUriArray', this.imageUriArray); 355 } 356 }); 357 358 // 2.3 从want.parameters中获取发起端放入的sessionId,调用setSessionId接口设置同步的sessionId 359 let sessionId = want.parameters.distributedSessionId as string; 360 console.log(TAG + `get sessionId: ${sessionId}`); 361 dataObject.setSessionId(sessionId); 362 } 363} 364``` 365 366### 在多端协同中使用分布式数据对象 367 3681. 调用端调用startAbilityByCall接口拉起对端Ability: 369 370 1.1 调用genSessionId接口创建一个sessionId,通过分布式设备管理接口获取对端设备networkId。 371 372 1.2 组装want,并将sessionId放入want。 373 374 1.3 调用startAbilityByCall接口拉起对端Ability。 375 3762. 调用端拉起对端Ability后创建分布式数据对象并加入组网: 377 378 2.1 创建分布式数据对象实例。 379 380 2.2 注册数据变更监听。 381 382 2.3 设置同步sessionId加入组网。 383 3843. 被调用端被拉起后创建和恢复分布式数据对象: 385 386 3.1 创建分布式数据对象实例。 387 388 3.2 注册数据变更监听。 389 390 3.3 从want中获取源端放入的sessionId,使用这个sessionId加入组网。 391 392> **说明:** 393> 394> - 暂时只支持<!--RP3-->在[跨设备Call调用实现的多端协同](../application-models/hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)中使用分布式数据对象进行数据同步。<!--RP3End--> 395> 396> - 跨设备Call调用实现的多端协同开发<!--RP4-->需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限和配置单实例启动标签,详见跨设备Call调用实现的多端协同的[开发步骤](../application-models/hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)。<!--RP4End--> 397> 398> - wantParam中的"sessionId"字段可能被其他服务占用,建议自定义一个key存取sessionId。 399> 400> - 使用分布式设备管理获取对端设备networkId详见[设备信息查询开发指导](../distributedservice/devicemanager-guidelines.md#设备信息查询开发指导)。 401 402 示例代码如下: 403 404```ts 405import { AbilityConstant, Caller, common, UIAbility, Want } from '@kit.AbilityKit'; 406import { distributedDataObject } from '@kit.ArkData'; 407import { distributedDeviceManager } from '@kit.DistributedServiceKit'; 408import { BusinessError } from '@kit.BasicServicesKit'; 409import { JSON } from '@kit.ArkTS'; 410 411// 业务数据定义 412class Data { 413 title: string | undefined; 414 text: string | undefined; 415 416 constructor(title: string | undefined, text: string | undefined) { 417 this.title = title; 418 this.text = text; 419 } 420} 421 422const TAG = '[DistributedDataObject]'; 423 424let sessionId: string; 425let caller: Caller; 426let dataObject: distributedDataObject.DataObject; 427const changeCallBack: distributedDataObject.DataObserver = (sessionId: string, fields: Array<string>) => { 428 console.info(`change, sessionId: ${sessionId}, fields: ${JSON.stringify(fields)}`); 429} 430 431export default class EntryAbility extends UIAbility { 432 // 1. 调用端调用startAbilityByCall接口拉起对端Ability 433 callRemote() { 434 if (caller) { 435 console.error(TAG + 'call remote already'); 436 return; 437 } 438 439 // 1.1 调用genSessionId接口创建一个sessionId,通过分布式设备管理接口获取对端设备networkId 440 sessionId = distributedDataObject.genSessionId(); 441 console.log(TAG + `gen sessionId: ${sessionId}`); 442 let deviceId = getRemoteDeviceId(); 443 if (deviceId == "") { 444 console.warn(TAG + 'no remote device'); 445 return; 446 } 447 console.log(TAG + `get remote deviceId: ${deviceId}`); 448 449 // 1.2 组装want,并将sessionId放入want 450 let want: Want = { 451 bundleName: 'com.example.collaboration', 452 abilityName: 'EntryAbility', 453 deviceId: deviceId, 454 parameters: { 455 'ohos.aafwk.param.callAbilityToForeground': true, // 前台启动,非必须 456 'distributedSessionId': sessionId 457 } 458 } 459 try { 460 // 1.3 调用startAbilityByCall接口拉起对端Ability 461 this.context.startAbilityByCall(want).then((res) => { 462 if (!res) { 463 console.error(TAG + 'startAbilityByCall failed'); 464 } 465 caller = res; 466 }) 467 } catch (e) { 468 let err = e as BusinessError; 469 console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 470 } 471 } 472 473 // 2. 拉起对端Ability后创建分布式数据对象 474 createDataObject() { 475 if (!caller) { 476 console.error(TAG + 'call remote first'); 477 return; 478 } 479 if (dataObject) { 480 console.error(TAG + 'create dataObject already'); 481 return; 482 } 483 484 // 2.1 创建分布式数据对象实例 485 let data = new Data('The title', 'The text'); 486 dataObject = distributedDataObject.create(this.context, data); 487 488 // 2.2 注册数据变更监听 489 dataObject.on('change', changeCallBack); 490 // 2.3 设置同步sessionId加入组网 491 dataObject.setSessionId(sessionId); 492 } 493 494 // 3. 被调用端被拉起后创建和恢复分布式数据对象 495 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 496 if (want.parameters && want.parameters.distributedSessionId) { 497 // 3.1 创建分布式数据对象实例 498 let data = new Data(undefined, undefined); 499 dataObject = distributedDataObject.create(this.context, data); 500 501 // 3.2 注册数据变更监听 502 dataObject.on('change', changeCallBack); 503 // 3.3 从want中获取源端放入的sessionId,使用这个sessionId加入组网 504 let sessionId = want.parameters.distributedSessionId as string; 505 console.log(TAG + `onCreate get sessionId: ${sessionId}`); 506 dataObject.setSessionId(sessionId); 507 } 508 } 509} 510 511// 获取可信组网中的设备 512function getRemoteDeviceId() { 513 let deviceId = ""; 514 try { 515 let deviceManager = distributedDeviceManager.createDeviceManager('com.example.collaboration'); 516 let devices = deviceManager.getAvailableDeviceListSync(); 517 if (devices[0] && devices[0].networkId) { 518 deviceId = devices[0].networkId; 519 } 520 } catch (e) { 521 let err = e as BusinessError; 522 console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 523 } 524 return deviceId; 525} 526``` 527 528## 相关实例 529 530针对分布式数据对象开发,有以下相关实例可供参考: 531 532- [设备管理(ArkTS)(Full SDK)(API10)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/SystemFeature/DistributedAppDev/DistributedAuthentication) 533 534- [分布式备忘录(ArkTS)(Full SDK)(API10)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedNote)