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 and request continuation. The value **AGREE** means that the continuation is accepted, and **REJECT** means the continuation is rejected, and **MISMATCH** means a version mismatch.| 16| onCreate(want: Want, param: LaunchParam): void | Called by the target to restore the data and UI page.| 17| **enum** OnContinueResult | Enumerates the return values of **onContinue**. The options are as follows: **AGREE** (request accepted), **REJECT** (request denied), and **MISMATCH** (version mismatch).| 18 19 20 21**Figure 1** Ability continuation development 22 23 24 25## How to Develop 26 27### Application Continuation 28 291. Configuration 30 31 - Configure the application to support ability continuation. 32 33 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. 34 35 ```javascript 36 "continuable": true 37 ``` 38 39 40 41 - Configure the application startup type. 42 43 Set **launchType** in the **module.json5** file to **standard** to add multi-instance support to the application. 44 45 ```javascript 46 "launchType": "standard" 47 ``` 48 49 50 51 - Apply for the distributed permissions. 52 53 Declare the **DISTRIBUTED_DATASYNC** permission in the **module.json5** file for the application. 54 55 ```javascript 56 "requestPermissions": [ 57 { 58 "name": "ohos.permission.DISTRIBUTED_DATASYNC" 59 }, 60 ``` 61 62 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: 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. Implement the **onContinue()** API. 104 105 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 **OnContinueResult.AGREE(0)** to accept the continuation request. If an error code is returned, the request is rejected. If this API is not implemented, the system rejects the continuation request by default. 106 107 Modules to import: 108 109 ```javascript 110 import Ability from '@ohos.application.Ability'; 111 import AbilityConstant from '@ohos.application.AbilityConstant'; 112 ``` 113 114 To implement ability continuation, you must implement this API and have the value **AGREE** returned. 115 116 117 Example 118 119 ```javascript 120 onContinue(wantParam : {[key: string]: any}) { 121 Logger.info("onContinue using distributedObject") 122 // Set the 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. Implement the continuation logic in the **onCreate()** API. 132 133 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. 134 135 The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate()**. 136 137 138 After data restore is complete, call **restoreWindowStage** to trigger page restoration. 139 140 141 Example 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 // Obtain 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### Data Continuation 161 162Use distributed objects. 163 164Distributed 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 [Distributed Data Object Development](../database/database-distributedobject-guidelines.md). 165 166In the ability continuation scenario, the distributed data object is used to synchronize the memory data from the local device to the target device. 167 168- In **onContinue()**, the initiator saves the data to be continued to the distributed object, sets the session ID, and sends the session ID to the target device through **wantParam**. 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 the session ID for the distributed data object. 184 g_object.setSessionId(this.sessionId); 185 g_object.name = "Amy"; 186 // Set the session ID into the want parameter. 187 wantParam["session"] = this.sessionId; 188 return AbilityConstant.OnContinueResult.AGREE 189 } 190 191 ``` 192 193- 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. 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 // Obtain the session ID of the distributed data object from the want parameter. 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 the session ID for data synchronization. 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 229For details about the complete example, see the sample. 230 231 232 233