• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Ability Continuation Development
2
3## When to Use
4
5Ability continuation is to continue the current mission of an application, including the UI component state variables and distributed objects, on another device. The UI component state variables are used to synchronize UI data, and the distributed objects are used to synchronize memory data.
6
7## Available APIs
8
9The following table lists the APIs used for ability continuation. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md).
10
11**Table 1** Ability continuation APIs
12
13|API| Description|
14|:------ | :------|
15| onContinue(wantParam : {[key: string]: any}): OnContinueResult | Called by the initiator to store the data required for continuation. The return value indicates whether the continuation request is accepted. The value **AGREE** means that the continuation request is accepted, **REJECT** means that the continuation request is rejected, and **MISMATCH** means a version mismatch.|
16| onCreate(want: Want, param: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the multi-instance ability scenario.|
17| onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the singleton ability scenario.|
18
19
20
21**Figure 1** Ability continuation development
22
23![continuation_dev](figures/continuation-info.png)
24
25In effect, ability continuation is a cross-device ability startup that carries data. When a continuation action is initiated, the system on device A calls back **onContinue()** of the application. You must implement storage of the current data in this API. Then, the system initiates a cross-device ability startup on device B and transmits the data to device B. The system on device B calls back **onCreate()** or **onNewWant()**. You must implement restoration of the transmitted data in this API.
26
27## How to Develop
28
29The code snippets provided below are all from [Sample](https://gitee.com/openharmony/ability_dmsfwk/tree/master/services/dtbschedmgr/test/samples/continuationManualTestSuite).
30
31### Application Continuation
32
331. Modify the configuration file.
34
35   - Configure the application to support ability continuation.
36
37     Set the **continuable** field in the **module.json5** file to **true**. The default value is **false**. If this parameter is set to **false**, the application cannot be continued on another device.
38
39     ```javascript
40     {
41       "module": {
42         "abilities": [
43           {
44             "continuable": true
45           }
46         ]
47       }
48     }
49     ```
50
51
52   - Configure the application startup type.
53
54        If **launchType** is set to **multiton** in the **module.json5** file, the application is of the multi-instance launch type. During ability continuation, regardless of whether the application is already open, the target starts the application and restores the UI page. If **launchType** is set to **singleton**, the application is of the singleton launch type. If the application is already open, the target clears the existing page stack and restores the UI page. For more information, see "Launch Type" in [Ability Development](./stage-ability.md).
55
56        Configure a multi-instance application as follows:
57
58        ```javascript
59        {
60          "module": {
61            "abilities": [
62              {
63                "launchType": "multiton"
64              }
65            ]
66          }
67        }
68        ```
69
70        Configure a singleton application as follows or retain the default settings of **launchType**:
71
72        ```javascript
73        {
74          "module": {
75            "abilities": [
76              {
77                "launchType": "singleton"
78              }
79            ]
80          }
81        }
82        ```
83
84   - Apply for the distributed permissions.
85
86        Declare the **DISTRIBUTED_DATASYNC** permission in the **module.json5** file for the application.
87
88        ```javascript
89        "requestPermissions": [
90               {
91                   "name": "ohos.permission.DISTRIBUTED_DATASYNC"
92               },
93        ```
94
95        This permission must be granted by the user in a dialog box when the application is started for the first time. To enable the application to display a dialog box to ask for the permission, add the following code to **onWindowStageCreate** of the **Ability** class:
96
97        ```javascript
98           requestPermissions = async () => {
99               let permissions: Array<string> = [
100                   "ohos.permission.DISTRIBUTED_DATASYNC"
101               ];
102               let needGrantPermission = false
103               let accessManger = accessControl.createAtManager()
104               Logger.info("app permission get bundle info")
105               let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100)
106               Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`)
107               for (const permission of permissions) {
108                   Logger.info(`app permission query grant status ${permission}`)
109                   try {
110                       let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission)
111                       if (grantStatus === PERMISSION_REJECT) {
112                           needGrantPermission = true
113                           break;
114                       }
115                   } catch (err) {
116                       Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`)
117                       needGrantPermission = true
118                       break;
119                   }
120               }
121               if (needGrantPermission) {
122                   Logger.info("app permission needGrantPermission")
123                   try {
124                       await accessManger.requestPermissionsFromUser(this.context, permissions)
125                   } catch (err) {
126                       Logger.error(`app permission ${JSON.stringify(err)}`)
127                   }
128               } else {
129                   Logger.info("app permission already granted")
130               }
131           }
132        ```
133
134
135
1362. Implement the **onContinue()** API.
137
138   The **onContinue()** API is called by the initiator to save the UI component state variables and memory data and prepare for continuation. After the application completes the continuation preparation, the system must return either **OnContinueResult.AGREE(0)** to accept the continuation request or an error code to reject the request. If this API is not implemented, the system rejects the continuation request by default.
139
140   Modules to import:
141
142   ```javascript
143   import Ability from '@ohos.application.Ability';
144   import AbilityConstant from '@ohos.application.AbilityConstant';
145   ```
146
147   To implement ability continuation, you must implement this API and have the value **AGREE** returned.
148
149   You can obtain the target device ID (identified by the key **targetDevice**) and the version number (identified by the key **version**) of the application installed on the target device from the **wantParam** parameter of this API. The version number can be used for compatibility check. If the current application version is incompatible with that on the target device, **OnContinueResult.MISMATCH** can be returned to reject the continuation request.
150
151   Example:
152
153   ```javascript
154        onContinue(wantParam : {[key: string]: any}) {
155            Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`)
156            let workInput = AppStorage.Get<string>('ContinueWork');
157            // Set the user input data into wantParam.
158            wantParam["work"] = workInput // set user input data into want params
159            Logger.info(`onContinue input = ${wantParam["input"]}`);
160            return AbilityConstant.OnContinueResult.AGREE
161        }
162   ```
163
1643. Implement the continuation logic in the **onCreate()** or **onNewWant()** API.
165
166   The **onCreate()** API is called by the target. When the ability is started on the target device, this API is called to instruct the application to synchronize the memory data and UI component state, and triggers page restoration after the synchronization is complete. If the continuation logic is not implemented, the ability will be started in common startup mode and the page cannot be restored.
167
168   The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate()**.
169
170   After data restore is complete, call **restoreWindowStage** to trigger page restoration.
171
172   You can also use **want.parameters.version** in the **want** parameter to obtain the application version number of the initiator.
173
174   Example:
175
176   ```javascript
177    import Ability from '@ohos.application.Ability';
178    import distributedObject from '@ohos.data.distributedDataObject';
179
180    export default class MainAbility extends Ability {
181        storage : LocalStorag;
182
183        onCreate(want, launchParam) {
184            Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
185            if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
186                // Obtain the user data from the want parameter.
187                let workInput = want.parameters.work
188                Logger.info(`work input ${workInput}`)
189                AppStorage.SetOrCreate<string>('ContinueWork', workInput)
190
191                this.storage = new LocalStorage();
192                this.context.restoreWindowStage(this.storage);
193            }
194        }
195    }
196   ```
197For a singleton ability, use **onNewWant()** to achieve the same implementation.
198
199### Data Continuation
200
201Use distributed objects.
202
203Distributed objects allow cross-device data synchronization like local variables. For two devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other device. Both devices can listen for the data changes and online and offline states of the other. For details, see [Sharing Distributed Data Objects](../database/data-sync-of-distributed-data-object.md).
204
205In the ability continuation scenario, the distributed data object is used to synchronize the memory data from the local device to the target device. For details, see [Distributed Data Object Development](../database/database-distributedobject-guidelines.md).
206
207- In **onContinue()**, the initiator saves the data to be migrated to the distributed object, calls the **save()** API to save the data and synchronize the data to the target device, sets the session ID, and sends the session ID to the target device through **wantParam**.
208
209  ```javascript
210     import Ability from '@ohos.application.Ability';
211     import distributedObject from '@ohos.data.distributedDataObject';
212
213     var g_object = distributedObject.createDistributedObject({data:undefined});
214
215     export default class MainAbility extends Ability {
216         sessionId : string;
217
218      onContinue(wantParam : {[key: string]: any}) {
219        Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`)
220
221        if (g_object.__sessionId === undefined) {
222            this.sessionId = distributedObject.genSessionId()
223            Logger.info(`onContinue generate new sessionId`)
224        }
225        else {
226            this.sessionId = g_object.__sessionId;
227        }
228
229        wantParam["session"] = this.sessionId
230        g_object.data = AppStorage.Get<string>('ContinueStudy');
231        Logger.info(`onContinue sessionId = ${this.sessionId}, name = ${g_object.data}`)
232        g_object.setSessionId(this.sessionId);
233        g_object.save(wantParam.targetDevice, (result, data)=>{
234            Logger.info("save callback");
235            Logger.info("save sessionId " + data.sessionId);
236            Logger.info("save version " + data.version);
237            Logger.info("save deviceId " + data.deviceId);
238        });
239  ```
240
241- The target device obtains the session ID from **onCreate()**, creates a distributed object, and associates the distributed object with the session ID. In this way, the distributed object can be synchronized. Before calling **restoreWindowStage**, ensure that all distributed objects required for continuation have been associated.
242
243  ```javascript
244     import Ability from '@ohos.application.Ability';
245     import distributedObject from '@ohos.data.distributedDataObject';
246
247     var g_object = distributedObject.createDistributedObject({data:undefined});
248
249     export default class MainAbility extends Ability {
250         storage : LocalStorag;
251
252
253         onCreate(want, launchParam) {
254             Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
255             if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
256              // Obtain the session ID of the distributed data object from the want parameter.
257                 this.sessionId = want.parameters.session
258                 Logger.info(`onCreate for continuation sessionId:  ${this.sessionId}`)
259
260              // Before fetching data from the remote device, reset g_object.data to undefined.
261                g_object.data = undefined;
262                // Set the session ID, so the target will fetch data from the remote device.
263                g_object.setSessionId(this.sessionId);
264
265                AppStorage.SetOrCreate<string>('ContinueStudy', g_object.data)
266                this.storage = new LocalStorage();
267                this.context.restoreWindowStage(this.storage);
268             }
269
270         }
271     }
272  ```
273
274### More Information
275
2761. Timeout
277
278   - If the application to be continued is not installed on the target device, the system checks whether the application can be installed on it and waits for a response for 4 seconds. If no response is received within 4 seconds, the caller receives a timeout error code, which means that the application cannot be installed on the target device. If the application can be installed, the system prompts the consumer to install the application on the target device. The consumer can initiate the continuation again after the installation.
279   -  If the application to be continued has been installed on the target device, the system waits for a response to the continuation request for 20 seconds. If no response is received within 20 seconds, the caller receives a timeout error code, which means that the continuation fails.
280
2812. By default, the system supports page stack information migration, which means that the page stack of the initiator will be automatically migrated to the target device. No adaptation is required.
282
283### Restrictions
284
2851.   The continuation must be performed between the same ability, which means the same bundle name, module name, and ability name. For details, see [Application Package Structure Configuration File](../quick-start/module-configuration-file.md).
2862.    Currently, the application can only implement the continuation capability. The continuation action must be initiated by the system.
287
288### Best Practice
289
290For better user experience, you are advised to use the **wantParam** parameter to transmit data smaller than 100 KB and use distributed objects to transmit data larger than 100 KB.
291