1# Continuous Task (ArkTS) 2 3## Overview 4 5### Introduction 6 7If 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 to prevent itself from being suspended. Examples of continuous tasks include music playback and navigation in the background. Within a continuous task, the application can concurrently request multiple types of tasks and update the task types. When the application operates in the background, the system performs consistency check to ensure that the application is executing the corresponding continuous task. Upon successful request for a continuous task, the notification panel displays the message associated with the task. If the user deletes the message, the system automatically terminates the task. 8 9### Use Cases 10 11The table below lists the types of continuous tasks, which are used in various scenarios. You can select a task type suitable for your case based on the description. 12 13**Table 1** Continuous task types 14| Name| Description| Item| Example Scenario| 15| -------- | -------- | -------- | -------- | 16| DATA_TRANSFER | Data transfer| dataTransfer | Non-hosting uploading and downloading operations, like those occurring in the background of a web browser for data transfer.| 17| AUDIO_PLAYBACK | Audio and video playback| audioPlayback | Audio and video playback in the background; audio and video casting.<br> **NOTE**<br>It can be used in atomic services.| 18| AUDIO_RECORDING | Audio recording| audioRecording | Recording and screen capture in the background.| 19| LOCATION | Positioning and navigation| location | Positioning and navigation.| 20| BLUETOOTH_INTERACTION | Bluetooth-related services| bluetoothInteraction | An application transitions into the background during the process of file transfer using Bluetooth.| 21| MULTI_DEVICE_CONNECTION | Multi-device connection| multiDeviceConnection | Distributed service connection and casting.<br> **NOTE**<br>It can be used in atomic services.| 22| <!--DelRow-->WIFI_INTERACTION | WLAN-related services (for system applications only)| wifiInteraction | An application transitions into the background during the process of file transfer using WLAN.| 23| VOIP<sup>13+</sup> | Audio and video calls| voip | Chat applications (with audio and video services) transition into the background during audio and video calls.| 24| TASK_KEEPING | Computing task (for 2-in-1 devices only).| taskKeeping | Antivirus software is running.| 25 26Description of **DATA_TRANSFER**: 27 28- During data transfer, if an application uses the [upload and download agent API](../reference/apis-basic-services-kit/js-apis-request.md) to hand over tasks to the system, the application will be suspended in the background even if it has requested the continuous task of the DATA_TRANSFER type. 29 30- During data transfer, the application needs to update the progress. If the progress is not updated for more than 10 minutes, the continuous task of the DATA_TRANSFER type will be canceled. For details about how to update the progress, see the example in [startBackgroundRunning()](../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstartbackgroundrunning12). 31 32Description of **AUDIO_PLAYBACK**: 33 34- To implement background playback through **AUDIO_PLAYBACK**, you must use the [AVSession](../media/avsession/avsession-overview.md) for audio and video development. 35 36- Casting audio and video involves transmitting content from one device to another for playback purposes. If the application transitions to the background while casting, the continuous task checks the audio and video playback and casting services. The task will persist as long as either the audio and video playback or casting service is running properly. 37 38### Constraints 39 40**Ability restrictions**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks. Continuous tasks can be requested by the current application on the current device or across devices or by other applications. However, the capability to make cross-device or cross-application requests is restricted to system applications. 41 42**Quantity restrictions**: A UIAbility (ServiceAbility in the FA model) can request only one continuous task at a time. If a UIAbility has a running continuous task, it can request another one only after the running task is finished. If an application needs to request multiple continuous tasks at the same time, it must create multiple UIAbilities. After a UIAbility requests a continuous task, all the processes of the application are not suspended. 43 44**Running restrictions**: 45 46- If an application requests a continuous task but does not carry out the relevant service, the system imposes restrictions on the application. For example, if the system detects that an application has requested a continuous task of the AUDIO_PLAYBACK type but does not play audio, the system cancels the continuous task. 47 48- If an application requests a continuous task but carries out a service that does not match the requested type, the system imposes restrictions on the application. For example, if the system detects that an application requests a continuous task of the AUDIO_PLAYBACK type, but the application is playing audio (corresponding to the AUDIO_PLAYBACK type) and recording (corresponding to the AUDIO_RECORDING type), the system enforces management measures. 49 50- When an application's operations are completed after a continuous task request, the system imposes restrictions on the application. 51 52- If the background load of the process that runs a continuous task is higher than the corresponding typical load for a long period of time, the system performs certain control. 53 54> **NOTE** 55> 56> The application shall proactively cancel a continuous task when it is finished. Otherwise, the system will forcibly cancel the task. For example, when a user taps the UI to pause music playback, the application must cancel the continuous task in a timely manner. When the user taps the UI again to continue music playback, the application needs to request a continuous task. 57> 58> If an application that plays an audio in the background is [interrupted](../media/audio/audio-playback-concurrency.md), the system automatically detects and stops the continuous task. The application must request a continuous task again to restart the playback. 59> 60> When an application that plays audio in the background stops a continuous task, it must suspend or stop the audio stream. Otherwise, the application will be forcibly terminated by the system. 61 62## Available APIs 63 64The table below uses promise as an example to describe the APIs used for developing continuous tasks. For details about more APIs and their usage, see [Background Task Management](../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md). 65 66**Table 2** Main APIs for continuous tasks 67 68| API| Description| 69| -------- | -------- | 70| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md)): Promise<void> | Requests a continuous task.| 71| stopBackgroundRunning(context: Context): Promise<void> | Cancels a continuous task.| 72 73## How to Develop 74 75The following walks you through how to request a continuous task for recording to implement the following functions: 76 77- When a user touches **Request Continuous Task**, the application requests a continuous task for recording, and a message is displayed in the notification bar, indicating that a recording task is running. 78 79- When a user touches **Cancel Continuous Task**, the application cancels the continuous task, and the notification message is removed. 80 81### Stage Model 82 831. Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). 84 852. Declare the continuous task type. 86 87 Declare the type of the continuous task for the target UIAbility in the **module.json5** file. Set the corresponding [configuration item](continuous-task.md#use-cases) in the configuration file. 88 89 ```json 90 "module": { 91 "abilities": [ 92 { 93 "backgroundModes": [ 94 // Configuration item of the continuous task type 95 "audioRecording" 96 ] 97 } 98 ], 99 // ... 100 } 101 ``` 102 1033. Import the modules. 104 105 Import the modules related to continuous tasks: @ohos.resourceschedule.backgroundTaskManager and @ohos.app.ability.wantAgent. Import other modules based on the project requirements. 106 107 ```ts 108 import { backgroundTaskManager } from '@kit.BackgroundTasksKit'; 109 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 110 import { window } from '@kit.ArkUI'; 111 import { rpc } from '@kit.IPCKit' 112 import { BusinessError } from '@kit.BasicServicesKit'; 113 import { wantAgent, WantAgent } from '@kit.AbilityKit'; 114 ``` 115 1164. Request and cancel a continuous task. 117 118 The code snippet below shows how an application requests a continuous task for itself. 119 120 ```ts 121 @Entry 122 @Component 123 struct Index { 124 @State message: string = 'ContinuousTask'; 125 // Use getContext to obtain the context of the UIAbility for the page. 126 private context: Context = getContext(this); 127 128 startContinuousTask() { 129 let wantAgentInfo: wantAgent.WantAgentInfo = { 130 // List of operations to be executed after the notification is clicked. 131 // Add the bundleName and abilityName of the application to start. 132 wants: [ 133 { 134 bundleName: "com.example.myapplication", 135 abilityName: "MainAbility" 136 } 137 ], 138 // Specify the action to perform (starting the ability) after the notification message is clicked. 139 actionType: wantAgent.OperationType.START_ABILITY, 140 // Custom request code. 141 requestCode: 0, 142 // Execution attribute of the operation to perform after the notification is clicked. 143 actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 144 }; 145 146 try { 147 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 148 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { 149 try { 150 let list: Array<string> = ["audioRecording"]; 151 backgroundTaskManager.startBackgroundRunning(this.context, list, wantAgentObj).then((res: backgroundTaskManager.ContinuousTaskNotification) => { 152 console.info("Operation startBackgroundRunning succeeded"); 153 // Execute the continuous task logic, for example, recording. 154 }).catch((error: BusinessError) => { 155 console.error(`Failed to Operation startBackgroundRunning. code is ${error.code} message is ${error.message}`); 156 }); 157 } catch (error) { 158 console.error(`Failed to Operation startBackgroundRunning. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`); 159 } 160 }); 161 } catch (error) { 162 console.error(`Failed to Operation getWantAgent. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`); 163 } 164 } 165 166 stopContinuousTask() { 167 backgroundTaskManager.stopBackgroundRunning(this.context).then(() => { 168 console.info(`Succeeded in operationing stopBackgroundRunning.`); 169 }).catch((err: BusinessError) => { 170 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 171 }); 172 } 173 174 build() { 175 Row() { 176 Column() { 177 Text("Index") 178 .fontSize(50) 179 .fontWeight(FontWeight.Bold) 180 181 Button() { 182 Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold) 183 } 184 .type(ButtonType.Capsule) 185 .margin({ top: 10 }) 186 .backgroundColor('#0D9FFB') 187 .width(250) 188 .height(40) 189 .onClick(() => { 190 // Request a continuous task by clicking a button. 191 this.startContinuousTask(); 192 }) 193 194 Button() { 195 Text('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold) 196 } 197 .type(ButtonType.Capsule) 198 .margin({ top: 10 }) 199 .backgroundColor('#0D9FFB') 200 .width(250) 201 .height(40) 202 .onClick(() => { 203 // Stop the continuous task. 204 205 // Cancel the continuous task by clicking a button. 206 this.stopContinuousTask(); 207 }) 208 } 209 .width('100%') 210 } 211 .height('100%') 212 } 213 } 214 ``` 215 <!--Del--> 216 217 The code snippet below shows how an application requests a continuous task across devices or applications. When a continuous task is executed across devices or applications in the background, the UIAbility can be created and run in the background in call mode. For details, see [Using Call to Implement UIAbility Interaction (for System Applications Only)](../application-models/uiability-intra-device-interaction.md#using-call-to-implement-uiability-interaction-for-system-applications-only) and [Using Cross-Device Call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call). 218 219 ```ts 220 const MSG_SEND_METHOD: string = 'CallSendMsg' 221 222 let mContext: Context; 223 224 function startContinuousTask() { 225 let wantAgentInfo : wantAgent.WantAgentInfo = { 226 // List of operations to be executed after the notification is clicked. 227 wants: [ 228 { 229 bundleName: "com.example.myapplication", 230 abilityName: "com.example.myapplication.MainAbility", 231 } 232 ], 233 // Type of the operation to perform after the notification is clicked. 234 actionType: wantAgent.OperationType.START_ABILITY, 235 // Custom request code. 236 requestCode: 0, 237 // Execution attribute of the operation to perform after the notification is clicked. 238 actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 239 }; 240 241 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 242 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => { 243 backgroundTaskManager.startBackgroundRunning(mContext, 244 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 245 console.info(`Succeeded in operationing startBackgroundRunning.`); 246 }).catch((err: BusinessError) => { 247 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 248 }); 249 }); 250 } 251 252 function stopContinuousTask() { 253 backgroundTaskManager.stopBackgroundRunning(mContext).then(() => { 254 console.info(`Succeeded in operationing stopBackgroundRunning.`); 255 }).catch((err: BusinessError) => { 256 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 257 }); 258 } 259 260 class MyParcelable implements rpc.Parcelable { 261 num: number = 0; 262 str: string = ''; 263 264 constructor(num: number, string: string) { 265 this.num = num; 266 this.str = string; 267 } 268 269 marshalling(messageSequence: rpc.MessageSequence) { 270 messageSequence.writeInt(this.num); 271 messageSequence.writeString(this.str); 272 return true; 273 } 274 275 unmarshalling(messageSequence: rpc.MessageSequence) { 276 this.num = messageSequence.readInt(); 277 this.str = messageSequence.readString(); 278 return true; 279 } 280 } 281 282 function sendMsgCallback(data: rpc.MessageSequence) { 283 console.info('BgTaskAbility funcCallBack is called ' + data); 284 let receivedData: MyParcelable = new MyParcelable(0, ''); 285 data.readParcelable(receivedData); 286 console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`); 287 // You can execute different methods based on the str value in the sequenceable data sent by the caller object. 288 if (receivedData.str === 'start_bgtask') { 289 // Request a continuous task. 290 startContinuousTask(); 291 } else if (receivedData.str === 'stop_bgtask') { 292 // Cancel the continuous task. 293 stopContinuousTask(); 294 } 295 return new MyParcelable(10, 'Callee test'); 296 } 297 298 export default class BgTaskAbility extends UIAbility { 299 // Create an ability. 300 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 301 console.info("[Demo] BgTaskAbility onCreate"); 302 try { 303 this.callee.on(MSG_SEND_METHOD, sendMsgCallback) 304 } catch (error) { 305 console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`); 306 } 307 mContext = this.context; 308 } 309 310 // Destroy an ability. 311 onDestroy() { 312 console.info('[Demo] BgTaskAbility onDestroy'); 313 } 314 315 onWindowStageCreate(windowStage: window.WindowStage) { 316 console.info('[Demo] BgTaskAbility onWindowStageCreate'); 317 318 windowStage.loadContent('pages/Index', (error, data) => { 319 if (error.code) { 320 console.error(`load content failed with error ${JSON.stringify(error)}`); 321 return; 322 } 323 console.info(`load content succeed with data ${JSON.stringify(data)}`); 324 }); 325 } 326 327 onWindowStageDestroy() { 328 console.info('[Demo] BgTaskAbility onWindowStageDestroy'); 329 } 330 331 onForeground() { 332 console.info('[Demo] BgTaskAbility onForeground'); 333 } 334 335 onBackground() { 336 console.info('[Demo] BgTaskAbility onBackground'); 337 } 338 }; 339 ``` 340 341 <!--DelEnd--> 342 343<!--Del--> 344### FA Model 345 3461. Start and connect to a ServiceAbility. 347 348 - If no user interaction is required, use **startAbility()** to start the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). In the **onStart** callback of the ServiceAbility, call the APIs to request and cancel continuous tasks. 349 350 - If user interaction is required (for example, in music playback scenarios), use **connectAbility()** to start and connect to the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). After obtaining the agent of the ServiceAbility, the application can communicate with the ServiceAbility and control the request and cancellation of continuous tasks. 351 3522. Configure permissions and declare the continuous task type. 353 354 Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission in the **config.json** file. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). In addition, declare the continuous task type for the ServiceAbility. 355 356 ```json 357 "module": { 358 "package": "com.example.myapplication", 359 "abilities": [ 360 { 361 "backgroundModes": [ 362 "audioRecording", 363 ], // Background mode 364 "type": "service" // The ability type is Service. 365 } 366 ], 367 "reqPermissions": [ 368 { 369 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission 370 } 371 ] 372 } 373 ``` 374 3753. Import the modules. 376 377 ```js 378 import { backgroundTaskManager } from '@kit.BackgroundTasksKit'; 379 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 380 import { window } from '@kit.ArkUI'; 381 import { rpc } from '@kit.IPCKit' 382 import { BusinessError } from '@kit.BasicServicesKit'; 383 import { wantAgent, WantAgent } from '@kit.AbilityKit'; 384 ``` 385 3864. Request and cancel a continuous task. In the ServiceAbility, call [startBackgroundRunning](#available-apis) and [stopBackgroundRunning](#available-apis) to request and cancel a continuous task. Use JavaScript code to implement this scenario. 387 388 ```js 389 function startContinuousTask() { 390 let wantAgentInfo: wantAgent.WantAgentInfo = { 391 // List of operations to be executed after the notification is clicked. 392 wants: [ 393 { 394 bundleName: "com.example.myapplication", 395 abilityName: "com.example.myapplication.MainAbility" 396 } 397 ], 398 // Type of the operation to perform after the notification is clicked. 399 actionType: wantAgent.OperationType.START_ABILITY, 400 // Custom request code. 401 requestCode: 0, 402 // Execution attribute of the operation to perform after the notification is clicked. 403 actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 404 }; 405 406 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 407 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { 408 backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(), 409 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 410 console.info(`Succeeded in operationing startBackgroundRunning.`); 411 }).catch((err: BusinessError) => { 412 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 413 }); 414 }); 415 } 416 417 function stopContinuousTask() { 418 backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => { 419 console.info(`Succeeded in operationing stopBackgroundRunning.`); 420 }).catch((err: BusinessError) => { 421 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 422 }); 423 } 424 425 async function processAsyncJobs() { 426 // Execute the continuous task. 427 428 // After the continuous task is complete, call the API to release resources. 429 stopContinuousTask(); 430 } 431 432 let mMyStub: MyStub; 433 434 // Start the service by calling connectAbility(). 435 class MyStub extends rpc.RemoteObject { 436 constructor(des: string) { 437 super(des); 438 } 439 440 onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) { 441 console.log('ServiceAbility onRemoteRequest called'); 442 // Custom request code. 443 if (code === 1) { 444 // Receive the request code for requesting a continuous task. 445 startContinuousTask(); 446 // Execute the continuous task. 447 } else if (code === 2) { 448 // Receive the request code for canceling the continuous task. 449 stopContinuousTask(); 450 } else { 451 console.log('ServiceAbility unknown request code'); 452 } 453 return true; 454 } 455 } 456 457 // Start the service by calling startAbility(). 458 class ServiceAbility { 459 onStart(want: Want) { 460 console.info('ServiceAbility onStart'); 461 mMyStub = new MyStub("ServiceAbility-test"); 462 // Call the API to start the task. 463 startContinuousTask(); 464 processAsyncJobs(); 465 } 466 467 onStop() { 468 console.info('ServiceAbility onStop'); 469 } 470 471 onConnect(want: Want) { 472 console.info('ServiceAbility onConnect'); 473 return mMyStub; 474 } 475 476 onReconnect(want: Want) { 477 console.info('ServiceAbility onReconnect'); 478 } 479 480 onDisconnect() { 481 console.info('ServiceAbility onDisconnect'); 482 } 483 484 onCommand(want: Want, startId: number) { 485 console.info('ServiceAbility onCommand'); 486 } 487 } 488 489 export default new ServiceAbility(); 490 ``` 491<!--DelEnd--> 492 493