• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Continuous Task
2
3
4## Overview
5
6
7### Introduction
8
9If 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.
10
11After an application requests a continuous task, the system verifies whether the application is actually executing the continuous task. It also attaches a notification to the continuous task. If the user deletes the notification, the system automatically stops the task.
12
13
14### Use Cases
15
16The 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.
17
18**Table 1** Continuous task types
19| Name| Description| Example Scenario|
20| -------- | -------- | -------- |
21| DATA_TRANSFER | Data transfer| The browser downloads a large file in the background.|
22| AUDIO_PLAYBACK | Audio playback| A music application plays music in the background.|
23| AUDIO_RECORDING | Audio recording| A recorder records audio in the background.|
24| LOCATION | Positioning and navigation| A navigation application provides navigation in the background.|
25| BLUETOOTH_INTERACTION | Bluetooth-related task| Transfer a file through Bluetooth.|
26| MULTI_DEVICE_CONNECTION | Multi-device connection| Carry out distributed service connection.|
27| WIFI_INTERACTION | WLAN-related task (for system applications only)| Transfer a file over Wi-Fi.|
28| VOIP | Voice and video calls (for system applications only)| Use a system chat application to make an audio call in the background.|
29| TASK_KEEPING | Computing task (for specific devices only)| Run antivirus software.|
30
31
32- When an application requests a continuous task of the DATA_TRANSFER type, the system increases the priority of the application process to reduce the probability of terminating the process. However, it still suspends the process. To use the upload and download feature, the application must call the [upload and download agent API](../reference/apis/js-apis-request.md) so that the system functions as the agent.
33- To implement background playback, the application must request an [AV session](../media/avsession-overview.md) in addition to a continuous task of the AUDIO_PLAYBACK type.
34
35
36### Constraints
37
38- **Ability limit**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks.
39
40- **Quantity limit**: 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.
41
42- **Running verification**: The system performs continuous task verification. If an application requests a continuous task but does not execute the task of the requested type or finishes the task, the system performs certain control. 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 terminates the application process.
43
44> **NOTE**
45>
46> 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.
47
48## Available APIs
49
50The 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/js-apis-resourceschedule-backgroundTaskManager.md).
51
52**Table 2** Main APIs for continuous tasks
53
54| API| Description|
55| -------- | -------- |
56| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis/js-apis-app-ability-wantAgent.md)): Promise<void> | Requests a continuous task.|
57| stopBackgroundRunning(context: Context): Promise<void> | Cancels a continuous task.|
58
59## How to Develop
60
61### Stage Model
62
631. Request the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
64
652. Declare the continuous task type.
66
67   Declare the continuous task type for the target UIAbility in the **module.json5** file.
68
69
70   ```ts
71   "module": {
72       "abilities": [
73           {
74               "backgroundModes": [
75               "audioRecording"
76               ], // Background mode
77           }
78       ],
79       ...
80   }
81   ```
82
833. Import the modules.
84
85   ```ts
86   import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
87   import wantAgent from '@ohos.app.ability.wantAgent';
88   ```
89
904. Request and cancel a continuous task.
91
92   - In the stage model, an application can request a continuous task for itself or another application either on the local device or on a remote device.
93
94   - 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).
95
96   The code snippet below shows how an application requests a continuous task for itself.
97
98   ```ts
99   @Entry
100   @Component
101   struct Index {
102     @State message: string = 'ContinuousTask';
103     // Use getContext to obtain the context of the UIAbility for the page.
104     private context = getContext(this);
105
106     startContinuousTask() {
107       let wantAgentInfo = {
108         // List of operations to be executed after the notification is clicked.
109         wants: [
110           {
111             bundleName: "com.example.myapplication",
112             abilityName: "com.example.myapplication.MainAbility"
113           }
114         ],
115         // Type of the operation to perform after the notification is clicked.
116         operationType: wantAgent.OperationType.START_ABILITY,
117         // Custom request code.
118         requestCode: 0,
119         // Execution attribute of the operation to perform after the notification is clicked.
120         wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
121       };
122
123       // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
124       wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
125         try {
126           backgroundTaskManager.startBackgroundRunning(this.context,
127           backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
128             console.info(`Succeeded in operationing startBackgroundRunning.`);
129           }).catch((err) => {
130             console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
131           });
132         } catch (error) {
133           console.error(`Failed to start background running. Code is ${error.code} message is ${error.message}`);
134         }
135       });
136     }
137
138     stopContinuousTask() {
139       try {
140         backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
141           console.info(`Succeeded in operationing stopBackgroundRunning.`);
142         }).catch((err) => {
143           console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
144         });
145       } catch (error) {
146         console.error(`Failed to stop background running. Code is ${error.code} message is ${error.message}`);
147       }
148     }
149
150     build() {
151       Row() {
152         Column() {
153           Text("Index")
154             .fontSize(50)
155             .fontWeight(FontWeight.Bold)
156
157           Button() {
158             Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold)
159           }
160           .type(ButtonType.Capsule)
161           .margin({ top: 10 })
162           .backgroundColor('#0D9FFB')
163           .width(250)
164           .height(40)
165           .onClick(() => {
166             // Request a continuous task by clicking a button.
167             this.startContinuousTask();
168
169             // Execute the continuous task logic, for example, music playback.
170           })
171
172           Button() {
173             Text ('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold)
174           }
175           .type(ButtonType.Capsule)
176           .margin({ top: 10 })
177           .backgroundColor('#0D9FFB')
178           .width(250)
179           .height(40)
180           .onClick(() => {
181             // Stop the continuous task.
182
183             // Cancel the continuous task by clicking a button.
184             this.stopContinuousTask();
185           })
186         }
187         .width('100%')
188       }
189       .height('100%')
190     }
191   }
192   ```
193
194   The code snippet below shows how an application requests a continuous task across devices or applications.
195
196   ```ts
197   import UIAbility from '@ohos.app.ability.UIAbility';
198
199   const MSG_SEND_METHOD: string = 'CallSendMsg'
200
201   let mContext = null;
202
203   function startContinuousTask() {
204     let wantAgentInfo = {
205       // List of operations to be executed after the notification is clicked.
206       wants: [
207         {
208           bundleName: "com.example.myapplication",
209           abilityName: "com.example.myapplication.MainAbility",
210         }
211       ],
212       // Type of the operation to perform after the notification is clicked.
213       operationType: wantAgent.OperationType.START_ABILITY,
214       // Custom request code.
215       requestCode: 0,
216       // Execution attribute of the operation to perform after the notification is clicked.
217       wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
218     };
219
220     // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
221     wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
222       try {
223         backgroundTaskManager.startBackgroundRunning(mContext,
224         backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
225           console.info(`Succeeded in operationing startBackgroundRunning.`);
226         }).catch((err) => {
227           console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
228         });
229       } catch (err) {
230         console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
231       }
232     });
233   }
234
235   function stopContinuousTask() {
236     try {
237       backgroundTaskManager.stopBackgroundRunning(mContext).then(() => {
238         console.info(`Succeeded in operationing stopBackgroundRunning.`);
239       }).catch((err) => {
240         console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
241       });
242     } catch (err) {
243       console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
244     }
245   }
246
247   class MyParcelable {
248     num: number = 0;
249     str: String = '';
250
251     constructor(num, string) {
252       this.num = num;
253       this.str = string;
254     }
255
256     marshalling(messageSequence) {
257       messageSequence.writeInt(this.num);
258       messageSequence.writeString(this.str);
259       return true;
260     }
261
262     unmarshalling(messageSequence) {
263       this.num = messageSequence.readInt();
264       this.str = messageSequence.readString();
265       return true;
266     }
267   }
268
269   function sendMsgCallback(data) {
270     console.info('BgTaskAbility funcCallBack is called ' + data)
271     let receivedData = new MyParcelable(0, '')
272     data.readParcelable(receivedData)
273     console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`)
274     // You can execute different methods based on the str value in the sequenceable data sent by the caller object.
275     if (receivedData.str === 'start_bgtask') {
276       startContinuousTask()
277     } else if (receivedData.str === 'stop_bgtask') {
278       stopContinuousTask();
279     }
280     return new MyParcelable(10, 'Callee test');
281   }
282
283   export default class BgTaskAbility extends UIAbility {
284     onCreate(want, launchParam) {
285       console.info("[Demo] BgTaskAbility onCreate")
286       this.callee.on('test', sendMsgCallback);
287
288       try {
289         this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
290       } catch (error) {
291         console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
292       }
293       mContext = this.context;
294     }
295
296     onDestroy() {
297       console.info('[Demo] BgTaskAbility onDestroy')
298     }
299
300     onWindowStageCreate(windowStage) {
301       console.info('[Demo] BgTaskAbility onWindowStageCreate')
302
303       windowStage.loadContent("pages/index").then((data) => {
304         console.info(`load content succeed with data ${JSON.stringify(data)}`)
305       }).catch((error) => {
306         console.error(`load content failed with error ${JSON.stringify(error)}`)
307       })
308     }
309
310     onWindowStageDestroy() {
311       console.info('[Demo] BgTaskAbility onWindowStageDestroy')
312     }
313
314     onForeground() {
315       console.info('[Demo] BgTaskAbility onForeground')
316     }
317
318     onBackground() {
319       console.info('[Demo] BgTaskAbility onBackground')
320     }
321   };
322   ```
323
324
325### FA Model
326
3271. Start and connect to a ServiceAbility.
328
329   - 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.
330
331   - 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.
332
3332. Configure permissions and declare the continuous task type.
334
335   Configure the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission in the **config.json** file. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). In addition, declare the continuous task type for the ServiceAbility.
336
337
338   ```js
339   "module": {
340       "package": "com.example.myapplication",
341       "abilities": [
342           {
343               "backgroundModes": [
344               "audioRecording",
345               ], // Background mode
346               "type": "service"  // The ability type is Service.
347           }
348       ],
349       "reqPermissions": [
350           {
351               "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission
352           }
353       ]
354   }
355   ```
356
3573. Import the modules.
358
359   ```js
360   import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
361   import featureAbility from '@ohos.ability.featureAbility';
362   import wantAgent from '@ohos.app.ability.wantAgent';
363   import rpc from "@ohos.rpc";
364   ```
365
3664. Request and cancel a continuous task. In the ServiceAbility, call **startBackgroundRunning()** and **startBackgroundRunning()** to request and cancel a continuous task.
367
368   ```js
369   function startContinuousTask() {
370     let wantAgentInfo = {
371       // List of operations to be executed after the notification is clicked.
372       wants: [
373         {
374           bundleName: "com.example.myapplication",
375           abilityName: "com.example.myapplication.MainAbility"
376         }
377       ],
378       // Type of the operation to perform after the notification is clicked.
379       operationType: wantAgent.OperationType.START_ABILITY,
380       // Custom request code.
381       requestCode: 0,
382       // Execution attribute of the operation to perform after the notification is clicked.
383       wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
384     };
385
386     // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
387     wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
388       try {
389         backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(),
390         backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
391           console.info(`Succeeded in operationing startBackgroundRunning.`);
392         }).catch((err) => {
393           console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
394         });
395       } catch (error) {
396         console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
397       }
398     });
399   }
400
401   function stopContinuousTask() {
402     try {
403       backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => {
404         console.info(`Succeeded in operationing stopBackgroundRunning.`);
405       }).catch((err) => {
406         console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
407       });
408     } catch (error) {
409       console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
410     }
411   }
412
413   async function processAsyncJobs() {
414     // Execute the continuous task.
415
416     // After the continuous task is complete, call the API to release resources.
417     stopContinuousTask();
418   }
419
420   let mMyStub;
421
422   class MyStub extends rpc.RemoteObject {
423     constructor(des) {
424       if (typeof des === 'string') {
425         super(des);
426       } else {
427         return null;
428       }
429     }
430
431     onRemoteRequest(code, data, reply, option) {
432       console.log('ServiceAbility onRemoteRequest called');
433       // Custom request code.
434       if (code === 1) {
435         // Receive the request code for requesting a continuous task.
436         startContinuousTask();
437         // Execute the continuous task.
438       } else if (code === 2) {
439         // Receive the request code for canceling the continuous task.
440         stopContinuousTask();
441       } else {
442         console.log('ServiceAbility unknown request code');
443       }
444       return true;
445     }
446   }
447
448   export default {
449     onStart(want) {
450       console.info('ServiceAbility onStart');
451       mMyStub = new MyStub("ServiceAbility-test");
452       // Call the API to start the task.
453       startContinuousTask();
454       processAsyncJobs();
455     },
456     onStop() {
457       console.info('ServiceAbility onStop');
458     },
459     onConnect(want) {
460       console.info('ServiceAbility onConnect');
461       return mMyStub;
462     },
463     onReconnect(want) {
464       console.info('ServiceAbility onReconnect');
465     },
466     onDisconnect() {
467       console.info('ServiceAbility onDisconnect');
468     },
469     onCommand(want, restart, startId) {
470       console.info('ServiceAbility onCommand');
471     }
472   };
473   ```
474
475