• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 跨端迁移开发指导
2
3## 场景介绍
4
5迁移的主要工作是实现将应用当前任务,包括页面控件状态变量、分布式对象等,迁移到远端设备。页面控件状态变量用于同步页面UI数据,分布式对象用于同步内存中的数据。
6
7## 接口说明
8
9迁移提供的能力如下,具体的API详见[接口文档](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-application-ability.md)10
11**表1** 应用迁移API接口功能介绍
12
13|接口名 | 描述|
14|:------ | :------|
15| onContinue(wantParam : {[key: string]: any}): OnContinueResult | 迁移**发起端**在该回调中保存迁移所需要的数据,同时返回是否同意迁移:0表示同意,拒绝返回相应错误码。 |
16| onCreate(want: Want,param:LaunchParam): void | 迁移**目标端**在该回调中完成数据恢复,并触发页面恢复。 |
17| **enum** OnContinueResult | onContinue的返回值类型:AGREE表示同意;REJECT表示拒绝;MISMATCH表示版本不匹配 |
18
19
20
21**图1** 迁移开发示意图
22
23![continuation_dev](figures/continuation-info.png)
24
25## 开发步骤
26
27### 迁移应用
28
291. 配置
30
31   - 配置应用支持迁移
32
33module.json5中配置continuable字段:true表示支持迁移,false表示不支持,默认为false。配置为false的应用将被系统识别为无法迁移。
34
35   ```javascript
36   "continuable": true
37   ```
38
39
40
41   * 配置应用启动类型
42
43     迁移当前只支持多实例应用,需要在在module.json5中配置launchType字段为standard。
44
45   ```javascript
46   "launchType": "standard"
47   ```
48
49
50
51   * 申请分布式权限
52
53     支持跨端迁移的应用需要在module.json5申请分布式权限 DISTRIBUTED_DATASYNC。
54
55   ```javascript
56   "requestPermissions": [
57       {
58           "name": "ohos.permission.DISTRIBUTED_DATASYNC"
59       },
60   ```
61
62   这个权限需要在应用首次启动的时候弹窗让用户授予,可以通过在ability的onWindowStageCreate中添加如下代码实现:
63
64   ```javascript
65   requestPermissions = async () => {
66       let permissions: Array<string> = [
67           "ohos.permission.DISTRIBUTED_DATASYNC"
68       ];
69       let needGrantPermission = false
70       let accessManger = accessControl.createAtManager()
71       Logger.info("app permission get bundle info")
72       let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100)
73       Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`)
74       for (const permission of permissions) {
75           Logger.info(`app permission query grant status ${permission}`)
76           try {
77               let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission)
78               if (grantStatus === PERMISSION_REJECT) {
79                   needGrantPermission = true
80                   break;
81               }
82           } catch (err) {
83               Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`)
84               needGrantPermission = true
85               break;
86           }
87       }
88       if (needGrantPermission) {
89           Logger.info("app permission needGrantPermission")
90           try {
91               await this.context.requestPermissionsFromUser(permissions)
92           } catch (err) {
93               Logger.error(`app permission ${JSON.stringify(err)}`)
94           }
95       } else {
96           Logger.info("app permission already granted")
97       }
98   }
99   ```
100
101
102
1032. 实现onContinue接口
104
105   onContinue接口在**发起端**被调用,主要用于在迁移发起时,通知开发者保存控件状态变量和内存中数据,准备迁移。当应用准备完成后,需要返回OnContinueResult.AGREE(0)表示同意迁移,否则返回相应的错误码拒绝迁移。如果不实现该接口,系统将默认为拒绝迁移。
106
107   导入模块
108
109   ```javascript
110   import Ability from '@ohos.application.Ability';
111   import AbilityConstant from '@ohos.application.AbilityConstant';
112   ```
113
114   - 要实现迁移,此接口必须实现并返回AGREE,否则默认为拒绝迁移。
115
116
117   - 示例
118
119   ```javascript
120    onContinue(wantParam : {[key: string]: any}) {
121        Logger.info("onContinue using distributedObject")
122        // set user input data into want params
123        wantParam["input"] = AppStorage.Get<string>('ContinueInput');
124        Logger.info(`onContinue input = ${wantParam["input"]}`);
125        return AbilityConstant.OnContinueResult.AGREE
126    }
127   ```
128
129
130
1313. 在onCreate接口中实现迁移逻辑
132
133   onCreate接口在迁移**目标端**被调用,在目标端ability被拉起时,通知开发者同步已保存的内存数据和控件状态,完成后触发页面的恢复。如果不实现该接口中迁移相关逻辑,ability将会作为普通的启动方式拉起,无法恢复页面。
134
135   - 远端设备上,在onCreate中根据launchReason判断该次启动是否为迁移LaunchReason.CONTINUATION
136
137
138   - 完成数据恢复后,开发者需要调用**restoreWindowStage**来触发页面恢复。
139
140
141   * 示例
142
143   ```javascript
144       onCreate(want, launchParam) {
145           Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
146           globalThis.abilityWant = want;
147           if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
148               let input = want.parameters.input // get user data from want params
149               AppStorage.SetOrCreate<string>('ContinueInput', input)
150               Logger.info(`onCreate for continuation sessionId:  ${this.sessionId}`)
151
152               this.contentStorage = new ContentStorage();
153               this.context.restoreWindowStage(this.contentStorage);
154           }
155       }
156   ```
157
158
159
160### 迁移数据
161
1621. 使用分布式对象
163
164   分布式数据对象提供了与本地变量类似的操作,实现两个设备的数据同步,当设备1的应用A的分布式数据对象增、删、改数据后,设备2的应用A也可以获取到对应的数据变化,同时还能监听数据变更以及对端数据对象的上下线。用法详见[分布式对象指导文档](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/database/database-distributedobject-guidelines.md)165
166   迁移场景中,分布式对象(distributedDataObject)主要用于将本机内存数据同步到目标设备。
167
168   - 发起端在onContinue中,将待迁移的数据存入分布式对象中,然后设置好session id,并通过wantParam将session id传到远端设备。
169
170    ```javascript
171      import Ability from '@ohos.application.Ability';
172      import distributedObject from '@ohos.data.distributedDataObject';
173
174      var g_object = distributedObject.createDistributedObject({name:undefined});
175
176      export default class MainAbility extends Ability {
177          contentStorage : ContentStorage
178          sessionId : string;
179
180       onContinue(wantParam : {[key: string]: any}) {
181           Logger.info("onContinue using distributedObject")
182           this.sessionId = distributedObject.genSessionId();
183           //set distributed data object session id
184           g_object.setSessionId(this.sessionId);
185           g_object.name = "Amy";
186           // set session id into want params
187           wantParam["session"] = this.sessionId;
188           return AbilityConstant.OnContinueResult.AGREE
189       }
190
191    ```
192
193   - 目标设备在onCreate中,取出发起端传过来的session id,建立分布式对象并关联该session id,这样就能实现分布式对象的同步。需要注意的是,在调用restoreWindowStage之前,迁移需要的分布式对象必须全部关联完,保证能够获取到正确的数据。
194
195   ```javascript
196      import Ability from '@ohos.application.Ability';
197      import distributedObject from '@ohos.data.distributedDataObject';
198
199      var g_object = distributedObject.createDistributedObject({name:undefined});
200
201      export default class MainAbility extends Ability {
202          contentStorage : ContentStorage
203          sessionId : string;
204
205          statusCallback(sessionId, networkid, status) {
206              Logger.info(`continuation object status change, sessionId: ${sessionId}, status: ${status}, g_object.name: ${g_object.name}`)
207          }
208
209          onCreate(want, launchParam) {
210              Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
211              if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
212                  // get distributed data object session id from want params
213                  this.sessionId = want.parameters.session
214                  Logger.info(`onCreate for continuation sessionId:  ${this.sessionId}`)
215
216                  g_object.on("status", this.statusCallback);
217                  // set session id, so it will sync data from remote device
218                  g_object.setSessionId(this.sessionId);
219
220                  this.contentStorage = new ContentStorage();
221                  this.context.restoreWindowStage(this.contentStorage);
222              }
223          }
224      }
225   ```
226
227
228
229以上完整的示例见sample
230
231
232
233