提交 d738cd3e 编写于 作者: G Gloria

Update docs against 17296+17418+17104+17369+17340+17510+17467+17106+17107+17362

Signed-off-by: wusongqing<wusongqing@huawei.com>
上级 8b24f780
......@@ -12,7 +12,7 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **myabilitystage**.
2. In the **myabilitystage** directory, right-click and choose **New > ts File** to create a file named **MyAbilityStage.ts**.
2. In the **myabilitystage** directory, right-click and choose **New > TypeScript File** to create a file named **MyAbilityStage.ts**.
3. Open the **MyAbilityStage.ts** file, and import the dependency package of AbilityStage. Customize a class that inherits from AbilityStage, and add the required lifecycle callbacks. The following code snippet adds the **onCreate()** lifecycle callback.
......@@ -20,16 +20,27 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
import AbilityStage from '@ohos.app.ability.AbilityStage';
export default class MyAbilityStage extends AbilityStage {
onCreate() {
// When the HAP of the application is loaded for the first time, initialize the module.
}
onAcceptWant(want) {
// Triggered only for the ability with the specified launch type.
return "MyAbilityStage";
}
onCreate() {
// When the HAP of the application is loaded for the first time, initialize the module.
}
onAcceptWant(want) {
// Triggered only for the ability with the specified launch type.
return "MyAbilityStage";
}
}
```
4. Set **srcEntry** in the [module.json5 file](../quick-start/module-configuration-file.md) to the code path of the module.
```json
{
"module": {
"name": "entry",
"type": "entry",
"srcEntry": "./ets/myabilitystage/MyAbilityStage.ts",
// ...
}
}
```
[AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md) has the lifecycle callback [onCreate()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageoncreate) and the event callbacks [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant), [onConfigurationUpdated()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonconfigurationupdate), and [onMemoryLevel()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonmemorylevel).
......@@ -49,9 +60,8 @@ When an application is switched to the background, it is cached in the backgroun
import AbilityStage from '@ohos.app.ability.AbilityStage';
export default class MyAbilityStage extends AbilityStage {
onMemoryLevel(level) {
// Release unnecessary memory based on the change of available system memory.
}
onMemoryLevel(level) {
// Release unnecessary memory based on the change of available system memory.
}
}
```
......@@ -187,13 +187,13 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../
> **NOTE**
>
> To obtain the context of another application:
>
>
> - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
>
>
> - This is a system API and cannot be called by third-party applications.
For example, application information displayed on the home screen includes the application name and icon. The home screen application calls the foregoing method to obtain the context information, so as to obtain the resource information including the application name and icon.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -248,7 +248,7 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../
In the DFX statistics scenario of an application, if you need to collect statistics on the stay duration and access frequency of a page, you can subscribe to UIAbility lifecycle changes in a process.
[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example.
[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext.md) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example.
```ts
......@@ -308,7 +308,7 @@ export default class EntryAbility extends UIAbility {
// Obtain the application context.
let applicationContext = this.context.getApplicationContext();
// Register the application lifecycle callback.
this.lifecycleId = applicationContext.on('Lifecycle', abilityLifecycleCallback);
this.lifecycleId = applicationContext.on('abilityLifecycle', abilityLifecycleCallback);
console.log(TAG, `register callback number: ${this.lifecycleId}`);
}
......
# DataShareExtensionAbility (for System Applications Only)
DataShareExtensionAbility provides the data sharing capability. System applications can implement a DataShareExtensionAbility or access an existing DataShareExtensionAbility in the system. Third-party applications can only access an existing DataShareExtensionAbility. For details, see [DataShare Development](../database/database-datashare-guidelines.md).
DataShareExtensionAbility provides the data sharing capability. System applications can implement a DataShareExtensionAbility or access an existing DataShareExtensionAbility in the system. Third-party applications can only access an existing DataShareExtensionAbility. For details, see [Cross-Application Data Sharing Overview](../database/share-device-data-across-apps-overview.md).
......@@ -187,7 +187,7 @@ On device A, touch the **Start** button provided by the initiator application to
// ...
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbilityForResult(want).then((data) => {
if (data?.resultCode === RESULT_CODE) {
// Parse the information returned by the target UIAbility.
......@@ -384,12 +384,12 @@ The following describes how to implement multi-device collaboration through cros
```json
"abilities":[{
"name": ".CalleeAbility",
"srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
"srcEnty": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"visible": true
"exported": true
}]
```
......@@ -459,7 +459,7 @@ The following describes how to implement multi-device collaboration through cros
onDestroy() {
try {
this.callee.off(MSG_SEND_METHOD)
this.callee.off(MSG_SEND_METHOD)
} catch (error) {
console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`)
}
......@@ -491,7 +491,7 @@ The following describes how to implement multi-device collaboration through cros
if (data != null) {
caller = data
console.info('get remote caller success')
// Register the onRelease listener of the CallerAbility.
// Register the onRelease() listener of the CallerAbility.
caller.onRelease((msg) => {
console.info(`remote caller onRelease is called ${msg}`)
})
......
# LifecycleApp Switching
| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model|
| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model|
| -------- | -------- | -------- |
| onShow?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback&lt;WindowStageEventType&gt;): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)<br>Listens for the switching to the [foreground](../reference/apis/js-apis-window.md#windowstageeventtype9).|
| onHide?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback&lt;WindowStageEventType&gt;): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)<br>Listens for the switching to the [background](../reference/apis/js-apis-window.md#windowstageeventtype9).|
| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) |
| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) |
| onCreate?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate) |
| onWindowDisplayModeChanged?(isShownInMultiWindow: boolean, newConfig: resourceManager.Configuration): void; | There is no corresponding API in the stage model.| No corresponding API is provided.|
| onStartContinuation?(): boolean; | There is no corresponding API in the stage model.| In the stage model, an application does not need to detect whether the continuation is successful (detected when the application initiates the continuation request). Therefore, the **onStartContinuation()** callback is deprecated.|
| onSaveData?(data: Object): boolean; | \@ohos.app.ability.UIAbility.d.ts | [onContinue(wantParam : {[key: string]: any}): AbilityConstant.OnContinueResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncontinue) |
| onCompleteContinuation?(result: number): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) |
| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)<br>In standard or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.|
| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)<br>In multiton or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.|
| onRemoteTerminated?(): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) |
| onSaveAbilityState?(outState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onSaveState(reason: AbilityConstant.StateType, wantParam : {[key: string]: any}): AbilityConstant.OnSaveResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonsavestate) |
| onRestoreAbilityState?(inState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>After the application is restarted, the **onCreate()** callback is triggered. In the callback, **launchParam.launchReason** is used to determine whether it is a self-recovery scenario. If it is, the data saved before the restart can be obtained from the **want** parameter.|
......
......@@ -8,16 +8,19 @@ The following describes how the mission list manager manages the UIAbility insta
- **singleton**: Only one UIAbility instance exists for an application.
**Figure 1** Missions and singleton mode
![mission-and-singleton](figures/mission-and-singleton.png)
- **standard**: Each time **startAbility()** is called, a UIAbility instance is created in the application process.
- **multiton**: Each time **startAbility()** is called, a **UIAbility** instance is created in the application process.
**Figure 2** Missions and multiton mode
**Figure 2** Missions and standard mode
![mission-and-standard](figures/mission-and-standard.png)
![mission-and-multiton](figures/mission-and-standard.png)
- **specified**: The ([onAcceptWant](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create an instance.
- **specified**: The ([onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create an instance.
**Figure 3** Missions and specified mode
![mission-and-specified](figures/mission-and-specified.png)
......
......@@ -13,6 +13,7 @@ Before getting started with the development of mission management, be familiar w
- MissionListManager: system mission management module that maintains all the MissionLists and is consistent with the list in **Recents**.
**Figure 1** Mission management
![mission-list-manager](figures/mission-list-manager.png)
......
......@@ -8,7 +8,7 @@ When switching an application from the FA model to the stage model, you must mig
| Field Name in the FA Model| Field Description| Field Name in the Stage Model| Difference|
| -------- | -------- | -------- | -------- |
| mainAbility | Ability displayed on the Service Center icon. When the resident process is started, the **mainAbility** is started.| mainElement | The field name is changed, and the stage mode does not use the period (.) in ability names.|
| package | Package name of the HAP file, which must be unique in the application.| / | The stage model uses **name** to ensure application uniqueness. To ensure a successful switching from the FA model to the stage model, **name** in the stage model must be the same as **package** in the FA model.|
| package | Package name of the HAP file, which must be unique in the application.| / | The stage model uses **name** to ensure application uniqueness. |
| name | Class name of the HAP file.| / | This configuration is not enabled in the FA model, and the stage model does not have such a field.|
| supportedModes | Modes supported by the application. Currently, only the **drive** mode is defined.| / | This configuration is deprecated in the stage model.|
| moduleName in the distro object| Name of the current HAP file.<br>moduleName in the distro object.| name | The field name is changed.|
......@@ -21,11 +21,12 @@ When switching an application from the FA model to the stage model, you must mig
| shortcuts | Shortcuts of the application.| shortcut_config.json| In the stage model, the **shortcut_config.json** file is defined in **resources/base/profile** in the development view.|
| reqPermissions | Permissions that the application requests from the system when it is running.| requestPermissions | The field name is changed.|
| colorMode | Color mode of the application.| / | This configuration is not supported in the stage model.|
| distroFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.|
| distributionFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.|
| reqCapabilities | Device capabilities required for running the application.| / | This configuration is not supported in the stage model.|
| commonEvents | Common events.| common_event_config.json| In the stage model, the **common_event_config.json** file is defined in **resources/base/profile** in the development view.|
| entryTheme | Keyword of an OpenHarmony internal theme.| / | This configuration is not supported in the stage model.|
### Table 2 metaData Comparison
| Field Name Under metaData in the FA Model| Field Description| Field Name Under metaData in the Stage Model| Difference|
......@@ -40,7 +41,8 @@ When switching an application from the FA model to the stage model, you must mig
| -------- | -------- | -------- | -------- |
| name | Key name that identifies a data item. The value is a string with a maximum of 255 bytes.| name | None.|
| value | Value of the data item. The value is a string with a maximum of 255 bytes.| value | None.|
| extra | Format of the current custom data. The value is the resource value of **extra**.| resource | The field name is changed. For details, see [Table 4](#table-4-metadata-examples).|
| extra | Format of the current custom data. The value is the resource value of **extra**.| resource | The field name is changed. For details, see [Table 4](#table 4-metadata-examples).|
### Table 4 metaData Examples
......@@ -69,5 +71,5 @@ When switching an application from the FA model to the stage model, you must mig
| formsEnabled | Whether the ability can provide widgets.| / | This configuration is not supported in the stage model.|
| forms | Information about the widgets used by the ability. This field is valid only when **formsEnabled** is set to **true**.| form_config.json| In the stage model, the **form_config.json** file is defined in **resources/base/profile** in the development view.|
| srcLanguage | Programming language used to develop the ability.| / | This configuration is not supported in the stage model.|
| srcPath | Path of the JS component code corresponding to the ability.| srcEntrance | Path of the JS code corresponding to the ability.|
| srcPath | Path of the JS component code corresponding to the ability.| srcEnty | Path of the JS code corresponding to the ability.|
| uriPermission | Application data that the ability can access.| / | This configuration is not supported in the stage model.|
......@@ -5,10 +5,10 @@ Depending on the launch type, the action performed when the PageAbility starts d
**Table 1** PageAbility launch types
| Launch Type| Description|
| -------- | -------- |
| singleton | Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.<br>A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.|
| standard | Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.<br>A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.|
| Launch Type| Meaning | Description|
| -------- | -------- | -------- |
| singleton | Singleton mode| Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.<br>A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.|
| standard | Multiton mode| Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.<br>A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.|
You can set **launchType** in the **config.json** file to configure the launch type. The sample code is as follows:
......@@ -19,8 +19,8 @@ You can set **launchType** in the **config.json** file to configure the launch t
// ...
"abilities": [
{
// singleton mode.
// standard mode.
// singleton means the singleton mode.
// standard means the multiton mode.
"launchType": "standard",
// ...
}
......@@ -30,7 +30,8 @@ You can set **launchType** in the **config.json** file to configure the launch t
```
When the PageAbility is started for the first time (either in standard or singleton mode), the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not.
When the PageAbility is started in multiton mode or it is started in singleton mode for the first time, the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not.
**Table 2** Callbacks specific to the singleton mode
......
......@@ -15,7 +15,8 @@ The OpenHarmony process model is shown below.
> NOTE
>
> You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications.
> - You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications.
> - To view information about all running processes, run the **hdc shell** command to enter the shell CLI of the device, and run the **ps -ef** command.
A system application can apply for multi-process permissions (as shown in the following figure) and configure a custom process for an HAP. UIAbility, DataShareExtensionAbility, and ServiceExtensionAbility in the HAP run in the custom process. Different HAPs run in different processes by configuring different process names.
......
......@@ -7,13 +7,14 @@ Generally, UI redirection within an application is triggered by users. However,
The PageAbility has a UI. It can use **startAbility()** to start an ability that has a UI and is visible to users.
The **visible** field under **abilities** in the **config.json** file specifies whether an ability can be started by other application components.
The **exported** field under **abilities** in the **config.json** file specifies whether an ability can be started by other application components.
**Table 1** Description of visible
**Table 1** Description of exported
| Name| Description| Initial Value Allowed|
| -------- | -------- | -------- |
| visible | Whether the ability can be called by other applications.<br>**true**: The ability can be called by any application.<br>**false**: The ability can be called only by other components of the same application.| Yes (initial value: **false**)|
| exported | Whether the ability can be called by other applications.<br>**true**: The ability can be called by any application.<br>**false**: The ability can be called only by other components of the same application.| Yes (initial value: **false**)|
To enable an ability to be called by any application, configure the **config.json** file as follows:
......@@ -24,7 +25,7 @@ To enable an ability to be called by any application, configure the **config.jso
// ...
"abilities": [
{
"visible": "true",
"exported": "true",
// ...
}
]
......@@ -33,4 +34,4 @@ To enable an ability to be called by any application, configure the **config.jso
```
If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant.
If the ability contains **skills**, you are advised to set **exported** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **exported** set to **false** are home screen, voice assistant, or search assistant.
# ServiceExtensionAbility
## Overview
[ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) is an ExtensionAbility component of the service type that provides extension capabilities related to background services.
[ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) is an ExtensionAbility component of the SERVICE type that provides capabilities related to background services. It holds an internal [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md), through which a variety of APIs are provided for external systems.
In this document, the started ServiceExtensionAbility component is called the server, and the component that starts ServiceExtensionAbility is called the client.
ServiceExtensionAbility can be started or connected by other application components to process transactions in the background based on the request of the caller. System applications can call the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability) method to start background services or call the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability) method to connect to background services. Third-party applications can call only **connectServiceExtensionAbility()** to connect to background services. The differences between starting and connecting to background services are as follows:
A ServiceExtensionAbility can be started or connected by other components to process transactions in the background based on the request of the caller. System applications can call the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method to start background services or call the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to background services. Third-party applications can call only **connectServiceExtensionAbility()** to connect to background services. The differences between starting and connecting to background services are as follows:
- **Starting**: In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB can still exist.
- In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB can still exist.
- **Connecting**: In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also exits.
- In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also exits.
Note the following:
- If a ServiceExtensionAbility is started only by means of connecting, its lifecycle is controlled by the client. A new connection is set up each time the client calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method. When the client exits or calls the [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextdisconnectserviceextensionability) method, the connection is disconnected. After all connections are disconnected, the ServiceExtensionAbility automatically exits.
Each type of ExtensionAbility has its own context. ServiceExtensionAbility has [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md). In this document, the started ServiceExtensionAbility component is called the server, and the component that starts ServiceExtensionAbility is called the client.
This topic describes how to use ServiceExtensionAbility in the following scenarios:
- [Implementing a Background Service (for System Applications Only)](#implementing-a-background-service-for-system-applications-only)
- [Starting a Background Service (for System Applications Only)](#starting-a-background-service-for-system-applications-only)
- [Connecting to a Background Service](#connecting-to-a-background-service)
- Once a ServiceExtensionAbility is started by means of starting, it will not exit automatically. System applications can call the [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstopserviceextensionability) method to stop it.
> **NOTE**
> - OpenHarmony does not support third-party applications in implementing ServiceExtensionAbility. If you want to implement transaction processing in the background, use background tasks. For details, see [Background Task](../task-management/background-task-overview.md).
>
>
> - Currently, third-party applications cannot implement ServiceExtensionAbility. If you want to implement transaction processing in the background, use background tasks. For details, see [Background Task](../task-management/background-task-overview.md).
> - UIAbility of a third-party application can connect to ServiceExtensionAbility provided by the system through the context.
>
> - Third-party applications can connect to ServiceExtensionAbility provided by the system only when they gain focus in the foreground.
## Implementing a Background Service (for System Applications Only)
## Lifecycle
[ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) provides the callbacks **onCreate()**, **onRequest()**, **onConnect()**, **onDisconnect()**, and **onDestory()**. Override them as required. The following figure shows the lifecycle of ServiceExtensionAbility.
**Figure 1** ServiceExtensionAbility lifecycle
**Figure 1** ServiceExtensionAbility lifecycle
![ServiceExtensionAbility-lifecycle](figures/ServiceExtensionAbility-lifecycle.png)
- **onCreate**
This callback is triggered when a service is created for the first time. You can perform initialization operations, for example, registering a common event listener.
This callback is triggered when a ServiceExtensionAbility is created for the first time. You can perform initialization operations, for example, registering a common event listener.
> **NOTE**
>
> If a service has been created, starting it again does not trigger the **onCreate()** callback.
> If a ServiceExtensionAbility has been created, starting it again does not trigger the **onCreate()** callback.
- **onRequest**
This callback is triggered when another component calls the **startServiceExtensionAbility()** method to start the service. After being started, the service runs in the background.
This callback is triggered when another component calls the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method to start a ServiceExtensionAbility. After being started, the ServiceExtensionAbility runs in the background. This callback is triggered each time the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method is called.
- **onConnect**
This callback is triggered when another component calls the **connectServiceExtensionAbility()** method to connect to the service. In this method, a remote proxy object (IRemoteObject) is returned, through which the client communicates with the server by means of RPC.
This callback is triggered when another component calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to a ServiceExtensionAbility. In this method, a remote proxy object (IRemoteObject) is returned, through which the client communicates with the server by means of RPC. At the same time, the system stores the remote proxy object (IRemoteObject). If another component calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to this ServiceExtensionAbility, the system directly returns the saved remote proxy object (IRemoteObject) and does not trigger the callback.
- **onDisconnect**
This callback is triggered when a component calls the **disconnectServiceExtensionAbility()** method to disconnect from the service.
This callback is triggered when the last connection is disconnected. A connection is disconnected when the client exits or the [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextdisconnectserviceextensionability) method is called.
- **onDestroy**
This callback is triggered when the service is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregister the listener.
This callback is triggered when ServiceExtensionAbility is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregister the listener.
## Implementing a Background Service (for System Applications Only)
## How to Develop
### Preparations
To implement a background service, manually create a ServiceExtensionAbility component in DevEco Studio. The procedure is as follows:
Only system applications can implement ServiceExtensionAbility. You must make the following preparations before development:
1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **serviceextability**.
- **Switching to the full SDK**: All APIs related to ServiceExtensionAbility are marked as system APIs and hidden by default. Therefore, you must manually obtain the full SDK from the mirror and switch to it in DevEco Studio. For details, see [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md).
2. In the **serviceextability** directory, right-click and choose **New > TypeScript File** to create a file named **ServiceExtAbility.ts**.
- **Requesting the AllowAppUsePrivilegeExtension privilege**: Only applications with the **AllowAppUsePrivilegeExtension** privilege can develop ServiceExtensionAbility. For details about how to request the privilege, see [Application Privilege Configuration Guide](../../device-dev/subsystems/subsys-app-privilege-config-guide.md).
3. Open the **ServiceExtAbility.ts** file, import the [RPC module](../reference/apis/js-apis-rpc.md), and reload the **onRemoteMessageRequest()** method to receive messages from the client and return the processing result to the client. **REQUEST_VALUE** is used to verify the service request code sent by the client.
```ts
import rpc from '@ohos.rpc';
const REQUEST_CODE = 99;
class StubTest extends rpc.RemoteObject {
constructor(des) {
super(des);
}
// Receive a message from the client and return the processing result to the client.
onRemoteMessageRequest(code, data, reply, option) {
if (code === REQUEST_CODE) {
// Receive data from the client.
// If the client calls data.writeInt() multiple times to write multiple pieces of data, the server can call data.readInt() multiple times to receive all the data.
let optFir = data.readInt();
let optSec = data.readInt();
// The server returns the data processing result to the client.
// In the example, the server receives two pieces of data and returns the sum of the two pieces of data to the client.
reply.writeInt(optFir + optSec);
}
return true;
}
// Send messages to the client in synchronous or asynchronous mode.
sendRequest(code, data, reply, options) {
return null;
}
}
```
### Defining IDL Interfaces
As a background service, ServiceExtensionAbility needs to provide interfaces that can be called by external systems. You can define the interfaces in IDL files and use the [IDL tool](../IDL/idl-guidelines.md) to generate proxy and stub files. The following demonstrates how to define a file named **IIdlServiceExt.idl**:
```cpp
interface OHOS.IIdlServiceExt {
int ProcessData([in] int data);
void InsertDataToMap([in] String key, [in] int val);
}
```
Create the **IdlServiceExt** directory in the **ets** directory corresponding to the module of the DevEco Studio project, and copy the files generated by the [IDL tool](../IDL/idl-guidelines.md) to this directory. Then create a file named **idl_service_ext_impl.ts** to implement the IDL interfaces.
```
├── ets
│ ├── IdlServiceExt
│ │ ├── i_idl_service_ext.ts # File generated.
│ │ ├── idl_service_ext_proxy.ts # File generated.
│ │ ├── idl_service_ext_stub.ts # File generated.
│ │ ├── idl_service_ext_impl.ts # Custom file used to implement IDL interfaces.
│ └
```
An example of **idl_service_ext_impl.ts** is as follows:
```ts
import {processDataCallback} from './i_idl_service_ext';
import {insertDataToMapCallback} from './i_idl_service_ext';
import IdlServiceExtStub from './idl_service_ext_stub';
const ERR_OK = 0;
const TAG: string = "[IdlServiceExtImpl]";
// You need to implement interfaces in this type.
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: processDataCallback): void {
// Implement service logic.
console.info(TAG, `processData: ${data}`);
callback(ERR_OK, data + 1);
}
insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
// Implement service logic.
console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`);
callback(ERR_OK);
}
}
```
### Creating a ServiceExtensionAbility
To manually create a ServiceExtensionAbility in the DevEco Studio project, perform the following steps:
1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **ServiceExtAbility**.
2. In the **ServiceExtAbility** directory, right-click and choose **New > TypeScript File** to create a file named **ServiceExtAbility.ts**.
```
├── ets
│ ├── IdlServiceExt
│ │ ├── i_idl_service_ext.ts # File generated.
│ │ ├── idl_service_ext_proxy.ts # File generated.
│ │ ├── idl_service_ext_stub.ts # File generated.
│ │ ├── idl_service_ext_impl.ts # Custom file used to implement IDL interfaces.
│ ├── ServiceExtAbility
│ │ ├── ServiceExtAbility.ts
```
3. In the **ServiceExtAbility.ts** file, add the dependency package for importing ServiceExtensionAbility. Customize a class that inherits from ServiceExtensionAbility and implement the lifecycle callbacks, and return the previously defined **ServiceExtImpl** object in the **onConnect** lifecycle callback.
4. In the **ServiceExtAbility.ts** file, add the dependency package for importing ServiceExtensionAbility. Customize a class that inherits from ServiceExtensionAbility and add the required lifecycle callbacks.
```ts
import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
import rpc from '@ohos.rpc';
const TAG: string = "[Example].[Entry].[ServiceExtAbility]";
const REQUEST_CODE = 99;
import ServiceExtImpl from '../IdlServiceExt/idl_service_ext_impl';
class StubTest extends rpc.RemoteObject {
// ...
}
const TAG: string = "[ServiceExtAbility]";
export default class ServiceExtAbility extends ServiceExtensionAbility {
serviceExtImpl = new ServiceExtImpl("ExtImpl");
onCreate(want) {
console.info(TAG, `onCreate, want: ${want.abilityName}`);
}
......@@ -130,7 +156,8 @@ To implement a background service, manually create a ServiceExtensionAbility com
onConnect(want) {
console.info(TAG, `onConnect, want: ${want.abilityName}`);
return new StubTest("test");
// Return the ServiceExtImpl object, through which the client can communicate with the ServiceExtensionAbility.
return this.serviceExtImpl;
}
onDisconnect(want) {
......@@ -143,8 +170,8 @@ To implement a background service, manually create a ServiceExtensionAbility com
}
```
5. Register ServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"service"** and **srcEntrance** to the code path of the ExtensionAbility component.
4. Register ServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"service"** and **srcEntry** to the code path of the ServiceExtensionAbility component.
```json
{
"module": {
......@@ -155,15 +182,14 @@ To implement a background service, manually create a ServiceExtensionAbility com
"icon": "$media:icon",
"description": "service",
"type": "service",
"visible": true,
"srcEntrance": "./ets/serviceextability/ServiceExtAbility.ts"
"exported": true,
"srcEntry": "./ets/ServiceExtAbility/ServiceExtAbility.ts"
}
]
}
}
```
## Starting a Background Service (for System Applications Only)
A system application uses the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability) method to start a background service. The [onRequest()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonrequest) callback is invoked, and the **Want** object passed by the caller is received through the callback. After the background service is started, its lifecycle is independent of that of the client. In other words, even if the client is destroyed, the background service can still run. Therefore, the background service must be stopped by calling [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) when its work is complete. Alternatively, another component can call [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability) to stop the background service.
......@@ -173,7 +199,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis
> [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability), [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability), and [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) of ServiceExtensionContext are system APIs and cannot be called by third-party applications.
1. Start a new ServiceExtensionAbility in a system application. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
```ts
let want = {
"deviceId": "",
......@@ -188,7 +214,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis
```
2. Stop ServiceExtensionAbility in the system application.
```ts
let want = {
"deviceId": "",
......@@ -203,7 +229,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis
```
3. ServiceExtensionAbility stops itself.
```ts
// this is the current ServiceExtensionAbility component.
this.context.terminateSelf().then(() => {
......@@ -213,35 +239,71 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis
})
```
> **NOTE**
>
> Background services can run in the background for a long time. To minimize resource usage, destroy it in time when a background service finishes the task of the requester. A background service can be stopped in either of the following ways:
>
> - The background service calls the [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) method to automatically stop itself.
>
> - Another component calls the [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability) method to stop the background service.
>
> After either method is called, the system destroys the background service.
## Connecting to a Background Service
Either a system application or a third-party application can connect to a service (service specified in the **Want** object) through [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability). The [onConnect()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonconnect) callback is invoked, and the **Want** object passed by the caller is received through the callback. In this way, a persistent connection is established.
Either a system application or a third-party application can connect to a ServiceExtensionAbility (specified in the **Want** object) through [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability). The [onConnect()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonconnect) callback is invoked, and the **Want** object passed by the caller is received through the callback. In this way, a persistent connection is established.
The ServiceExtensionAbility component returns an IRemoteObject in the **onConnect()** callback. Through this IRemoteObject, you can define communication interfaces for RPC interaction between the client and server. Multiple clients can connect to the same background service at the same time. After a client finishes the interaction, it must call [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextdisconnectserviceextensionability) to disconnect from the service. If all clients connected to a background service are disconnected, the system destroys the service.
- Call **connectServiceExtensionAbility()** to establish a connection to a background service. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
```ts
import rpc from '@ohos.rpc';
const REQUEST_CODE = 99;
let want = {
"deviceId": "",
"bundleName": "com.example.myapplication",
"abilityName": "ServiceExtAbility"
};
let options = {
onConnect(elementName, remote) {
/* The input parameter remote is the object returned by ServiceExtensionAbility in the onConnect lifecycle callback.
* This object is used for communication with ServiceExtensionAbility. For details, see the section below.
*/
console.info('onConnect callback');
if (remote === null) {
console.info(`onConnect remote is null`);
return;
}
},
onDisconnect(elementName) {
console.info('onDisconnect callback')
},
onFailed(code) {
console.info('onFailed callback')
}
}
// The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection.
let connectionId = this.context.connectServiceExtensionAbility(want, options);
```
- Use **disconnectServiceExtensionAbility()** to disconnect from the background service.
```ts
// connectionId is returned when connectServiceExtensionAbility is called and needs to be manually maintained.
this.context.disconnectServiceExtensionAbility(connectionId).then((data) => {
console.info('disconnectServiceExtensionAbility success');
}).catch((error) => {
console.error('disconnectServiceExtensionAbility failed');
})
```
## Communication Between the Client and Server
After obtaining the [rpc.RemoteObject](../reference/apis/js-apis-rpc.md#iremoteobject) object from the **onConnect()** callback, the client can communicate with ServiceExtensionAbility in either of the following ways:
- Using the IDL interface provided by the server for communication (recommended)
```ts
// The client needs to import idl_service_ext_proxy.ts provided by the server for external systems to the local project.
import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy';
let options = {
onConnect(elementName, remote) {
console.info('onConnect callback');
......@@ -249,23 +311,54 @@ The ServiceExtensionAbility component returns an IRemoteObject in the **onConnec
console.info(`onConnect remote is null`);
return;
}
let serviceExtProxy = new IdlServiceExtProxy(remote);
// Communication is carried out by interface calling, without exposing RPC details.
serviceExtProxy.processData(1, (errorCode, retVal) => {
console.log(`processData, errorCode: ${errorCode}, retVal: ${retVal}`);
});
serviceExtProxy.insertDataToMap('theKey', 1, (errorCode) => {
console.log(`insertDataToMap, errorCode: ${errorCode}`);
})
},
onDisconnect(elementName) {
console.info('onDisconnect callback')
},
onFailed(code) {
console.info('onFailed callback')
}
}
```
- Calling [sendMessageRequest](../reference/apis/js-apis-rpc.md#sendmessagerequest9) to send messages to the server (not recommended)
```ts
import rpc from '@ohos.rpc';
const REQUEST_CODE = 1;
let options = {
onConnect(elementName, remote) {
console.info('onConnect callback');
if (remote === null) {
console.info(`onConnect remote is null`);
return;
}
// Directly call the RPC interface to send messages to the server. The client needs to serialize the input parameters and deserialize the return values. The process is complex.
let option = new rpc.MessageOption();
let data = new rpc.MessageParcel();
let reply = new rpc.MessageParcel();
let data = new rpc.MessageSequence();
let reply = new rpc.MessageSequence();
data.writeInt(100);
data.writeInt(200);
// @param code Indicates the service request code sent by the client.
// @param data Indicates the {@link MessageParcel} object sent by the client.
// @param data Indicates the {@link MessageSequence} object sent by the client.
// @param reply Indicates the response message object sent by the remote service.
// @param options Specifies whether the operation is synchronous or asynchronous.
//
// @return Returns {@code true} if the operation is successful; returns {@code false} otherwise.
remote.sendRequest(REQUEST_CODE, data, reply, option).then((ret) => {
remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret) => {
let msg = reply.readInt();
console.info(`sendRequest ret:${ret} msg:${msg}`);
console.info(`sendMessageRequest ret:${ret} msg:${msg}`);
}).catch((error) => {
console.info('sendRequest failed');
console.info('sendMessageRequest failed');
});
},
onDisconnect(elementName) {
......@@ -275,18 +368,90 @@ The ServiceExtensionAbility component returns an IRemoteObject in the **onConnec
console.info('onFailed callback')
}
}
// The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection.
let connectionId = this.context.connectServiceExtensionAbility(want, options);
```
- Use **disconnectServiceExtensionAbility()** to disconnect from the background service.
## Client Identity Verification by the Server
When ServiceExtensionAbility is used to provide sensitive services, the client identity must be verified. You can implement the verification on the stub of the IDL interface. For details about the IDL interface implementation, see [Defining IDL Interfaces](#defining-idl-interfaces). Two verification modes are recommended:
- **Verifying the client identity based on callerUid**
Call the [getCallingUid()](../reference/apis/js-apis-rpc.md#getcallinguid) method to obtain the UID of the client, and then call the [getBundleNameByUid()](../reference/apis/js-apis-bundleManager.md#bundlemanagergetbundlenamebyuid) method to obtain the corresponding bundle name. In this way, the client identify is verified. Note that [getBundleNameByUid()](../reference/apis/js-apis-bundleManager.md#bundlemanagergetbundlenamebyuid) is asynchronous, and therefore the server cannot return the verification result to the client. This verification mode applies when the client sends an asynchronous task execution request to the server. The sample code is as follows:
```ts
let connectionId = 1 // ID returned when the service is connected through connectServiceExtensionAbility.
this.context.disconnectServiceExtensionAbility(connectionId).then((data) => {
console.info('disconnectServiceExtensionAbility success');
}).catch((error) => {
console.error('disconnectServiceExtensionAbility failed');
})
import rpc from '@ohos.rpc';
import bundleManager from '@ohos.bundle.bundleManager';
import {processDataCallback} from './i_idl_service_ext';
import {insertDataToMapCallback} from './i_idl_service_ext';
import IdlServiceExtStub from './idl_service_ext_stub';
const ERR_OK = 0;
const ERR_DENY = -1;
const TAG: string = "[IdlServiceExtImpl]";
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: processDataCallback): void {
console.info(TAG, `processData: ${data}`);
let callerUid = rpc.IPCSkeleton.getCallingUid();
bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
console.info(TAG, 'getBundleNameByUid: ' + callerBundleName);
// Identify the bundle name of the client.
if (callerBundleName != 'com.example.connectextapp') { // The verification fails.
console.info(TAG, 'The caller bundle is not in whitelist, reject');
return;
}
// The verification is successful, and service logic is executed normally.
}).catch(err => {
console.info(TAG, 'getBundleNameByUid failed: ' + err.message);
});
}
insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
// Implement service logic.
console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`);
callback(ERR_OK);
}
}
```
- **Verifying the client identity based on callerTokenId**
Call the [getCallingTokenId()](../reference/apis/js-apis-rpc.md#getcallingtokenid) method to obtain the token ID of the client, and then call the [verifyAccessTokenSync()](../reference/apis/js-apis-abilityAccessCtrl.md#verifyaccesstokensync) method to check whether the client has a specific permission. Currently, OpenHarmony does not support permission customization. Therefore, only [system-defined permissions](../security/permission-list.md) can be verified. The sample code is as follows:
```ts
import rpc from '@ohos.rpc';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import {processDataCallback} from './i_idl_service_ext';
import {insertDataToMapCallback} from './i_idl_service_ext';
import IdlServiceExtStub from './idl_service_ext_stub';
const ERR_OK = 0;
const ERR_DENY = -1;
const TAG: string = "[IdlServiceExtImpl]";
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: processDataCallback): void {
console.info(TAG, `processData: ${data}`);
let callerTokenId = rpc.IPCSkeleton.getCallingTokenId();
let accessManger = abilityAccessCtrl.createAtManager();
// The permission to be verified varies depending on the service requirements. ohos.permission.SET_WALLPAPER is only an example.
let grantStatus =
accessManger.verifyAccessTokenSync(callerTokenId, "ohos.permission.SET_WALLPAPER");
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
console.info(TAG, `PERMISSION_DENIED`);
callback(ERR_DENY, data); // The verification fails and an error is returned.
return;
}
callback(ERR_OK, data + 1); // The verification is successful, and service logic is executed normally.
}
insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
// Implement service logic.
console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`);
callback(ERR_OK);
}
}
```
......@@ -12,7 +12,7 @@ import featureAbility from '@ohos.ability.featureAbility';
async function restartAbility() {
let wantInfo = {
bundleName: "com.sample.MyApplication",
abilityName: "EntryAbility",
abilityName: "MainAbility",
parameters: {
page: "pages/second"
}
......@@ -70,7 +70,7 @@ struct Index {
```
When the launch type of a PageAbility is set to **standard** or when the PageAbility with the launch type set to **singleton** is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page.
When a PageAbility in multiton mode is started or when the PageAbility in singleton mode is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page.
When a user touches the button on the page of the caller PageAbility, the **startAbility()** method is called to start the target PageAbility. The **want** parameter in **startAbility()** carries the specified page information.
......@@ -89,7 +89,7 @@ struct Index {
featureAbility.startAbility({
want: {
bundleName: "com.exm.myapplication",
abilityName: "com.exm.myapplication.EntryAbility",
abilityName: "com.exm.myapplication.MainAbility",
parameters: { page: "pages/page1" }
}
}).then((data) => {
......@@ -104,7 +104,7 @@ struct Index {
featureAbility.startAbility({
want: {
bundleName: "com.exm.myapplication",
abilityName: "com.exm.myapplication.EntryAbility",
abilityName: "com.exm.myapplication.MainAbility",
parameters: { page: "pages/page2" }
}
}).then((data) => {
......
......@@ -2,19 +2,14 @@
For an OpenHarmony application, each process has a main thread to provide the following functionalities:
- Manage other threads.
- Enable multiple UIAbility components of the same application to share the same main thread.
- Distribute input events.
- Draw the UI.
- Invoke application code callbacks (event processing and lifecycle callbacks).
- Manage the ArkTS engine instance of the main thread so that multiple UIAbility components can run on it.
- Manage ArkTS engine instances of other threads (such as the worker thread), for example, starting and terminating other threads.
- Distribute interaction events.
- Process application code callbacks (event processing and lifecycle management).
- Receive messages sent by the worker thread.
In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. It cannot directly operate the UI. The worker thread is created in the main thread and is independent of the main thread. A maximum of seven worker threads can be created.
In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. The worker thread is created in the main thread and is independent from the main thread. It cannot directly operate the UI. A maximum of seven worker threads can be created.
![thread-model-stage](figures/thread-model-stage.png)
......@@ -22,4 +17,5 @@ Based on the OpenHarmony thread model, different services run on different threa
> **NOTE**
>
> The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread.
> - The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread.
> - To view thread information about an application process, run the **hdc shell** command to enter the shell CLI of the device, and then run the **ps -p *<pid>* -T command**, where *<pid>* indicates the ID of the application process.
......@@ -38,7 +38,7 @@ Assume that your application has two UIAbility components: EntryAbility and Func
info: 'From the Index page of EntryAbility',
},
}
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbility(wantInfo).then(() => {
// ...
}).catch((err) => {
......@@ -65,7 +65,7 @@ Assume that your application has two UIAbility components: EntryAbility and Func
3. To stop the **UIAbility** instance after the FuncAbility service is complete, call **terminateSelf()** in FuncAbility.
```ts
// context is the UIAbilityContext of the UIAbility instance to stop.
// context is the AbilityContext of the UIAbility instance to stop.
this.context.terminateSelf((err) => {
// ...
});
......@@ -88,7 +88,7 @@ When starting FuncAbility from EntryAbility, you want the result to be returned
info: 'From the Index page of EntryAbility',
},
}
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbilityForResult(wantInfo).then((data) => {
// ...
}).catch((err) => {
......@@ -124,7 +124,7 @@ When starting FuncAbility from EntryAbility, you want the result to be returned
// ...
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbilityForResult(want).then((data) => {
if (data?.resultCode === RESULT_CODE) {
// Parse the information returned by the target UIAbility.
......@@ -187,7 +187,7 @@ This section describes how to start the UIAbility of another application through
entities: ['entity.system.default'],
}
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbility(wantInfo).then(() => {
// ...
}).catch((err) => {
......@@ -251,7 +251,7 @@ If you want to obtain the return result when using implicit Want to start the UI
entities: ['entity.system.default'],
}
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbilityForResult(wantInfo).then((data) => {
// ...
}).catch((err) => {
......@@ -289,7 +289,7 @@ If you want to obtain the return result when using implicit Want to start the UI
// Want parameter information.
};
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbilityForResult(want).then((data) => {
if (data?.resultCode === RESULT_CODE) {
// Parse the information returned by the target UIAbility.
......@@ -322,7 +322,7 @@ let wantInfo = {
router: 'funcA',
},
}
// context is the UIAbilityContext of the initiator UIAbility.
// context is the AbilityContext of the initiator UIAbility.
this.context.startAbility(wantInfo).then(() => {
// ...
}).catch((err) => {
......@@ -500,12 +500,12 @@ For the CalleeAbility, implement the callback to receive data and the methods to
```json
"abilities":[{
"name": ".CalleeAbility",
"srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
"srcEnty": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"visible": true
"exported": true
}]
```
......@@ -596,7 +596,7 @@ For the CalleeAbility, implement the callback to receive data and the methods to
2. Obtain the caller interface.
The **UIAbilityContext** attribute implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **UIAbilityContext**, uses **startAbilityByCall** to start the CalleeAbility, obtain the caller object, and register the **onRelease** listener of the CallerAbility. You need to implement processing based on service requirements.
The **context** attribute of the UIAbility implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the UIAbility, uses **startAbilityByCall** to start the CalleeAbility, obtain the caller object, and register the **onRelease** listener of the CallerAbility. You need to implement processing based on service requirements.
```ts
......
......@@ -6,7 +6,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility
- [Singleton](#singleton)
- [Standard](#standard)
- [Multiton](#multiton)
- [Specified](#specified)
......@@ -18,8 +18,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility
Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, if a UIAbility instance of this type already exists in the application process, the instance is reused. Therefore, only one UIAbility instance of this type exists in the system, that is, displayed in **Recents**.
**Figure 1** Demonstration effect in singleton mode
![uiability-launch-type1](figures/uiability-launch-type1.png)
![uiability-launch-type1](figures/uiability-launch-type1.gif)
> **NOTE**
>
......@@ -43,15 +42,15 @@ To use the singleton mode, set **launchType** in the [module.json5 configuration
```
## Standard
## Multiton
In standard mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**.
In multiton mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**.
**Figure 2** Demonstration effect in standard mode
**Figure 2** Demonstration effect in multiton mode
![standard-mode](figures/standard-mode.png)
![uiability-launch-type2](figures/uiability-launch-type2.gif)
To use the standard mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **standard**.
To use the multiton mode, set **launchType** in the [module.json5 file](../quick-start/module-configuration-file.md) to **multiton**.
```json
......@@ -60,7 +59,7 @@ To use the standard mode, set **launchType** in the [module.json5 configuration
// ...
"abilities": [
{
"launchType": "standard",
"launchType": "multiton",
// ...
}
]
......@@ -73,14 +72,13 @@ To use the standard mode, set **launchType** in the [module.json5 configuration
The **specified** mode is used in some special scenarios. For example, in a document application, you want a document instance to be created each time you create a document, but you want to use the same document instance when you repeatedly open an existing document.
**Figure 3** Demonstration effect in specified mode
![uiability-launch-type2](figures/uiability-launch-type2.png)
**Figure 3** Demonstration effect in specified mode
![uiability-launch-type3](figures/uiability-launch-type3.gif)
For example, there are two UIAbility components: EntryAbility and SpecifiedAbility (with the launch type **specified**). You are required to start SpecifiedAbility from EntryAbility.
1. In SpecifiedAbility, set the **launchType** field in the [module.json5 file](../quick-start/module-configuration-file.md) to **specified**.
```json
{
"module": {
......@@ -95,8 +93,8 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili
}
```
2. Create a unique string key for the instance. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application, based on the key, identifies the UIAbility instance used to respond to the request. In EntryAbility, add a custom parameter, for example, **instanceKey**, to the [want](want-overview.md) parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instance.
2. Create a unique string key for the instance. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application, based on the key, identifies the UIAbility instance used to respond to the request. In EntryAbility, add a custom parameter, for example, **instanceKey**, to the **want** parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instance.
```ts
// Configure an independent key for each UIAbility instance.
// For example, in the document usage scenario, use the document path as the key.
......@@ -120,10 +118,11 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili
// ...
})
```
3. During running, the internal service of UIAbility determines whether to create multiple instances. If the key is matched, the UIAbility instance bound to the key is started. Otherwise, a new UIAbility instance is created.
The launch type of SpecifiedAbility is set to **specified**. Before SpecifiedAbility is started, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the corresponding AbilityStage instance is invoked to parse the input **want** parameter and obtain the custom parameter **instanceKey**. A string key identifier is returned through the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the AbilityStage instance. [If the returned key corresponds to a started UIAbility instance](mission-management-launch-type.md#fig14520125175314), that UIAbility instance is switched to the foreground and gains focus again. Otherwise, a new instance is created and started.
3. Before SpecifiedAbility is started, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the corresponding AbilityStage instance is invoked to obtain the key of the UIAbility, because the launch type of SpecifiedAbility is set to **specified**. If a UIAbility instance matching the key exists, the system starts the UIAbility instance and invokes its [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback. Otherwise, the system creates a new UIAbility instance and invokes its [onCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate) and [onWindowStageCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate) callbacks.
In the sample code, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback parses the **want** parameter to obtain the custom parameter **instanceKey**. The service logic returns a key string based on **instanceKey** parameter to identify the UIAbility instance. If the returned key maps to a started UIAbility instance, the system pulls the UIAbility instance back to the foreground and obtains the focus. If the returned key does not map to a started UIAbility instance, the system creates a new UIAbility instance and starts it.
```ts
import AbilityStage from '@ohos.app.ability.AbilityStage';
......@@ -140,12 +139,12 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili
}
}
```
> **NOTE**
>
> 1. Assume that the application already has a UIAbility instance created, and the launch type of the UIAbility instance is set to **specified**. If [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called again to start the UIAbility instance, and the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of [AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md) matches a created UIAbility instance, the original UIAbility instance is started, and no new UIAbility instance is created. In this case, the [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback is invoked, but the [onCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate) and [onWindowStageCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate) callbacks are not.
> 2. AbilityStage is not automatically generated in the default project of DevEco Studio. For details about how to create an AbilityStage file, see [AbilityStage Component Container](abilitystage.md).
For example, in the document application, different keys are bound to different document instances. Each time a document is created, a new key (for example, file path) is passed, and a new UIAbility instance is created when UIAbility is started in AbilityStage. However, when you open an existing document, the same UIAbility instance is started again in AbilityStage.
The following steps are used as an example.
......@@ -153,6 +152,4 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili
1. Open file A. A UIAbility instance, for example, UIAbility instance 1, is started.
2. Close the process of file A in **Recents**. UIAbility instance 1 is destroyed. Return to the home screen and open file A again. A new UIAbility instance is started, for example, UIAbility instance 2.
3. Return to the home screen and open file B. A new UIAbility instance is started, for example, UIAbility instance 3.
4. Return to the home screen and open file A again. UIAbility instance 2 is started.
\ No newline at end of file
4. Return to the home screen and open file A again. UIAbility instance 2 is started. This is because the system automatically matches the key of the UIAbility instance and starts the UIAbility instance that has a matching key. In this example, UIAbility instance 2 has the same key as file A. Therefore, the system pulls back UIAbility instance 2 and focuses it without creating a new instance.
......@@ -37,7 +37,7 @@ To enable an application to properly use a UIAbility component, declare the UIAb
"abilities": [
{
"name": "EntryAbility", // Name of the UIAbility component.
"srcEntrance": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component.
"srcEnty": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component.
"description": "$string:EntryAbility_desc", // Description of the UIAbility component.
"icon": "$media:icon", // Icon of the UIAbility component.
"label": "$string:EntryAbility_label", // Label of the UIAbility component.
......
......@@ -364,7 +364,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi
> **NOTE**
>
> Only the JavaScript-based web-like development paradigm is supported when developing the widget UI.
> In the FA model, only the JavaScript-based web-like development paradigm is supported when developing the widget UI.
- HML: uses web-like paradigm components to describe the widget page information.
......@@ -452,7 +452,7 @@ You can set router and message events for components on a widget. The router eve
2. Set the router event.
- **action**: **"router"**, which indicates a router event.
- **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default MainAbility name created by DevEco Studio in the FA model is com.example.entry.MainAbility.
- **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name created by DevEco Studio in the FA model is com.example.entry.MainAbility.
- **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the MainAbility in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
3. Set the message event.
......@@ -543,4 +543,3 @@ The following is an example:
}
}
```
......@@ -11,7 +11,7 @@ Widget switching involves the following parts:
| Configuration Item | FA Model | Stage Model |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------ |
| Configuration item location | **formAbility** and **forms** are in the **config.json** file.| **extensionAbilities** (configuration for **formExtensionAbility**) is in the **module.json5** file in the level-1 directory, and **forms** (configuration for **forms** contained in **formExtensionAbility**) is in the **form_config.json** file in the level-2 directory.|
| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEntrance**, with the file name. |
| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEnty**, with the file name. |
| Programming language | **srcLanguage** can be set to **js** or **ets**. | This configuration item is unavailable. Only ets is supported. |
| Whether to enable widgets | formsEnabled | This configuration item is unavailable. The setting of **type** set to **form** means that the widgets are enabled. |
| Ability type | type: service | type: form |
......@@ -32,7 +32,7 @@ Figure 2 Widget configuration differences
| Item| FA Model| Stage Model|
| -------- | -------- | -------- |
| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEntrance**|
| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEnty**|
| Lifecycle| export default| import FormExtension from '\@ohos.app.form.FormExtensionAbility';<br>export default class FormAbility extends FormExtension|
......
# WindowExtensionAbility
[WindowExtensionAbility](../reference/apis/js-apis-application-windowExtensionAbility.md) is a type of ExtensionAbility component that allows a system application to be embedded in and displayed over another application.
......@@ -14,7 +15,7 @@ the context is [WindowExtensionContext](../reference/apis/js-apis-inner-applicat
>
## Setting an Embedded Ability (for System Applications Only)
## Setting an Embedded UIAbility (for System Applications Only)
The **WindowExtensionAbility** class provides **onConnect()**, **onDisconnect()**, and **onWindowReady()** lifecycle callbacks, which can be overridden.
......@@ -58,7 +59,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i
}
```
4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEntrance** to the code path of the ExtensionAbility component.
4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEnty** to the code path of the ExtensionAbility component.
```json
{
......@@ -66,11 +67,11 @@ To implement an embedded application, manually create a WindowExtensionAbility i
"extensionAbilities": [
{
"name": "WindowExtAbility",
"srcEntrance": "./ets/WindowExtAbility/WindowExtAbility.ts",
"srcEnty": "./ets/WindowExtAbility/WindowExtAbility.ts",
"icon": "$media:icon",
"description": "WindowExtension",
"type": "window",
"visible": true,
"exported": true,
}
],
}
......@@ -78,7 +79,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i
```
## Starting an Embedded Ability (for System Applications Only)
## Starting an Embedded UIAbility (for System Applications Only)
System applications can load the created WindowExtensionAbility through the AbilityComponent.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册