• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Continuous task (ArkTS)
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| Item| Example Scenario|
20| -------- | -------- | -------- | -------- |
21| DATA_TRANSFER | Data transfer| dataTransfer | The browser downloads a large file in the background.|
22| AUDIO_PLAYBACK | Audio and video playback| audioPlayback | A music application plays music in the background.<br>It can be used in atomic services.|
23| AUDIO_RECORDING | Audio recording| audioRecording | A recorder records audio in the background.|
24| LOCATION | Positioning and navigation| location | A navigation application provides navigation in the background.|
25| BLUETOOTH_INTERACTION | Bluetooth-related task| bluetoothInteraction | Transfer a file through Bluetooth.|
26| MULTI_DEVICE_CONNECTION | Multi-device connection| multiDeviceConnection | Carry out distributed service connection.<br>It can be used in atomic services.|
27| <!--DelRow-->WIFI_INTERACTION | WLAN-related task (for system applications only)| wifiInteraction  | Transfer a file over WLAN.|
28| VOIP | Audio and video calls| voip  | Use a chat application to make an audio and video call in the background.|
29| TASK_KEEPING | <!--RP1-->Computing task (for specific devices only)<!--RP1End--> | taskKeeping  | Run antivirus software.|
30
31- If an application calls the [upload and download agent API](../reference/apis-basic-services-kit/js-apis-request.md) to delegate the upload and download task to the system, the application will be suspended regardless of whether it has requested such a continuous task. For a continuous task used for download, the application needs to update the download progress. If the progress is not updated for more than 10 minutes, the continuous task will be canceled. You are advised to use the [new API](../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstartbackgroundrunning12) to request a continuous task of the DATA_TRANSFER type and update the notification progress.
32- Only audio and video applications that use [AVSession](../media/avsession/avsession-overview.md) can request a continuous task of the AUDIO_PLAYBACK type to implement background playback.
33
34### Constraints
35
36- **Ability restrictions**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks.
37
38- **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.
39
40- **Running restrictions**: The system verifies continuous tasks on mobile phones.
41   - Scenario 1: If an application requests a continuous task but does not execute or has finished the task of the requested type, 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 cancels the continuous task.
42   - Scenario 2: If an application does not request a continuous task of a given type but executes such a continuous task, the system performs certain control. 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 performs control on the application.
43   - Scenario 3: 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.
44
45> **NOTE**
46>
47> 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.
48>
49> 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.
50>
51> When an application that plays audio stops a continuous task in the background, it must suspend or stop the audio stream. Otherwise, the application will be forcibly terminated by the system.
52
53## Available APIs
54
55The 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).
56
57**Table 2** Main APIs for continuous tasks
58
59| API| Description|
60| -------- | -------- |
61| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md)): Promise&lt;void&gt; | Requests a continuous task.|
62| stopBackgroundRunning(context: Context): Promise&lt;void&gt; | Cancels a continuous task.|
63
64## How to Develop
65
66The following walks you through how to request a continuous task for recording. In this example, the application provides two buttons: **Request Continuous Task** and **Cancel Continuous Task**.
67- 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.
68- When a user touches **Cancel Continuous Task**, the application cancels the continuous task, and the notification message is removed.
69
70### Stage Model
71
721. Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
73
742. Declare the background mode and add configurations such as **uris**.
75   - (Mandatory) Declare the background mode. Specifically, declare the type of the continuous task for the target UIAbility in the **module.json5** file. (Set the corresponding configuration item in the configuration file.)
76   - (Optional) Add configurations such as **uris**. If redirection features such as deep linking and app linking are used, refer to the sample code below. The mandatory parameters cannot be modified. For details about the optional parameters, see [Overview of Application Redirection](../application-models/link-between-apps-overview.md).
77
78   ```json
79    "module": {
80        "abilities": [
81            {
82                "backgroundModes": [
83                 // Configuration item of the continuous task type
84                "audioRecording"
85                ],
86                "skills": [
87                    // Mandatory: entities and actions values for the request for a continuous task.
88                    {
89                        "entities": [
90                            "entity.system.home"
91                        ],
92                        "actions": [
93                            "action.system.home"
94                        ]
95                    },
96                    // Optional: required for redirection features such as deep linking and app linking.
97                    {
98                        "entities": [
99                            "test"
100                        ],
101                        "actions": [
102                            "test"
103                        ],
104                        "uris": [
105                            {
106                                "scheme": "test"
107                            }
108                        ]
109                    }
110                ]
111            }
112        ],
113        ...
114    }
115   ```
116
1173. Import the modules.
118
119   Import the modules related to continuous tasks: @ohos.resourceschedule.backgroundTaskManager and @ohos.app.ability.wantAgent. Import other modules based on the project requirements.
120
121   ```ts
122    import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
123    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
124    import { window } from '@kit.ArkUI';
125    import { rpc } from '@kit.IPCKit'
126    import { BusinessError } from '@kit.BasicServicesKit';
127    import { wantAgent, WantAgent } from '@kit.AbilityKit';
128   ```
129
1304. Request and cancel a continuous task.
131
132   - 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.<!--RP2--><!--RP2End-->
133   <!--Del-->
134   - 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).<!--DelEnd-->
135
136   The code snippet below shows how an application requests a continuous task for itself.
137
138   ```ts
139    @Entry
140    @Component
141    struct Index {
142      @State message: string = 'ContinuousTask';
143     // Use getContext to obtain the context of the UIAbility for the page.
144      private context: Context = getContext(this);
145
146      startContinuousTask() {
147        let wantAgentInfo: wantAgent.WantAgentInfo = {
148          // List of operations to be executed after the notification is clicked.
149          // Add the bundleName and abilityName of the application to start.
150          wants: [
151            {
152              bundleName: "com.example.myapplication",
153              abilityName: "com.example.myapplication.MainAbility"
154            }
155          ],
156          // Specify the action to perform (starting the ability) after the notification message is clicked.
157          actionType: wantAgent.OperationType.START_ABILITY,
158          // Custom request code.
159          requestCode: 0,
160          // Execution attribute of the operation to perform after the notification is clicked.
161          actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
162        };
163
164        // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
165        wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
166          backgroundTaskManager.startBackgroundRunning(this.context,
167            backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
168            // Execute the continuous task logic, for example, music playback.
169            console.info(`Succeeded in operationing startBackgroundRunning.`);
170          }).catch((err: BusinessError) => {
171            console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
172          });
173        });
174      }
175
176      stopContinuousTask() {
177         backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
178           console.info(`Succeeded in operationing stopBackgroundRunning.`);
179         }).catch((err: BusinessError) => {
180           console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
181         });
182      }
183
184      build() {
185        Row() {
186          Column() {
187            Text("Index")
188              .fontSize(50)
189              .fontWeight(FontWeight.Bold)
190
191           Button() {
192              Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold)
193            }
194            .type(ButtonType.Capsule)
195            .margin({ top: 10 })
196            .backgroundColor('#0D9FFB')
197            .width(250)
198            .height(40)
199            .onClick(() => {
200              // Request a continuous task by clicking a button.
201              this.startContinuousTask();
202            })
203
204            Button() {
205              Text ('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold)
206            }
207            .type(ButtonType.Capsule)
208            .margin({ top: 10 })
209            .backgroundColor('#0D9FFB')
210            .width(250)
211            .height(40)
212            .onClick(() => {
213              // Stop the continuous task.
214
215              // Cancel the continuous task by clicking a button.
216              this.stopContinuousTask();
217            })
218          }
219          .width('100%')
220        }
221        .height('100%')
222      }
223    }
224   ```
225   <!--Del-->
226
227   The code snippet below shows how an application requests a continuous task across devices or applications.
228
229   ```ts
230    const MSG_SEND_METHOD: string = 'CallSendMsg'
231
232    let mContext: Context;
233
234    function startContinuousTask() {
235      let wantAgentInfo : wantAgent.WantAgentInfo = {
236        // List of operations to be executed after the notification is clicked.
237        wants: [
238          {
239            bundleName: "com.example.myapplication",
240            abilityName: "com.example.myapplication.MainAbility",
241          }
242        ],
243        // Type of the operation to perform after the notification is clicked.
244        actionType: wantAgent.OperationType.START_ABILITY,
245        // Custom request code.
246        requestCode: 0,
247        // Execution attribute of the operation to perform after the notification is clicked.
248        actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
249      };
250
251      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
252      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => {
253        backgroundTaskManager.startBackgroundRunning(mContext,
254          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
255          console.info(`Succeeded in operationing startBackgroundRunning.`);
256        }).catch((err: BusinessError) => {
257          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
258        });
259      });
260    }
261
262    function stopContinuousTask() {
263      backgroundTaskManager.stopBackgroundRunning(mContext).then(() => {
264        console.info(`Succeeded in operationing stopBackgroundRunning.`);
265      }).catch((err: BusinessError) => {
266        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
267      });
268    }
269
270    class MyParcelable implements rpc.Parcelable {
271      num: number = 0;
272      str: string = '';
273
274      constructor(num: number, string: string) {
275        this.num = num;
276        this.str = string;
277      }
278
279      marshalling(messageSequence: rpc.MessageSequence) {
280        messageSequence.writeInt(this.num);
281        messageSequence.writeString(this.str);
282        return true;
283      }
284
285      unmarshalling(messageSequence: rpc.MessageSequence) {
286        this.num = messageSequence.readInt();
287        this.str = messageSequence.readString();
288        return true;
289      }
290    }
291
292    function sendMsgCallback(data: rpc.MessageSequence) {
293      console.info('BgTaskAbility funcCallBack is called ' + data);
294      let receivedData: MyParcelable = new MyParcelable(0, '');
295      data.readParcelable(receivedData);
296      console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);
297      // You can execute different methods based on the str value in the sequenceable data sent by the caller object.
298      if (receivedData.str === 'start_bgtask') {
299        // Request a continuous task.
300        startContinuousTask();
301      } else if (receivedData.str === 'stop_bgtask') {
302        // Cancel the continuous task.
303        stopContinuousTask();
304      }
305      return new MyParcelable(10, 'Callee test');
306    }
307
308    export default class BgTaskAbility extends UIAbility {
309      // Create an ability.
310      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
311        console.info("[Demo] BgTaskAbility onCreate");
312        try {
313          this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
314        } catch (error) {
315          console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
316        }
317        mContext = this.context;
318      }
319
320      // Destroy an ability.
321      onDestroy() {
322        console.info('[Demo] BgTaskAbility onDestroy');
323      }
324
325      onWindowStageCreate(windowStage: window.WindowStage) {
326        console.info('[Demo] BgTaskAbility onWindowStageCreate');
327
328        windowStage.loadContent('pages/Index', (error, data) => {
329          if (error.code) {
330            console.error(`load content failed with error ${JSON.stringify(error)}`);
331            return;
332          }
333          console.info(`load content succeed with data ${JSON.stringify(data)}`);
334        });
335      }
336
337      onWindowStageDestroy() {
338        console.info('[Demo] BgTaskAbility onWindowStageDestroy');
339      }
340
341      onForeground() {
342        console.info('[Demo] BgTaskAbility onForeground');
343      }
344
345      onBackground() {
346        console.info('[Demo] BgTaskAbility onBackground');
347      }
348    };
349   ```
350
351   <!--DelEnd-->
352
353<!--Del-->
354### FA Model
355
3561. Start and connect to a ServiceAbility.
357
358   - 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.
359
360   - 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.
361
3622. Configure permissions and declare the continuous task type.
363
364   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.
365
366   ```json
367   "module": {
368       "package": "com.example.myapplication",
369       "abilities": [
370           {
371               "backgroundModes": [
372               "audioRecording",
373               ], // Background mode
374               "type": "service"  // The ability type is Service.
375           }
376       ],
377       "reqPermissions": [
378           {
379               "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission
380           }
381       ]
382   }
383   ```
384
3853. Import the modules.
386
387   ```js
388    import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
389    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
390    import { window } from '@kit.ArkUI';
391    import { rpc } from '@kit.IPCKit'
392    import { BusinessError } from '@kit.BasicServicesKit';
393    import { wantAgent, WantAgent } from '@kit.AbilityKit';
394   ```
395
3964. 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.
397
398   ```js
399    function startContinuousTask() {
400      let wantAgentInfo: wantAgent.WantAgentInfo = {
401        // List of operations to be executed after the notification is clicked.
402        wants: [
403          {
404            bundleName: "com.example.myapplication",
405            abilityName: "com.example.myapplication.MainAbility"
406          }
407        ],
408        // Type of the operation to perform after the notification is clicked.
409        actionType: wantAgent.OperationType.START_ABILITY,
410        // Custom request code.
411        requestCode: 0,
412        // Execution attribute of the operation to perform after the notification is clicked.
413        actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
414      };
415
416      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
417      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
418        backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(),
419          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
420          console.info(`Succeeded in operationing startBackgroundRunning.`);
421        }).catch((err: BusinessError) => {
422          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
423        });
424      });
425    }
426
427    function stopContinuousTask() {
428      backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => {
429        console.info(`Succeeded in operationing stopBackgroundRunning.`);
430      }).catch((err: BusinessError) => {
431        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
432      });
433    }
434
435    async function processAsyncJobs() {
436      // Execute the continuous task.
437
438      // After the continuous task is complete, call the API to release resources.
439      stopContinuousTask();
440    }
441
442    let mMyStub: MyStub;
443
444    // Start the service by calling connectAbility().
445    class MyStub extends rpc.RemoteObject {
446      constructor(des: string) {
447        super(des);
448      }
449
450      onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) {
451        console.log('ServiceAbility onRemoteRequest called');
452        // Custom request code.
453        if (code === 1) {
454          // Receive the request code for requesting a continuous task.
455          startContinuousTask();
456          // Execute the continuous task.
457        } else if (code === 2) {
458          // Receive the request code for canceling the continuous task.
459          stopContinuousTask();
460        } else {
461          console.log('ServiceAbility unknown request code');
462        }
463        return true;
464      }
465    }
466
467    // Start the service by calling startAbility().
468    class ServiceAbility {
469      onStart(want: Want) {
470        console.info('ServiceAbility onStart');
471        mMyStub = new MyStub("ServiceAbility-test");
472        // Call the API to start the task.
473        startContinuousTask();
474        processAsyncJobs();
475      }
476
477      onStop() {
478        console.info('ServiceAbility onStop');
479      }
480
481      onConnect(want: Want) {
482        console.info('ServiceAbility onConnect');
483        return mMyStub;
484      }
485
486      onReconnect(want: Want) {
487        console.info('ServiceAbility onReconnect');
488      }
489
490      onDisconnect() {
491        console.info('ServiceAbility onDisconnect');
492      }
493
494      onCommand(want: Want, startId: number) {
495        console.info('ServiceAbility onCommand');
496      }
497    }
498
499    export default new ServiceAbility();
500    ```
501<!--DelEnd-->
502
503