1# Continuous Task Development 2 3## When to Use 4 5If an application has a perceivable task that needs to run in an extended period of time in the background, it can request a continuous task so that it will not be suspended. Examples of continuous tasks include music playback, navigation, device connection, and VoIP. 6There is no time limit for a continuous task running in the background. To prevent abuse, the system limits the number of continuous tasks that can be requested. It also attaches a notification to each of the tasks so that the tasks are perceivable. In addition, the system verifies whether the application is actually executing a continuous task. 7 8## Available APIs 9 10**Table 1** Main APIs for continuous tasks 11 12| API | Description | 13| ---------------------------------------- | ---------------------------- | 14| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: WantAgent): Promise<void> | Requests a continuous task from the system so that the application keeps running in the background.| 15| stopBackgroundRunning(context: Context): Promise<void> | Cancels the continuous task. | 16 17 18For details about **wantAgent**, see [WantAgent](../reference/apis/js-apis-wantAgent.md). 19 20**Table 2** Background modes 21 22| Name | Description | Item | 23| ----------------------- | -------------- | --------------------- | 24| DATA_TRANSFER | Data transfer. | dataTransfer | 25| AUDIO_PLAYBACK | Audio playback. | audioPlayback | 26| AUDIO_RECORDING | Audio recording. | audioRecording | 27| LOCATION | Positioning and navigation. | location | 28| BLUETOOTH_INTERACTION | Bluetooth-related task. | bluetoothInteraction | 29| MULTI_DEVICE_CONNECTION | Multi-device connection. | multiDeviceConnection | 30| WIFI_INTERACTION | WLAN-related task (reserved). | wifiInteraction | 31| VOIP | Voice and video call (reserved). | voip | 32| TASK_KEEPING | Computing task (for specific devices only).| taskKeeping | 33 34 35## How to Develop 36 37### Development in the FA Model 38 39For details about how to use the ServiceAbility in the FA model, see [ServiceAbility Component Overview](../application-models/serviceability-overview.md). 40 41If an application does not need to interact with a continuous task in the background, you can use **startAbility()** to start the ServiceAbility. In the **onStart** callback of the ServiceAbility, call **startBackgroundRunning()** to declare that the ServiceAbility needs to run in the background for a long time. After the task execution is complete, call **stopBackgroundRunning()** to release resources. 42 43If an application needs to interact with a continuous task in the background (for example, an application related to music playback), you can use **connectAbility()** to start and connect to the ServiceAbility. After obtaining the proxy of the ServiceAbility, the application can communicate with the ServiceAbility and control the request and cancellation of continuous tasks. 44 451. Configure the continuous task permission **ohos.permission.KEEP_BACKGROUND_RUNNING** in the **config.json** file, and declare the corresponding background mode type for the ServiceAbility that needs to use the task. 46 47 ``` 48 "module": { 49 "package": "com.example.myapplication", 50 "abilities": [ 51 { 52 "backgroundModes": [ 53 "dataTransfer", 54 "location" 55 ], // Background mode 56 "type": "service" // The ability type is Service. 57 } 58 ], 59 "reqPermissions": [ 60 { 61 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission 62 } 63 ] 64 } 65 ``` 66 672. Call the APIs for requesting and canceling a continuous task in the ServiceAbility. 68 69 ```js 70 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 71 import featureAbility from '@ohos.ability.featureAbility'; 72 import wantAgent from '@ohos.wantAgent'; 73 import rpc from "@ohos.rpc"; 74 75 function startContinuousTask() { 76 let wantAgentInfo = { 77 // List of operations to be executed after the notification is clicked. 78 wants: [ 79 { 80 bundleName: "com.example.myapplication", 81 abilityName: "com.example.myapplication.MainAbility" 82 } 83 ], 84 // Type of the operation to perform after the notification is clicked. 85 operationType: wantAgent.OperationType.START_ABILITY, 86 // Custom request code. 87 requestCode: 0, 88 // Execution attribute of the operation to perform after the notification is clicked. 89 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 90 }; 91 92 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 93 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 94 try { 95 backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(), 96 backgroundTaskManager.BackgroundMode.DATA_TRANSFER, wantAgentObj).then(() => { 97 console.info("Operation startBackgroundRunning succeeded"); 98 }).catch((err) => { 99 console.error("Operation startBackgroundRunning failed Cause: " + err); 100 }); 101 } catch (error) { 102 console.error(`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 103 } 104 }); 105 } 106 107 function stopContinuousTask() { 108 try { 109 backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => { 110 console.info("Operation stopBackgroundRunning succeeded"); 111 }).catch((err) => { 112 console.error("Operation stopBackgroundRunning failed Cause: " + err); 113 }); 114 } catch (error) { 115 console.error(`Operation stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 116 } 117 } 118 119 async function processAsyncJobs() { 120 // Execute the continuous task. 121 122 // After the continuous task is complete, call the API to release resources. 123 stopContinuousTask(); 124 } 125 126 let mMyStub; 127 128 class MyStub extends rpc.RemoteObject { 129 constructor(des) { 130 if (typeof des === 'string') { 131 super(des); 132 } else { 133 return null; 134 } 135 } 136 onRemoteRequest(code, data, reply, option) { 137 console.log('ServiceAbility onRemoteRequest called'); 138 // The meaning of code is user-defined. 139 if (code === 1) { 140 // Receive the request code for requesting a continuous task. 141 startContinuousTask(); 142 // Execute the continuous task. 143 } else if (code === 2) { 144 // Receive the request code for canceling the continuous task. 145 stopContinuousTask(); 146 } else { 147 console.log('ServiceAbility unknown request code'); 148 } 149 return true; 150 } 151 } 152 153 export default { 154 onStart(want) { 155 console.info('ServiceAbility onStart'); 156 mMyStub = new MyStub("ServiceAbility-test"); 157 // Call the API to start the task. 158 startContinuousTask(); 159 processAsyncJobs(); 160 }, 161 onStop() { 162 console.info('ServiceAbility onStop'); 163 }, 164 onConnect(want) { 165 console.info('ServiceAbility onConnect'); 166 return mMyStub; 167 }, 168 onReconnect(want) { 169 console.info('ServiceAbility onReconnect'); 170 }, 171 onDisconnect() { 172 console.info('ServiceAbility onDisconnect'); 173 }, 174 onCommand(want, restart, startId) { 175 console.info('ServiceAbility onCommand'); 176 } 177 }; 178 ``` 179 180### Development in the Stage Model 181 182For details about the stage model, see [Stage Model Development Overview](../application-models/stage-model-development-overview.md). 183 1841. Configure the continuous task permission **ohos.permission.KEEP_BACKGROUND_RUNNING** in the **module.json5** file, and declare the corresponding background mode type for the ability that needs to use the task. 185 186 ``` 187 "module": { 188 "abilities": [ 189 { 190 "backgroundModes": [ 191 "dataTransfer", 192 "location" 193 ], // Background mode 194 } 195 ], 196 "requestPermissions": [ 197 { 198 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission 199 } 200 ] 201 } 202 ``` 203 2042. If an application needs to execute a continuous task for its own, include the execution logic in the Page ability. This is because an application cannot use **startAbilityByCall** to create and run its own ability in the background due to the restriction of ability startup controls. For details, see [UIAbility Component Overview](../application-models/uiability-overview.md). 205 206 ```ts 207 import wantAgent from '@ohos.wantAgent'; 208 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 209 210 @Entry 211 @Component 212 struct Index { 213 @State message: string = 'test' 214 // Use getContext to obtain the context of the Page ability. 215 private context: any = getContext(this) 216 217 startContinuousTask() { 218 let wantAgentInfo = { 219 // List of operations to be executed after the notification is clicked. 220 wants: [ 221 { 222 bundleName: "com.example.myapplication", 223 abilityName: "com.example.myapplication.MainAbility", 224 } 225 ], 226 // Type of the operation to perform after the notification is clicked. 227 operationType: wantAgent.OperationType.START_ABILITY, 228 // Custom request code. 229 requestCode: 0, 230 // Execution attribute of the operation to perform after the notification is clicked. 231 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 232 }; 233 234 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 235 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 236 try { 237 backgroundTaskManager.startBackgroundRunning(this.context, 238 backgroundTaskManager.BackgroundMode.DATA_TRANSFER, wantAgentObj).then(() => { 239 console.info("Operation startBackgroundRunning succeeded"); 240 }).catch((err) => { 241 console.error("Operation startBackgroundRunning failed Cause: " + err); 242 }); 243 } catch (error) { 244 console.error(`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 245 } 246 }); 247 } 248 249 stopContinuousTask() { 250 try { 251 backgroundTaskManager.stopBackgroundRunning(this.context).then(() => { 252 console.info("Operation stopBackgroundRunning succeeded"); 253 }).catch((err) => { 254 console.error("Operation stopBackgroundRunning failed Cause: " + err); 255 }); 256 } catch (error) { 257 console.error(`Operation stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 258 } 259 } 260 261 build() { 262 Row() { 263 Column() { 264 Text("Index") 265 .fontSize(50) 266 .fontWeight(FontWeight.Bold) 267 268 Button() { Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold) }.type(ButtonType.Capsule) 269 .margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40) 270 .onClick(() => { 271 // Request a continuous task by clicking a button. 272 this.startContinuousTask(); 273 274 // Execute the continuous task logic, for example, music playback. 275 }) 276 277 Button() {Text('Cancel continuous task') .fontSize(25).fontWeight(FontWeight.Bold) }.type(ButtonType.Capsule) 278 .margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40) 279 .onClick(() => { 280 // Stop the continuous task. 281 282 // Cancel the continuous task by clicking a button. 283 this.stopContinuousTask(); 284 }) 285 } 286 .width('100%') 287 } 288 .height('100%') 289 } 290 } 291 ``` 292 2933. If a continuous task needs to be executed in the background for another application or on another device, you can create and run an ability in the background in Call mode. For details, see [Using Call to Implement UIAbility Interaction (intra-device)](../application-models/uiability-intra-device-interaction.md#using-call-to-implement-uiability-interaction-for-system-applications-only) and [Using Cross-Device Call (inter-device)](../application-models/hop-multi-device-collaboration.md#using-cross-device-call). 294 295 ```ts 296 import UIAbility from '@ohos.app.ability.UIAbility'; 297 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 298 import wantAgent from '@ohos.wantAgent'; 299 300 const MSG_SEND_METHOD: string = 'CallSendMsg' 301 302 let mContext = null; 303 304 function startContinuousTask() { 305 let wantAgentInfo = { 306 // List of operations to be executed after the notification is clicked. 307 wants: [ 308 { 309 bundleName: "com.example.myapplication", 310 abilityName: "com.example.myapplication.MainAbility", 311 } 312 ], 313 // Type of the operation to perform after the notification is clicked. 314 operationType: wantAgent.OperationType.START_ABILITY, 315 // Custom request code. 316 requestCode: 0, 317 // Execution attribute of the operation to perform after the notification is clicked. 318 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 319 }; 320 321 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 322 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 323 try { 324 backgroundTaskManager.startBackgroundRunning(mContext, 325 backgroundTaskManager.BackgroundMode.DATA_TRANSFER, wantAgentObj).then(() => { 326 console.info("Operation startBackgroundRunning succeeded"); 327 }).catch((error) => { 328 console.error(`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 329 }); 330 } catch (error) { 331 console.error(`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 332 } 333 }); 334 } 335 336 function stopContinuousTask() { 337 try { 338 backgroundTaskManager.stopBackgroundRunning(mContext).then(() => { 339 console.info("Operation stopBackgroundRunning succeeded"); 340 }).catch((error) => { 341 console.error(`Operation stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 342 }); 343 } catch (error) { 344 console.error(`Operation stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`); 345 } 346 } 347 348 class MyParcelable { 349 num: number = 0; 350 str: String = ""; 351 352 constructor(num, string) { 353 this.num = num; 354 this.str = string; 355 } 356 357 marshalling(messageSequence) { 358 messageSequence.writeInt(this.num); 359 messageSequence.writeString(this.str); 360 return true; 361 } 362 363 unmarshalling(messageSequence) { 364 this.num = messageSequence.readInt(); 365 this.str = messageSequence.readString(); 366 return true; 367 } 368 } 369 370 function sendMsgCallback(data) { 371 console.info('BgTaskAbility funcCallBack is called ' + data) 372 let receivedData = new MyParcelable(0, "") 373 data.readParcelable(receivedData) 374 console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`) 375 // You can execute different methods based on the str value in the parcelable data sent by the caller. 376 if (receivedData.str === 'start_bgtask') { 377 startContinuousTask() 378 } else if (receivedData.str === 'stop_bgtask') { 379 stopContinuousTask(); 380 } 381 return new MyParcelable(10, "Callee test"); 382 } 383 384 export default class BgTaskAbility extends Ability { 385 onCreate(want, launchParam) { 386 console.info("[Demo] BgTaskAbility onCreate") 387 this.callee.on("test", sendMsgCallback); 388 389 try { 390 this.callee.on(MSG_SEND_METHOD, sendMsgCallback) 391 } catch (error) { 392 console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) 393 } 394 mContext = this.context; 395 } 396 397 onDestroy() { 398 console.info("[Demo] BgTaskAbility onDestroy") 399 } 400 401 onWindowStageCreate(windowStage) { 402 console.info("[Demo] BgTaskAbility onWindowStageCreate") 403 404 windowStage.loadContent("pages/index").then((data)=> { 405 console.info(`load content succeed with data ${JSON.stringify(data)}`) 406 }).catch((error)=>{ 407 console.error(`load content failed with error ${JSON.stringify(error)}`) 408 }) 409 } 410 411 onWindowStageDestroy() { 412 console.info("[Demo] BgTaskAbility onWindowStageDestroy") 413 } 414 415 onForeground() { 416 console.info("[Demo] BgTaskAbility onForeground") 417 } 418 419 onBackground() { 420 console.info("[Demo] BgTaskAbility onBackground") 421 } 422 }; 423 ``` 424 425