提交 789b9762 编写于 作者: R RayShih

sync 3.2 canary contents to 3.1 Release branch

Signed-off-by: NRayShih <shirui721@huawei.com>
上级 c5fe408b
# Ability Development # Ability Development
- [FA Model Overview](fa-brief.md) - [Ability Framework Overview](ability-brief.md)
- [Page Ability Development](fa-pageability.md) - FA Model
- [Service Ability Development](fa-serviceability.md) - [FA Model Overview](fa-brief.md)
- [Data Ability Development](fa-dataability.md) - [Page Ability Development](fa-pageability.md)
- [FA Widget Development](fa-formability.md) - [Service Ability Development](fa-serviceability.md)
- [Data Ability Development](fa-dataability.md)
- [FA Widget Development](fa-formability.md)
- Stage Model
- [Stage Model Overview](stage-brief.md)
- [Ability Development](stage-ability.md)
- [Service Extension Ability Development](stage-serviceextension.md)
- [Ability Continuation Development](stage-ability-continuation.md)
- [Ability Call Development](stage-call.md)
- [Stage Widget Development](stage-formextension.md)
- Other - Other
- [WantAgent Development](wantagent.md) - [WantAgent Development](wantagent.md)
- [Ability Assistant Usage](ability-assistant-guidelines.md) - [Ability Assistant Usage](ability-assistant-guidelines.md)
......
# Ability Framework Overview
An ability is an abstraction of a functionality that an application can provide. It is the minimum unit for the system to schedule applications. An application can contain one or more **Ability** instances.
The ability framework model has two forms.
- FA model, which applies to application development using API 8 and earlier versions. In the FA model, there are Feature Ability (FA) and Particle Ability (PA). The FA supports Page abilities, and the PA supports Service, Data, and Form abilities.
- Stage model, which is introduced since API 9. In the stage model, there are Ability and ExtensionAbility. The ExtensionAbility is further extended to ServiceExtensionAbility, FormExtensionAbility, DataShareExtensionAbility, and more.
The stage model is designed to make it easier to develop complex applications in the distributed environment. The table below lists the design differences between the two models.
| Item | FA Model | Stage Model |
| -------------- | ------------------------------------------------------------ | -------------------------------------------------------- |
| Development mode | Web-like APIs are provided. The UI development is the same as that of the stage model. | Object-oriented development mode is provided. The UI development is the same as that of the FA model. |
| Engine instance | Each ability in a process exclusively uses a JS VM engine instance. | Multiple abilities in a process share one JS VM engine instance. |
| Intra-process object sharing| Not supported. | Supported. |
| Bundle description file | The **config.json** file is used to describe the HAP and component information. The component must use a fixed file name.| The **module.json** file is used to describe the HAP and component information. The entry file name can be specified.|
| Component | Four types of components are provided: Page ability (used for UI page display), Service ability (used to provide services), Data ability (used for data sharing), and Form ability (used to provide widgets).| Two types of components are provided: Ability (used for UI page display) and Extension (scenario-based service extension). |
In addition, the following differences are available in the development process:
* Different ability types
![favsstage](figures/favsstage.png)
* Different ability lifecycles
![lifecycle](figures/lifecycle.png)
For details about the two models, see [FA Model Overview](fa-brief.md) and [Stage Model Overview](stage-brief.md).
...@@ -231,7 +231,7 @@ You should override **onDestroy** to delete widget data. ...@@ -231,7 +231,7 @@ You should override **onDestroy** to delete widget data.
} }
``` ```
For details about the persistence method, see [Lightweight Data Store Development](../database/database-storage-guidelines.md). For details about the persistence method, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
Note that the **Want** passed by the widget host to the widget provider contains a temporary flag, indicating whether the requested widget is a temporary one. Note that the **Want** passed by the widget host to the widget provider contains a temporary flag, indicating whether the requested widget is a temporary one.
......
...@@ -34,16 +34,15 @@ Description of ability lifecycle states: ...@@ -34,16 +34,15 @@ Description of ability lifecycle states:
You can override the lifecycle callbacks provided by the Page ability in the **app.js/app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. You can override the lifecycle callbacks provided by the Page ability in the **app.js/app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks.
### Launch Type ### Launch Type
The ability supports three launch types: singleton, multi-instance, and instance-specific. The ability supports two launch types: singleton and multi-instance.
The **launchType** item in the **config.json** file is used to specify the launch type. The **launchType** item in the **config.json** file is used to specify the launch type.
| Launch Type | Description |Description | | Launch Type | Description |Description |
| ----------- | ------- |---------------- | | ----------- | ------- |---------------- |
| standard | Multi-instance | A new instance is started each time an ability starts.| | standard | Multi-instance | A new instance is started each time an ability starts.|
| singleton | Singleton | Only one instance exists in the system. If an instance already exists when an ability is started, that instance is reused.| | singleton | Singleton | Only one instance exists in the system. If an instance already exists when an ability is started, that instance is reused.|
| specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.|
By default, **standard** is used. By default, **singleton** is used.
## Development Guidelines ## Development Guidelines
...@@ -260,9 +259,6 @@ export default { ...@@ -260,9 +259,6 @@ export default {
}, },
} }
``` ```
### Development Example ## Samples
The following sample is provided to help you better understand how to develop a Page ability: The following sample is provided to help you better understand how to develop a Page ability:
- [`DMS`: Distributed Demo (eTS) (API7)](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS)
[DMS](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS)
This sample describes how to start a local ability and remote ability.
# Ability Continuation Development
## When to Use
Ability continuation is to continue the current mission of an application, including the UI component status variables and distributed objects, on another device. The UI component status variables are used to synchronize page data, and the distributed objects are used to synchronize data in the memory.
## Available APIs
The following table lists the APIs used for ability continuation. For details about the APIs, see [Ability](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-application-ability.md).
**Table 1** Ability continuation APIs
|API| Description|
|:------ | :------|
| onContinue(wantParam : {[key: string]: any}): OnContinueResult | Called by the **initiator** to save data during the ability continuation preparation process. The return value **0** means that the continuation request is accepted, and an error code means that the continuation request is denied.|
| onCreate(want: Want, param: LaunchParam): void| Called by the **target** to restore the data and page.|
| **enum** OnContinueResult | Enumerates the return values of **onContinue**. The options are as follows: **AGREE** (request accepted), **REJECT** (request denied), and **MISMATCH** (version mismatch).|
**Figure 1** Ability continuation development
![continuation_dev](figures/continuation-info.png)
## How to Develop
### Application Continuation
1. Configuration
- Configure the application to support ability continuation.
Set the **continuable** field in the **module.json5** file to **true**. The default value is **false**. If this parameter is set to **false**, the application cannot be continued on another device.
```javascript
"continuable": true
```
* Configure the application startup type.
Set **launchType** in the **module.json5** to **standard**. Currently, only multi-instance applications can be continued on another device.
```javascript
"launchType": "standard"
```
* Apply for the distributed permissions.
Declare the **DISTRIBUTED_DATASYNC** permission in the **module.json5** file for the application.
```javascript
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
```
This permission must be granted by the user in a dialog box when the application is started for the first time. To enable the application to display a dialog box to ask for the permission, add the following code to **onWindowStageCreate** of the **Ability** class:
```javascript
requestPermissions = async () => {
let permissions: Array<string> = [
"ohos.permission.DISTRIBUTED_DATASYNC"
];
let needGrantPermission = false
let accessManger = accessControl.createAtManager()
Logger.info("app permission get bundle info")
let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100)
Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`)
for (const permission of permissions) {
Logger.info(`app permission query grant status ${permission}`)
try {
let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission)
if (grantStatus === PERMISSION_REJECT) {
needGrantPermission = true
break;
}
} catch (err) {
Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`)
needGrantPermission = true
break;
}
}
if (needGrantPermission) {
Logger.info("app permission needGrantPermission")
try {
await this.context.requestPermissionsFromUser(permissions)
} catch (err) {
Logger.error(`app permission ${JSON.stringify(err)}`)
}
} else {
Logger.info("app permission already granted")
}
}
```
2. Implement the **onContinue** API.
The **onContinue** API is called by the **initiator** to save the UI component status variables and memory data and prepare for continuation. After the application completes the continuation preparation, the system must return **OnContinueResult.AGREE** to accept the continuation request. If an error code is returned, the request is denied. If this API is not implemented, the system rejects the continuation request by default.
Modules to import:
```javascript
import Ability from '@ohos.application.Ability';
import AbilityConstant from '@ohos.application.AbilityConstant';
```
- To implement ability continuation, you must implement this API and have the value **AGREE** returned.
- Example
```javascript
onContinue(wantParam : {[key: string]: any}) {
Logger.info("onContinue using distributedObject")
// Set the user input data into the want parameter.
wantParam["input"] = AppStorage.Get<string>('ContinueInput');
Logger.info(`onContinue input = ${wantParam["input"]}`);
return AbilityConstant.OnContinueResult.AGREE
}
```
3. Implement the continuation logic in the **onCreate** API.
The **onCreate** API is called by the **target**. When the ability is started on the target device, this API is called to instruct the application to synchronize the memory data and UI component status, and triggers page restoration after the synchronization is complete. If the continuation logic is not implemented, the ability will be started in common startup mode and the page cannot be restored.
- The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate**.
- After data restore is complete, call **restoreWindowStage** to trigger page restoration.
* Example
```javascript
onCreate(want, launchParam) {
Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
globalThis.abilityWant = want;
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
let input = want.parameters.input // get user data from want params
AppStorage.SetOrCreate<string>('ContinueInput', input)
Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`)
this.contentStorage = new ContentStorage();
this.context.restoreWindowStage(this.contentStorage);
}
}
```
### Data Continuation
1. Use distributed objects.
Distributed data objects allow cross-device data synchronization like local variables. For two devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other device. Both devices can listen for the data changes and online and offline states of the other. For details, see [Distributed Data Object Development](https://gitee.com/openharmony/docs/blob/master/en/application-dev/database/database-distributedobject-guidelines.md).
In the ability continuation scenario, the distributed data object is used to synchronize the memory data from the local device to the target device.
- In **onContinue**, the initiator saves the data to be continued to the distributed object, sets the session ID, and sends the session ID to the target device through **wantParam**.
```javascript
import Ability from '@ohos.application.Ability';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({name:undefined});
export default class MainAbility extends Ability {
contentStorage : ContenStorage
sessionId : string;
onContinue(wantParam : {[key: string]: any}) {
Logger.info("onContinue using distributedObject")
this.sessionId = distributedObject.genSessionId();
// Set the session ID for the distributed data object.
g_object.setSessionId(this.sessionId);
g_object.name = "Amy";
// Set the session ID into the want parameter.
wantParam["session"] = this.sessionId;
return AbilityConstant.OnContinueResult.AGREE
}
```
- The target device obtains the session ID from **onCreate**, creates a distributed object, and associates the distributed object with the session ID. In this way, the distributed object can be synchronized. Before calling **restoreWindowStage**, ensure that all distributed objects required for continuation have been associated for correct data retrieval.
```javascript
import Ability from '@ohos.application.Ability';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({name:undefined});
export default class MainAbility extends Ability {
contentStorage : ContentStorage
sessionId : string;
statusCallback(sessionId, networkid, status) {
Logger.info(`continuation object status change, sessionId: ${sessionId}, status: ${status}, g_object.name: ${g_object.name}`)
}
onCreate(want, launchParam) {
Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
// Obtain the session ID of the distributed data object from the want parameter.
this.sessionId = want.parameters.session
Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`)
g_object.on("status", this.statusCallback);
// Set the session ID for data synchronization.
g_object.setSessionId(this.sessionId);
this.contentStorage = new ContentStorage();
this.context.restoreWindowStage(this.contentStorage);
}
}
}
```
For details about the complete example, see the sample.
# Ability Development
## When to Use
The stage model is an application development model introduced in API version 9. For details about this model, see [Stage Model Overview](stage-brief.md). To develop an ability based on the stage model, you must implement the following logic:
- Create Page abilities for an application that needs to be browsed on the screen and supports man-machine interaction, such as video playback and news browsing.
- Obtain ability configuration information, such as **ApplicationInfo**, **AbilityInfo**, and **HapModuleInfo**.
- Start an ability, start an ability with start options, start an ability with the returned result, or start an ability with an account ID.
- Request certain permissions from end users.
- Notify the ability stage and ability of environment configuration changes.
- Call common components. For details, see [Call Development](stage-call.md).
- Connect to and disconnect from the Service Extension ability. For details, see [Service Extension Ability Development](stage-serviceextension.md).
- Continue the application on another device. For details, see [Ability Continuation Development](stage-ability-continuation.md).
### Launch Type
The ability supports three launch types: singleton, multi-instance, and instance-specific.
The **launchType** item in the **module.json** file is used to specify the launch type.
| Launch Type | Description |Description |
| ----------- | ------- |---------------- |
| standard | Multi-instance | A new instance is started each time an ability starts.|
| singleton | Singleton | Only one instance exists in the system. If an instance already exists when an ability is started, that instance is reused.|
| specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.|
By default, **singleton** is used.
## Available APIs
The table below describes the APIs provided by the **AbilityStage** class, which has the **context** attribute. For details about the APIs, see [AbilityStage](../reference/apis/js-apis-application-abilitystage.md).
**Table 1** AbilityStage APIs
|API|Description|
|:------|:------|
|void onCreate()|Called when an ability stage is created.|
|string onAcceptWant(want: Want)|Called when a specified ability is started.|
|void onConfigurationUpdated(config: Configuration)|Called when the global configuration is updated.|
The table below describes the APIs provided by the **Ability** class. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md).
**Table 2** Ability APIs
|API|Description|
|:------|:------|
|void onCreate(want: Want, param: AbilityConstant.LaunchParam)|Called when an ability is created.|
|void onDestroy()|Called when the ability is destroyed.|
|void onWindowStageCreate(windowStage: window.WindowStage)|Called when a **WindowStage** is created for the ability. You can use the **window.WindowStage** APIs to implement operations such as page loading.|
|void onWindowStageDestroy()|Called when the **WindowStage** is destroyed for the ability.|
|void onForeground()|Called when the ability is running in the foreground.|
|void onBackground()|Called when the ability is switched to the background.|
|void onNewWant(want: Want)|Called when the ability startup mode is set to singleton.|
|void onConfigurationUpdated(config: Configuration)|Called when the configuration of the environment where the ability is running is updated.|
The **Ability** class has the **context** attribute, which belongs to the **AbilityContext** class. The **AbilityContext** class has attributes such as **abilityInfo** and **currentHapModuleInfo**. For details about the APIs, see [AbilityContext](../reference/apis/js-apis-ability-context.md).
**Table 3** AbilityContext APIs
|API|Description|
|:------|:------|
|void startAbility(want: Want, callback: AsyncCallback<void>)|Starts an ability.|
|void startAbility(want: Want, options: StartOptions, callback: AsyncCallback<void>)|Starts an ability with start options.|
|void startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback<void>)|Starts an ability with the account ID.|
|void startAbilityWithAccount(want: Want, accountId: number, options: StartOptions, callback: AsyncCallback<void>)|Starts an ability with the account ID and start options.|
|void startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>)|Starts an ability with the returned result.|
|void startAbilityForResult(want: Want, options: StartOptions, callback: AsyncCallback<AbilityResult>)|Starts an ability with the returned result and start options.|
|void startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback<AbilityResult>)|Starts an ability with the returned result and account ID.|
|void startAbilityForResultWithAccount(want: Want, accountId: number, options: StartOptions, callback: AsyncCallback<void>)|Starts an ability with the returned result, account ID, and start options.|
|void terminateSelf(callback: AsyncCallback<void>)|Destroys the Page ability.|
|void terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>)|Destroys the Page ability with the returned result.|
## How to Develop
### Creating Page Abilities for an Application
To create Page abilities for an application on the stage model, you must implement the **AbilityStage** class and ability lifecycle callbacks, and use the **Window** APIs to set the pages. The sample code is as follows:
1. Import the **AbilityStage** module.
```
import AbilityStage from "@ohos.application.AbilityStage"
```
2. Implement the **AbilityStage** class.
```ts
export default class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage onCreate")
}
}
```
3. Import the **Ability** module.
```js
import Ability from '@ohos.application.Ability'
```
4. Implement the lifecycle callbacks of the **Ability** class.
In the **onWindowStageCreate(windowStage)** API, use **loadContent** to set the pages to be loaded by the application. For details about how to use the **Window** APIs, see [Window Development](../windowmanager/window-guidelines.md).
```ts
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
}
onDestroy() {
console.log("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.log("MainAbility onWindowStageCreate")
windowStage.loadContent("pages/index").then((data) => {
console.log("MainAbility load content succeed with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("MainAbility load content failed with error: "+ JSON.stringify(error))
})
}
onWindowStageDestroy() {
console.log("MainAbility onWindowStageDestroy")
}
onForeground() {
console.log("MainAbility onForeground")
}
onBackground() {
console.log("MainAbility onBackground")
}
}
```
### Obtaining AbilityStage and Ability Configuration Information
Both the **AbilityStage** and **Ability** classes have the **context** attribute. An application can obtain the context of the **Ability** instance through **this.context** to obtain detailed configuration information. The following example shows how the ability stage obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute. The sample code is as follows:
```ts
import AbilityStage from "@ohos.application.AbilityStage"
export default class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage onCreate")
let context = this.context
console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir)
let currentHapModuleInfo = context.currentHapModuleInfo
console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name)
console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName)
let config = this.context.config
console.log("MyAbilityStage config language" + config.language)
}
}
```
The following example shows how the ability obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute. The sample code is as follows:
```ts
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
let context = this.context
console.log("MainAbility bundleCodeDir" + context.bundleCodeDir)
let abilityInfo = this.context.abilityInfo;
console.log("MainAbility ability bundleName" + abilityInfo.bundleName)
console.log("MainAbility ability name" + abilityInfo.name)
let config = this.context.config
console.log("MyAbilityStage config language" + config.language)
}
}
```
### Starting an Ability
An application can obtain the context of an **Ability** instance through **this.context** and then use the **StartAbility** API in the **AbilityContext** class to start the ability. The ability can be started by specifying **Want**, **StartOptions**, and **accountId**, and the operation result can be returned using a callback or **Promise** instance. The sample code is as follows:
```ts
let context = this.context
var want = {
"deviceId": "",
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
};
var options = {
windowMode: 0,
displayId: 2
};
context.startAbility(want, options).then((data) => {
console.log("Succeed to start ability with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("Failed to start ability with error: "+ JSON.stringify(error))
})
```
### Starting an Ability on a Remote Device (Available only to System Applications)
>Note: The **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. Therefore, cross-device ability startup applies only to system applications.
In the cross-device scenario, you must specify the ID of the remote device. The sample code is as follows:
```ts
let context = this.context
var want = {
"deviceId": getRemoteDeviceId(),
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
};
context.startAbility(want).then((data) => {
console.log("Succeed to start remote ability with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("Failed to start remote ability with error: "+ JSON.stringify(error))
})
```
Obtain the ID of a specified device from **DeviceManager**. The sample code is as follows:
```ts
import deviceManager from '@ohos.distributedHardware.deviceManager';
function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) {
var list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
### Requesting Permissions
If an application requires certain permissions, such as storage, location information, and log access, the application must request the permissions from end users. After determining the required permissions, add the permissions in the **module.json** file and use **requestPermissionsFromUser** to request the permissions from end users in the form of a dialog box. The following uses the permissions for calendar access as an example.
Modify the **module.json** file as follows:
```json
"requestPermissions": [
{
"name": "ohos.permission.READ_CALENDAR"
}
]
```
Request the permissions from end users in the form of a dialog box:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.READ_CALENDAR']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
### Notifying of Environment Configuration Changes
When the global configuration, for example, system language and color mode, changes, the **onConfigurationUpdated** API is called to notify the ability stage and ability. System applications can update the system language and color mode through the **updateConfiguration** API. The following example shows the implement of the **onConfigurationUpdated** callback in the **AbilityStage** class. The callback is triggered when the system language and color mode change. The sample code is as follows:
```ts
import Ability from '@ohos.application.Ability'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
export default class MyAbilityStage extends AbilityStage {
onConfigurationUpdated(config) {
console.log("MyAbilityStage onConfigurationUpdated")
console.log("MyAbilityStage config language" + config.language)
console.log("MyAbilityStage config colorMode" + config.colorMode)
}
}
```
The following example shows the implement of the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, and display parameters (such as the direction and density) change. The sample code is as follows:
```ts
import Ability from '@ohos.application.Ability'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
export default class MainAbility extends Ability { {
onConfigurationUpdated(config) {
console.log("MainAbility onConfigurationUpdated")
console.log("MainAbility config language" + config.language)
console.log("MainAbility config colorMode" + config.colorMode)
console.log("MainAbility config direction" + config.direction)
console.log("MainAbility config screenDensity" + config.screenDensity)
console.log("MainAbility config displayId" + config.displayId)
}
}
```
## Samples
The following sample is provided to help you better understand how to develop an ability on the stage model:
- [`StageCallAbility`: Stage Ability Creation and Usage (eTS) (API9)](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
# Stage Model Overview
### Design Ideas
The stage model is designed to make it easier to develop complex applications in the distributed environment.
The following figure shows the design ideas of the stage model.
![stagedesign](figures/stagedesign.png)
The stage model is designed based on the following considerations:
- **Balance between application capabilities and overall system power consumption**
On a running device, resources are preferentially guaranteed for foreground applications, on the prerequisites that the overall power consumption requirements of the system are met. The stage model balances the application capabilities and overall system power consumption through ability and UI separation, strict background control, scenario-based service mechanism, and single-process model.
- **Native support for component continuation and collaboration**
OpenHarmony natively supports distributed deployment. Therefore, its application framework must be designed for easier component migration and collaboration. The stage model achieves this design objective by providing features such as separation between ability and UI as well as integration of UI display and service capabilities.
- **Support for multiple device types and window forms**
To support multiple device types and facilitate the implementation of different window forms, the component manager and window manager must be decoupled at the architecture layer for easier tailoring. To achieve this goal, the stage model redefines the ability lifecycle and implements unidirectional dependency of the component manager and window manager.
### Basic Concepts
The following figure shows the basic concepts in the stage model.
![stageconcept](figures/stageconcept.png)
- **HAP**: Harmony Ability Package, also called module, which is the basic unit for building, distributing, and loading OpenHarmony applications. Each HAP has a unique name, which is called **moduleName**, in an application.
- **Bundle**: an OpenHarmony application identified by **appid**. A bundle can contain multiple HAP files. Each application has a **bundleName**. However, **bundleName** must be used together with **appid** and other information to uniquely identify an application.
- **AbilityStage**: runtime class of an HAP. It is created when the HAP is loaded to the process for the first time and is visible to developers in the runtime.
- **Application**: runtime class of a bundle, which is invisible to developers in the runtime.
- **Context**: provides various capabilities that can be invoked by developers during the runtime. The **Ability** and **ExtensionAbility** classes have their own context classes, which inherit the base class **Context**. The base class provides information such as the bundle name, module name, and path.
- **Ability**: provides lifecycle callback, holds the **AbilityContext** class, and supports component continuation and collaboration.
- **ExtensionAbility**: general name of scenario-based service extension abilities. The system defines multiple scenario-based **ExtensionAbility** classes, each of which has its own **ExtensionContext**.
- **WindowStage**: local window manager.
- **Window**: basic unit managed by the window manager. It has an ArkUI engine instance.
- **ArkUI Page**: displays declarative ArkUI.
### Lifecycle
The ability and ability stage lifecycles are the most important concepts in the basic process of an application. The comparison between the FA model lifecycle and stage model lifecycle is provided in [Ability Framework Overview](ability-brief.md). This section focuses on the ability lifecycle transition and the scheduling relationships between the ability, ability stage, and window stage.
![stageabilitylifecyclecallback](figures/stageabilitylifecyclecallback.png)
To implement multi-device-form tailoring and multi-window scalability, OpenHarmony decouples the component manager from the window manager. The ability lifecycle defined in the stage model includes only the creation, destruction, foreground, and background states. The gain focus and lose focus states that are closely related to UI content are defined in the window stage. This implements weak coupling between the abilities and windows. On the service side, the window manager notifies the component manager of the foreground and background changes, so the component manager only senses the foreground and background changes but not the focus changes.
### Ability Instances and Missions
Abilities can be started in any of the following modes:
+ **Singleton**: For each type of ability, only one instance exists in the application process. **Ability1** in the figure below is started in singleton mode.
+ **Standard**: Each time **startAbility** is called, an instance of the specified ability type is created in the application process. **Ability2** in the figure below is started in standard mode.
+ **Specified**: Before creating an **AbilityRecord**, you can create a key for the instance. Each time **startAbility** is called, the system asks the application which ability instance (corresponding to a key) will be used. **Ability3** in the figure below is started in specified mode.
Each ability instance corresponds to a mission in **Launcher Recent**.
The mission corresponding to each ability instance has a snapshot of the ability instance. After the ability instance is destroyed, the ability class information and snapshot are retained in the mission until the user deletes the information or the storage space exceeds the upper limit.
![AbilityComponentInstanceMission](figures/AbilityComponentInstanceMission.png)
### ExtensionAbility Mechanism
Different from the ability used for page display, the extension ability provides a restricted service running environment. It has the following features:
- Its process runs independently from the main process and shares the same storage sandbox with the main process. There is no inter-process communication (IPC) between the process and the main process.
- It has an independent context that provides scenario-specific APIs.
- It is created by the system, rather than by applications.
- The lifecycles of the extension ability and process are managed by the system.
The following figure uses the widget scenario as an example. You can inherit from the **FormExtensionAbility** base class to provide the widget details. The lifecycle of the **FormExtensionAbility** instance and that of the extension ability process where the instance is located are managed by **FormManagerService**, which is a system service.
![ExtensionAbility](figures/ExtensionAbility.png)
### Process Model
All OpenHarmony applications are designed to meet the single-process model. In the single-process model, an application is not allowed to configure multiple processes, and all processes in the application are created and managed by the system. Each application supports a maximum of three types of processes:
- Main process: runs all ability components, pages, and service logic.
- Extension process: runs classes derived from **ExtensionAbility** in the application. The lifecycle of this process is managed by a scenario-specific system service.
- Render process: created for the WebView and used to load the WebView rendering library.
The following figure shows the process model of an application.
![stageprocessmodel](figures/stageprocessmodel.png)
# Ability Call Development
## When to Use
Ability call is an extension of the ability capabilities. It enables an ability to be invoked by external systems. In this way, the ability can be displayed as a UI page on the foreground and created and run on the background. You can use the **Call** APIs to implement data sharing between different abilities through inter-process communication (IPC). There are two roles in the ability call: caller and callee. The following scenarios are involved in the ability call development:
- Creating a callee
- Accessing the callee
The following figure shows the ability call process.
![stage-call](figures/stage-call.png)
## Available APIs
The table below describes the ability call APIs. For details, see [Ability](../reference/apis/js-apis-application-ability.md#caller).
**Table 1** Ability call APIs
|API|Description|
|:------|:------|
|Promise<Caller> startAbilityByCall(want: Want)|Obtains the caller interface of the specified ability, and if the specified ability is not started, starts the ability in the background.|
|void on(method: string, callback: CalleeCallBack)|Callee.on: callback invoked when the callee registers a method.|
|void off(method: string)|Callee.off: callback invoked when the callee deregisters a method.|
|Promise<void> call(method: string, data: rpc.Sequenceable)|Caller.call: sends agreed sequenceable data to the callee.|
|Promise<rpc.MessageParcel> callWithResult(method: string, data: rpc.Sequenceable)|Caller.callWithResult: sends agreed sequenceable data to the callee and returns the agreed sequenceable data.|
|void release()|Caller.release: releases the caller interface.|
|void onRelease(callback: OnReleaseCallBack)|Caller.onRelease: registers a callback that is invoked when the caller is disconnected.|
## How to Develop
### Creating a Callee
For the callee, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use the **on** API to register a listener. When data does not need to be received, use the **off** API to deregister the listener.
1. Configure the ability startup mode.
Set the ability of the callee to **singleton** in the **module.json5** file.
|JSON Field|Description|
|:------|:------|
|"launchType"|Ability startup mode. Set this parameter to **singleton**.|
An example of the ability configuration is as follows:
```json
"abilities":[{
"name": ".CalleeAbility",
"srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"visible": true
}]
```
2. Import the **Ability** module.
```
import Ability from '@ohos.application.Ability'
```
3. Define the agreed sequenceable data.
The data formats sent and received by the caller and callee must be consistent. In the following example, the data consists of numbers and strings. The sample code is as follows:
```ts
export default class MySequenceable {
num: number = 0
str: String = ""
constructor(num, string) {
this.num = num
this.str = string
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num)
messageParcel.writeString(this.str)
return true
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt()
this.str = messageParcel.readString()
return true
}
}
```
4. Implement **Callee.on** and **Callee.off**.
The time to register a listener for the callee depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the **CalleeSortMethod** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns them. You need to implement processing based on service requirements. The sample code is as follows:
```ts
const TAG: string = '[CalleeAbility]'
const MSG_SEND_METHOD: string = 'CallSendMsg'
function sendMsgCallback(data) {
Logger.log(TAG, 'CalleeSortFunc called')
// Obtain the sequenceable data sent by the caller.
let receivedData = new MySequenceable(0, '')
data.readSequenceable(receivedData)
Logger.log(TAG, `receiveData[${receivedData.num}, ${receivedData.str}]`)
// Process the data.
// Return the sequenceable data result to the caller.
return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`)
}
export default class CalleeAbility extends Ability {
onCreate(want, launchParam) {
try {
this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
} catch (error) {
Logger.error(TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
}
}
onDestroy() {
try {
this.callee.off(MSG_SEND_METHOD)
} catch (error) {
console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`)
}
}
}
```
### Accessing the Callee
1. Import the **Ability** module.
```
import Ability from '@ohos.application.Ability'
```
2. Obtain the caller interface.
The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller interface of the ability. The following example uses **this.context** to obtain the **context** attribute of the **Ability** instance, uses **startAbilityByCall** to start the callee, obtain the caller interface, and register the **onRelease** listener of the caller. You need to implement processing based on service requirements. The sample code is as follows:
```ts
async onButtonGetCaller() {
try {
this.caller = await context.startAbilityByCall({
bundleName: 'com.samples.CallApplication',
abilityName: 'CalleeAbility'
})
if (this.caller === undefined) {
Logger.error(TAG, 'get caller failed')
return
}
Logger.log(TAG, 'get caller success')
this.regOnRelease(this.caller)
} catch (error) {
Logger.error(TAG, `get caller failed with ${error}`)
}
}.catch((error) => {
console.error(TAG + 'get caller failed with ' + error)
})
```
In the cross-device scenario, you need to specify the ID of the peer device. The sample code is as follows:
```ts
let TAG = '[MainAbility] '
var caller = undefined
let context = this.context
context.startAbilityByCall({
deviceId: getRemoteDeviceId(),
bundleName: 'com.samples.CallApplication',
abilityName: 'CalleeAbility'
}).then((data) => {
if (data != null) {
caller = data
console.log(TAG + 'get remote caller success')
// Register the onRelease listener of the caller.
caller.onRelease((msg) => {
console.log(TAG + 'remote caller onRelease is called ' + msg)
})
console.log(TAG + 'remote caller register OnRelease succeed')
}
}).catch((error) => {
console.error(TAG + 'get remote caller failed with ' + error)
})
```
Obtain the ID of the peer device from **DeviceManager**. Note that the **getTrustedDeviceListSync** API is open only to system applications. The sample code is as follows:
```ts
import deviceManager from '@ohos.distributedHardware.deviceManager';
var dmClass;
function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) {
var list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
3. Send agreed sequenceable data.
The sequenceable data can be sent to the callee in either of the following ways: without a return value or obtaining data returned by the callee. The method and sequenceable data must be consistent with those of the callee. The following example describes how to invoke the **Call** API to send data to the callee. The sample code is as follows:
```ts
const MSG_SEND_METHOD: string = 'CallSendMsg'
async onButtonCall() {
try {
let msg = new MySequenceable(1, 'origin_Msg')
await this.caller.call(MSG_SEND_METHOD, msg)
} catch (error) {
Logger.error(TAG, `caller call failed with ${error}`)
}
}
```
In the following, **CallWithResult** is used to send data **originMsg** to the callee and assign the data processed by the **CallSendMsg** method to **backMsg**. The sample code is as follows:
```ts
const MSG_SEND_METHOD: string = 'CallSendMsg'
originMsg: string = ''
backMsg: string = ''
async onButtonCallWithResult(originMsg, backMsg) {
try {
let msg = new MySequenceable(1, originMsg)
const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg)
Logger.log(TAG, 'caller callWithResult succeed')
let result = new MySequenceable(0, '')
data.readSequenceable(result)
backMsg(result.str)
Logger.log(TAG, `caller result is [${result.num}, ${result.str}]`)
} catch (error) {
Logger.error(TAG, `caller callWithResult failed with ${error}`)
}
}
```
4. Release the caller interface.
When the caller interface is no longer required, call the **release** API to release it. The sample code is as follows:
```ts
try {
this.caller.release()
this.caller = undefined
Logger.log(TAG, 'caller release succeed')
} catch (error) {
Logger.error(TAG, `caller release failed with ${error}`)
}
```
## Development Example
The following sample is provided to help you better understand how to develop an ability call in the stage model:
[StageCallAbility](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
In this sample, the **AbilityStage** APIs are implemented in the **AbilityStage.ts** file in the **Application** directory, the **Ability** APIs are implemented in the **MainAbility** directory, and **pages/index** is the pages of the ability. Another ability and callee are implemented in the **CalleeAbility** directory, and its pages are the content configured in **pages/second**. The **MainAbility** functions as the caller, and the **CalleeAbility** functions as the callee. After starting the **CalleeAbility**, the **MainAbility** obtains the caller interface, processes the string entered by the user, and transfers the processed string to the **CalleeAbility**. The **CalleeAbility** refreshes the page based on the received data and returns the result to the **MainAbility**.
# Stage Widget Development
## Widget Overview
A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application.
A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive features such as opening a UI page or sending a message. The widget host is responsible for displaying the service widget.
Basic concepts:
- Widget provider
The widget provider is an atomic service that provides the content to be displayed. It controls the display content, component layout, and component click events of a widget.
- Widget host
The widget host is an application that displays the widget content and controls the position where the widget is displayed in the host application.
- Widget Manager
The Widget Manager is a resident agent that manages widgets added to the system and provides functions such as periodic widget update.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The widget host and provider do not keep running all the time. The Widget Manager starts the widget provider to obtain widget information when a widget is added, deleted, or updated.
You only need to develop widget content as the widget provider. The system automatically handles the work done by the widget host and Widget Manager.
The widget provider controls the widget content to display, component layout, and click events bound to components.
## When to Use
Stage ability development refers to the development conducted by the widget provider based on the [stage model](stage-brief.md). As a widget provider, you need to carry out the following operations:
- Develop the lifecycle callback functions in **FormExtension**.
- Create a **FormBindingData** object.
- Update a widget through **FormProvider**.
- Develop the widget UI page.
## Available APIs
The **FormExtension** class has the **context** attribute. For details on the APIs provided by the **FormExtension** class, see [FormExtension](../reference/apis/js-apis-formextension.md).
**Table 1** FormExtension APIs
| API | Description |
| :----------------------------------------------------------- | :------------------------------------------- |
| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a **Form** instance (widget) has been created. |
| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.|
| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated. |
| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change of widget visibility. |
| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process the widget event. |
| onDestroy(formId: string): void | Called to notify the widget provider that a **Form** instance (widget) has been destroyed. |
| onConfigurationUpdated(config: Configuration): void; | Called when the configuration of the environment where the ability is running is updated. |
The **context** attribute of the **FormExtension** class inherits from the **FormExtensionContext** class. For details about the APIs provided by the **FormExtensionContext** class, see [FormExtensionContext](../reference/apis/js-apis-formextensioncontext.md).
**Table 2** FormExtensionContext APIs
| API | Description |
| :----------------------------------------------------------- | :------------------------ |
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback\<void>): void | Updates a widget. This method uses a callback to return the result. |
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise\<void> | Updates a widget. This method uses a promise to return the result.|
For details about the **FormProvider** APIs, see [FormProvider](../reference/apis/js-apis-formprovider.md).
**Table 3** FormProvider APIs
| API | Description |
| :----------------------------------------------------------- | :------------------------------------------------ |
| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback&lt;void&gt;): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result. |
| setFormNextRefreshTime(formId: string, minute: number): Promise&lt;void&gt;; | Sets the next refresh time for a widget. This API uses a promise to return the result.|
| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback&lt;void&gt;): void; | Updates a widget. This API uses an asynchronous callback to return the result. |
| updateForm(formId: string, formBindingData: FormBindingData): Promise&lt;void&gt;; | Updates a widget. This API uses a promise to return the result. |
## How to Develop
### Creating a Form Extension
To create a widget in the stage model, you need to implement the lifecycle callback functions of **FormExtension**. The sample code is as follows:
1. Import the required modules.
```javascript
import FormExtension from '@ohos.application.FormExtension'
import formBindingData from '@ohos.application.formBindingData'
import formInfo from '@ohos.application.formInfo'
import formProvider from '@ohos.application.formProvider'
```
2. Implement the lifecycle callback functions of **FormExtension**.
```javascript
export default class FormAbility extends FormExtension {
onCreate(want) {
console.log('FormAbility onCreate');
// Persistently store widget information for subsequent use, such as widget instance retrieval and update.
let obj = {
"title": "titleOnCreate",
"detail": "detailOnCreate"
};
let formData = formBindingData.createFormBindingData(obj);
return formData;
}
onCastToNormal(formId) {
// Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion.
console.log('FormAbility onCastToNormal');
}
onUpdate(formId) {
// To support scheduled update, periodic update, or update requested by the widget host for a widget, override this method for data update.
console.log('FormAbility onUpdate');
let obj = {
"title": "titleOnUpdate",
"detail": "detailOnUpdate"
};
let formData = formBindingData.createFormBindingData(obj);
formProvider.updateForm(formId, formData).catch((error) => {
console.log('FormAbility updateForm, error:' + JSON.stringify(error));
});
}
onVisibilityChange(newStatus) {
// Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification.
console.log('FormAbility onVisibilityChange');
}
onEvent(formId, message) {
// If the widget supports event triggering, override this method and implement the trigger.
console.log('FormAbility onEvent');
}
onDestroy(formId) {
// Delete widget data.
console.log('FormAbility onDestroy');
}
onConfigurationUpdated(config) {
console.log('FormAbility onConfigurationUpdated, config:' + JSON.stringify(config));
}
}
```
### Configuring config.json for the Form Ability
Configure the **module.json** file for the **Form** ability.
- The internal field structure of the **extensionAbility** module is described as follows:
| Field | Description | Data Type | Default |
| ----------- | ------------------------------------------------------------ | ---------- | -------------------- |
| name | Name of an extension ability. | String | No |
| srcEntrance | JS code path of the extension ability. | String | No |
| description | Description of the extension ability. The value can be a string or a resource index to descriptions in multiple languages.| String | Yes (initial value: left empty)|
| icon | Index of the extension ability icon file. | String | Yes (initial value: left empty)|
| label | Descriptive information about the extension ability presented externally. The value can be a string or a resource index to the description.| String | Yes (initial value: left empty)|
| type | Type of the extension ability. The value can be **form** or **service**. | String | No |
| permissions | Permissions required for abilities of another application to call the current ability. | String array| Yes (initial value: left empty)|
| metadata | Metadata of the extension ability. It describes the configuration information of the extension ability.| Object | Yes (initial value: left empty) |
For a Form Extension ability, set **type** to **form** and **metadata** to the widget details.
A configuration example is as follows:
```json
"extensionAbilities": [{
"name": "FormAbility",
"srcEntrance": "./ets/FormAbility/FormAbility.ts",
"label": "$string:form_FormAbility_label",
"description": "$string:form_FormAbility_desc",
"type": "form",
"metadata": [{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}]
}]
```
- Configure the widget profile module. In the metadata of the Form Extension ability, the resource file path specified by **ohos.extension.form** must be used. For example, **$profile:form_config** means that **form_config.json** in the **resources/base/profile/** directory of the development view is used as the widget profile.
The internal field structure is described as follows:
| Field | Description | Data Type | Default |
| ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ |
| name | Class name of the widget. The value is a string with a maximum of 127 bytes. | String | No |
| description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String | Yes (initial value: left empty) |
| src | Full path of the UI code corresponding to the widget. | String | No |
| window | Window-related configurations. | Object | Yes |
| isDefault | Whether the widget is a default one. Each ability has only one default widget.<br>**true**: The widget is the default one.<br>**false**: The widget is not the default one.| Boolean | No |
| colorMode | Color mode of the widget. Available values are as follows:<br>**auto**: The widget adopts the auto-adaptive color mode.<br>**dark**: The widget adopts the dark color mode.<br>**light**: The widget adopts the light color mode.| String | Yes (initial value: **auto**)|
| supportDimensions | Grid styles supported by the widget. Available values are as follows:<br>1 * 2: indicates a grid with one row and two columns.<br>2 * 2: indicates a grid with two rows and two columns.<br>2 * 4: indicates a grid with two rows and four columns.<br>4 * 4: indicates a grid with four rows and four columns.| String array| No |
| defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No |
| updateEnabled | Whether the widget can be updated periodically. Available values are as follows:<br>**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is preferentially recommended.<br>**false**: The widget cannot be updated periodically.| Boolean | No |
| scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute. | String | Yes (initial value: **0:0**) |
| updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.| Number | Yes (initial value: **0**) |
| formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) |
| formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) |
| metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) |
A configuration example is as follows:
```json
{
"forms": [{
"name": "widget",
"description": "This is a service widget.",
"src": "./js/widget/pages/index/index",
"window": {
"autoDesignWidth": true,
"designWidth": 720
},
"isDefault": true,
"colorMode": "auto",
"supportDimensions": ["2*2"],
"defaultDimension": "2*2",
"updateEnabled": true,
"scheduledUpdateTime": "10:30",
"updateDuration": 1,
"formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility"
}]
}
```
### Widget Data Persistence
Mostly, the widget provider is started only when it needs to obtain information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting a widget.
```javascript
onCreate(want) {
console.log('FormAbility onCreate');
let formId = want.parameters["ohos.extra.param.key.form_identity"];
let formName = want.parameters["ohos.extra.param.key.form_name"];
let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];
// Persistently store widget information for subsequent use, such as widget instance retrieval and update.
storeFormInfo(formId, formName, tempFlag, want);
let obj = {
"title": "titleOnCreate",
"detail": "detailOnCreate"
};
let formData = formBindingData.createFormBindingData(obj);
return formData;
}
```
You should override **onDestroy** to delete widget data.
```javascript
onDestroy(formId) {
// Delete widget data.
deleteFormInfo(formId);
console.log('FormAbility onDestroy');
}
```
For details about the persistence method, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
Note that the **Want** passed by the widget host to the widget provider contains a temporary flag, indicating whether the requested widget is a temporary one.
Normal widget: a widget that will be persistently used by the widget host
Temporary widget: a widget that is temporarily used by the widget host
Data of a temporary widget is not persistently stored. If the widget framework is killed and restarted, data of a temporary widget will be deleted. However, the widget provider is not notified of which widget is deleted, and still keeps the data. Therefore, the widget provider should implement data clearing. In addition, the widget host may convert a temporary widget into a normal one. If the conversion is successful, the widget provider should process the widget ID and store the data persistently. This prevents the widget provider from deleting persistent data when clearing temporary widgets.
### Developing the Widget UI Page
You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI.
- hml:
```html
<div class="container">
<stack>
<div class="container-img">
<image src="/common/widget.png" class="bg-img"></image>
</div>
<div class="container-inner">
<text class="title">{{title}}</text>
<text class="detail_text" onclick="routerEvent">{{detail}}</text>
</div>
</stack>
</div>
```
- css:
```css
.container {
flex-direction: column;
justify-content: center;
align-items: center;
}
.bg-img {
flex-shrink: 0;
height: 100%;
}
.container-inner {
flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
height: 100%;
width: 100%;
padding: 12px;
}
.title {
font-size: 19px;
font-weight: bold;
color: white;
text-overflow: ellipsis;
max-lines: 1;
}
.detail_text {
font-size: 16px;
color: white;
opacity: 0.66;
text-overflow: ellipsis;
max-lines: 1;
margin-top: 6px;
}
```
- json:
```json
{
"data": {
"title": "TitleDefault",
"detail": "TextDefault"
},
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.MyApplication.hmservice.FormAbility",
"params": {
"message": "add detail"
}
}
}
}
```
Now you've got a widget shown below.
![fa-form-example](figures/fa-form-example.png)
## Development Example
The following sample is provided to help you better understand how to develop a widget on the stage model:
[FormExtAbility](https://gitee.com/openharmony/app_samples/tree/master/ability/FormExtAbility)
This sample provides a widget. Users can create, update, and delete widgets on the home screen of their phones or by using their own widget host. This sample also implements widget information persistence by using lightweight data storage.
# Service Extension Ability Development
## When to Use
**ExtensionAbility** is the base class of the new Extension component in the stage model. It is used to process missions without UIs. The lifecycle of an Extension ability is simple, and it does not involve foreground or background. **ServiceExtensionAbility** is extended from **ExtensionAbility**.
You can customize a class that inherits from **ServiceExtensionAbility** and override the lifecycle callbacks in the base class to perform service logic operations during the initialization, connection, and disconnection processes.
## Available APIs
**Table 1** ServiceExtensionAbility lifecycle callbacks
|API|Description|
|:------|:------|
|onCreate|Called for the initialization when **startAbility** or **connectAbility** is invoked for a given ability for the first time.|
|onRequest|Called each time **startAbility** is invoked for a given ability. The initial value of **startId** is 1, and the value is incremented by one each time **startAbility** is invoked for that ability.|
|onConnect|Called when **connectAbility** is invoked for a given ability. This callback is not invoked for repeated calling of **connectAbility** for a specific ability. However, it will be invoked when **disconnectAbility** is called to disconnect an ability and then **connectAbility** is called to connect the ability again. The returned result is a **RemoteObject**.|
|onDisconnect|Called when **disconnectAbility** is called for a given ability. If the Extension ability is started by **connectAbility** and is not bound by other applications, the **onDestroy** callback will also be triggered to destroy the Extension ability.|
|onDestroy|Called when **terminateSelf** is invoked to terminate the ability.|
## Constraints
- Currently, OpenHarmony does not support creation of a Service Extension ability for third-party applications.
## How to Develop
1. Create a Service Extension ability.
Customize a class that inherits from **ServiceExtensionAbility** in the .ts file and override the lifecycle callbacks of the base class. The code sample is as follows:
```js
import rpc from '@ohos.rpc'
class StubTest extends rpc.RemoteObject {
constructor(des) {
super(des);
}
onRemoteRequest(code, data, reply, option) {
}
}
class ServiceExt extends ServiceExtensionAbility {
onCreate(want) {
console.log('onCreate, want:' + want.abilityName);
}
onRequest(want, startId) {
console.log('onRequest, want:' + want.abilityName);
}
onConnect(want) {
console.log('onConnect , want:' + want.abilityName);
return new StubTest("test");
}
onDisconnect(want) {
console.log('onDisconnect, want:' + want.abilityName);
}
onDestroy() {
console.log('onDestroy');
}
}
```
2. Register the Service Extension ability.
Declare the Service Extension ability in the **module.json** file by setting its **type** attribute to **service**.
**module.json configuration example**
```json
"extensionAbilities":[{
"name": "ServiceExtAbility",
"icon": "$media:icon",
"description": "service",
"type": "service",
"visible": true,
"srcEntrance": "./ets/ServiceExtAbility/ServiceExtAbility.ts"
}]
```
## Development Example
The following sample is provided to help you better understand how to develop a Service Extension ability:
- [ServiceExtensionAbility](https://gitee.com/openharmony/app_samples/tree/master/ability/ServiceExtAbility)
This sample shows how to:
Create a Service Extension ability in the **ServiceExtAbility.ts** file in the **ServiceExtensionAbility** directory.
...@@ -475,6 +475,7 @@ ...@@ -475,6 +475,7 @@
- [@ohos.application.appManager](reference/apis/js-apis-appmanager.md) - [@ohos.application.appManager](reference/apis/js-apis-appmanager.md)
- [@ohos.application.Configuration](reference/apis/js-apis-configuration.md) - [@ohos.application.Configuration](reference/apis/js-apis-configuration.md)
- [@ohos.application.ConfigurationConstant](reference/apis/js-apis-configurationconstant.md) - [@ohos.application.ConfigurationConstant](reference/apis/js-apis-configurationconstant.md)
- [@ohos.application.abilityMonitor](reference/apis/js-apis-application-abilityMonitor.md)
- [@ohos.ability.featureAbility](reference/apis/js-apis-featureAbility.md) - [@ohos.ability.featureAbility](reference/apis/js-apis-featureAbility.md)
- [@ohos.application.formBindingData](reference/apis/js-apis-formbindingdata.md) - [@ohos.application.formBindingData](reference/apis/js-apis-formbindingdata.md)
- [@ohos.application.FormExtension](reference/apis/js-apis-formextension.md) - [@ohos.application.FormExtension](reference/apis/js-apis-formextension.md)
......
# AbilityContext
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements the ability context. This module is inherited from **Context**.
## Usage
Before using the **AbilityContext** module, you must define a child class that inherits from **Ability**.
```js
import Ability from '@ohos.application.Ability'
class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
let context = this.context;
}
}
```
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| abilityInfo | AbilityInfo | Yes| No| Ability information.|
| currentHapModuleInfo | HapModuleInfo | Yes| No| Information about the current HAP.|
## AbilityContext.startAbility
startAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void
Starts an ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information about the **Want** used for starting an ability.|
| callback | AsyncCallback&lt;void&gt; | Yes| Callback used to return the result.|
**Example**
```js
var want = {
"deviceId": "",
"bundleName": "com.extreme.test",
"abilityName": "com.extreme.test.MainAbility"
};
this.context.startAbility(want, (error) => {
console.log("error.code = " + error.code)
})
```
## AbilityContext.startAbility
startAbility(want: Want, options: StartOptions, callback: AsyncCallback&lt;void&gt;): void
Starts an ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want) | Yes| Information about the **Want** used for starting an ability.|
| options | StartOptions | Yes| Parameters used for starting the ability.|
| callback | AsyncCallback&lt;void&gt; | Yes| Callback used to return the result.|
**Example**
```js
var want = {
"deviceId": "",
"bundleName": "com.extreme.test",
"abilityName": "com.extreme.test.MainAbility"
};
var options = {
windowMode: 0,
};
this.context.startAbility(want, options, (error) => {
console.log("error.code = " + error.code)
})
```
## AbilityContext.startAbility
startAbility(want: Want, options?: StartOptions): Promise&lt;void&gt;;
Starts an ability. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information about the **Want** used for starting an ability.|
| options | StartOptions | No| Parameters used for starting the ability.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result.|
**Example**
```js
var want = {
"deviceId": "",
"bundleName": "com.extreme.test",
"abilityName": "com.extreme.test.MainAbility"
};
var options = {
windowMode: 0,
};
this.context.startAbility(want, options)
.then((data) => {
console.log('Operation successful.')
}).catch((error) => {
console.log('Operation failed.');
})
```
## AbilityContext.startAbilityForResult
startAbilityForResult(want: Want, callback: AsyncCallback&lt;AbilityResult&gt;): void;
Starts an ability. This API uses a callback to return the execution result when the ability is terminated.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want |[Want](js-apis-featureAbility.md#Want)| Yes| Information about the **Want** used for starting an ability.|
| callback | AsyncCallback&lt;[AbilityResult](js-apis-featureAbility.md#abilityresult)&gt; | Yes| Callback used to return the result.|
**Example**
```js
this.context.startAbilityForResult(
{bundleName: "com.extreme.myapplication", abilityName: "MainAbilityDemo2"},
(error, result) => {
console.log("startAbilityForResult AsyncCallback is called, error.code = " + error.code)
console.log("startAbilityForResult AsyncCallback is called, result.resultCode = " + result.resultCode)
}
);
```
## AbilityContext.startAbilityForResult
startAbilityForResult(want: Want, options: StartOptions, callback: AsyncCallback&lt;AbilityResult&gt;): void;
Starts an ability. This API uses a callback to return the execution result when the ability is terminated.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want |[Want](js-apis-featureAbility.md#Want)| Yes| Information about the **Want** used for starting an ability.|
| options | StartOptions | Yes| Parameters used for starting the ability.|
| callback | AsyncCallback&lt;[AbilityResult](js-apis-featureAbility.md#abilityresult)&gt; | Yes| Callback used to return the result.|
**Example**
```js
var options = {
windowMode: 0,
};
this.context.startAbilityForResult(
{bundleName: "com.extreme.myapplication", abilityName: "MainAbilityDemo2"}, options,
(error, result) => {
console.log("startAbilityForResult AsyncCallback is called, error.code = " + error.code)
console.log("startAbilityForResult AsyncCallback is called, result.resultCode = " + result.resultCode)
}
);
```
## AbilityContext.startAbilityForResult
startAbilityForResult(want: Want, options?: StartOptions): Promise&lt;AbilityResult&gt;;
Starts an ability. This API uses a promise to return the execution result when the ability is terminated.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information about the **Want** used for starting an ability.|
| options | StartOptions | No| Parameters used for starting the ability.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;[AbilityResult](js-apis-featureAbility.md#abilityresult)&gt; | Promise used to return the result.|
**Example**
```js
var options = {
windowMode: 0,
};
this.context.startAbilityForResult({bundleName: "com.extreme.myapplication", abilityName: "MainAbilityDemo2"}, options).then((result) => {
console.log("startAbilityForResult Promise.resolve is called, result.resultCode = " + result.resultCode)
}, (error) => {
console.log("startAbilityForResult Promise.Reject is called, error.code = " + error.code)
})
```
## AbilityContext.terminateSelf
terminateSelf(callback: AsyncCallback&lt;void&gt;): void;
Terminates this ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;void&gt; | Yes| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.terminateSelf((err) => {
console.log('terminateSelf result:' + JSON.stringify(err));
});
```
## AbilityContext.terminateSelf
terminateSelf(): Promise&lt;void&gt;;
Terminates this ability. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.terminateSelf(want).then((data) => {
console.log('success:' + JSON.stringify(data));
}).catch((error) => {
console.log('failed:' + JSON.stringify(error));
});
```
## AbilityContext.terminateSelfWithResult
terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback&lt;void&gt;): void;
Terminates this ability. This API uses a callback to return the information to the caller of **startAbilityForResult**.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| parameter | [AbilityResult](js-apis-featureAbility.md#abilityresult) | Yes| Information returned to the caller.|
| callback | AsyncCallback&lt;void&gt; | Yes| Callback used to return the result.|
**Example**
```js
this.context.terminateSelfWithResult(
{
want: {bundleName: "com.extreme.myapplication", abilityName: "MainAbilityDemo"},
resultCode: 100
}, (error) => {
console.log("terminateSelfWithResult is called = " + error.code)
}
);
```
## AbilityContext.terminateSelfWithResult
terminateSelfWithResult(parameter: AbilityResult): Promise&lt;void&gt;;
Terminates this ability. This API uses a promise to return information to the caller of **startAbilityForResult**.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| parameter | [AbilityResult](js-apis-featureAbility.md#abilityresult) | Yes| Information returned to the caller.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result.|
**Example**
```js
this.context.terminateSelfWithResult(
{
want: {bundleName: "com.extreme.myapplication", abilityName: "MainAbilityDemo"},
resultCode: 100
}).then((result) => {
console.log("terminateSelfWithResult")
}
)
```
## AbilityContext.startAbilityByCall
startAbilityByCall(want: Want): Promise&lt;Caller&gt;;
Obtains the caller interface of the specified ability, and if the specified ability is not started, starts the ability in the background.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information about the ability to start, including the ability name, bundle name, and device ID. If the device ID is left blank or the default value is used, the local ability will be started.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;Caller&gt; | Promise used to return the caller object to communicate with.|
**Example**
```js
import Ability from '@ohos.application.Ability';
var caller;
export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
this.context.startAbilityByCall({
bundleName: "com.example.myservice",
abilityName: "com.example.myservice.MainAbility",
deviceId: ""
}).then((obj) => {
caller = obj;
console.log('Caller GetCaller Get ' + call);
}).catch((e) => {
console.log('Caller GetCaller error ' + e);
});
}
}
```
## AbilityContext.requestPermissionsFromUser
requestPermissionsFromUser(permissions: Array&lt;string&gt;, requestCallback: AsyncCallback&lt;PermissionRequestResult&gt;) : void;
Requests permissions from the user by displaying a pop-up window. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| permissions | Array&lt;string&gt; | Yes| Permissions to request.|
| callback | AsyncCallback&lt;[PermissionRequestResult](js-apis-permissionrequestresult.md)&gt; | Yes| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```
this.context.requestPermissionsFromUser(permissions,(result) => {
console.log('requestPermissionsFromUserresult:' + JSON.stringify(result));
});
```
## AbilityContext.requestPermissionsFromUser
requestPermissionsFromUser(permissions: Array&lt;string&gt;) : Promise&lt;PermissionRequestResult&gt;;
Requests permissions from the user by displaying a pop-up window. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| permissions | Array&lt;string&gt; | Yes| Permissions to request.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;[PermissionRequestResult](js-apis-permissionrequestresult.md)&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```
this.context.requestPermissionsFromUser(permissions).then((data) => {
console.log('success:' + JSON.stringify(data));
}).catch((error) => {
console.log('failed:' + JSON.stringify(error));
});
```
## AbilityContext.setMissionLabel
setMissionLabel(label: string, callback:AsyncCallback&lt;void&gt;): void;
Sets the label of the ability displayed in the task. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| label | string | Yes| Label of the ability to set.|
| callback | AsyncCallback&lt;void&gt; | Yes| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.setMissionLabel("test",(result) => {
console.log('requestPermissionsFromUserresult:' + JSON.stringify(result));
});
```
## AbilityContext.setMissionLabel
setMissionLabel(label: string): Promise&lt;void&gt;
Sets the label of the ability displayed in the task. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| label | string | Yes| Label of the ability to set.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.setMissionLabel("test").then((data) => {
console.log('success:' + JSON.stringify(data));
}).catch((error) => {
console.log('failed:' + JSON.stringify(error));
});
```
# AbilityStageContext
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements the context of an ability stage. This module is inherited from [Context](js-apis-application-context.md).
## Usage
The ability stage context is obtained through an **AbilityStage** instance.
```js
import AbilityStage from '@ohos.application.AbilityStage';
class MyAbilityStage extends AbilityStage {
onCreate() {
let abilityStageContext = this.context;
}
}
```
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| currentHapModuleInfo | HapModuleInfo | Yes| No| **ModuleInfo** object corresponding to the **AbilityStage**.|
| config | [Configuration](js-apis-configuration.md) | Yes| No| Configuration for the environment where the application is running.|
# Ability
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Manages the ability lifecycle and context.
## Modules to Import
```
import Ability from '@ohos.application.Ability';
```
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| context | [AbilityContext](js-apis-ability-context.md) | Yes| No| Context of an ability.|
| launchWant | [Want](js-apis-featureAbility.md#Want)| Yes| No| Parameters for starting the ability.|
| lastRequestWant | [Want](js-apis-featureAbility.md#Want)| Yes| No| Parameters used when the ability was started last time.|
## Ability.onCreate
onCreate(want: Want, param: AbilityConstant.LaunchParam): void;
Called to initialize the service logic when an ability is created.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information related to this ability, including the ability name and bundle name.|
| param | AbilityConstant.LaunchParam | Yes| Parameters for starting the ability, and the reason for the last abnormal exit.|
**Example**
```js
class myAbility extends Ability {
onCreate(want, param) {
console.log('onCreate, want:' + want.abilityName);
}
}
```
## Ability.onWindowStageCreate
onWindowStageCreate(windowStage: window.WindowStage): void
Called when a **WindowStage** is created for this ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| windowStage | window.WindowStage | Yes| **WindowStage** information.|
**Example**
```js
class myAbility extends Ability {
onWindowStageCreate(windowStage) {
console.log('onWindowStageCreate');
}
}
```
## Ability.onWindowStageDestroy
onWindowStageDestroy(): void
Called when the **WindowStage** is destroyed for this ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Example**
```js
class myAbility extends Ability {
onWindowStageDestroy() {
console.log('onWindowStageDestroy');
}
}
```
## Ability.onWindowStageRestore
onWindowStageRestore(windowStage: window.WindowStage): void
Called when the **WindowStage** is restored during the migration of this ability, which is a multi-instance ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| windowStage | window.WindowStage | Yes| **WindowStage** information.|
**Example**
```js
class myAbility extends Ability {
onWindowStageRestore(windowStage) {
console.log('onWindowStageRestore');
}
}
```
## Ability.onDestroy
onDestroy(): void;
Called when this ability is destroyed to clear resources.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Example**
```js
class myAbility extends Ability {
onDestroy() {
console.log('onDestroy');
}
}
```
## Ability.onForeground
onForeground(): void;
Called when this ability is running in the foreground.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Example**
```js
class myAbility extends Ability {
onForeground() {
console.log('onForeground');
}
}
```
## Ability.onBackground
onBackground(): void;
Callback when this ability is switched to the background.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Example**
```js
class myAbility extends Ability {
onBackground() {
console.log('onBackground');
}
}
```
## Ability.onContinue
onContinue(wantParam : {[key: string]: any}): AbilityConstant.OnContinueResult;
Called to save data during the ability migration preparation process.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| wantParam | {[key:&nbsp;string]:&nbsp;any} | Yes| **want** parameter.|
**Return value**
| Type| Description|
| -------- | -------- |
| AbilityConstant.OnContinueResult | Continuation result.|
**Example**
```js
class myAbility extends Ability {
onContinue(wantParams) {
console.log('onContinue');
wantParams["myData"] = "my1234567";
return true;
}
}
```
## Ability.onNewWant
onNewWant(want: Want): void;
Called when the ability startup mode is set to singleton.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Want parameters, such as the ability name and bundle name.|
**Example**
```js
class myAbility extends Ability {
onNewWant(want) {
console.log('onNewWant, want:' + want.abilityName);
}
}
```
## Ability.onConfigurationUpdated
onConfigurationUpdated(config: Configuration): void;
Called when the configuration of the environment where the ability is running is updated.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| config | [Configuration](js-apis-configuration.md) | Yes| New configuration.|
**Example**
```js
class myAbility extends Ability {
onConfigurationUpdated(config) {
console.log('onConfigurationUpdated, config:' + JSON.stringify(config));
}
}
```
## Caller
Implements sending of sequenceable data to the target ability when an ability (caller) invokes the target ability (callee).
## Caller.call
call(method: string, data: rpc.Sequenceable): Promise&lt;void&gt;;
Sends sequenceable data to the target ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| method | string | Yes| Notification message string negotiated between the two abilities. The message is used to instruct the callee to register a function to receive the sequenceable data.|
| data | rpc.Sequenceable | Yes| Sequenceable data. You need to customize the data.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return a response.|
**Example**
```js
import Ability from '@ohos.application.Ability';
class MyMessageAble{ // Custom sequenceable data structure
constructor(name, str) {
this.name = name;
this.str = str;
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num);
messageParcel.writeString(this.str);
console.log('MyMessageAble marshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt();
this.str = messageParcel.readString();
console.log('MyMessageAble unmarshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
};
var method = 'call_Function'; // Notification message string negotiated by the two abilities
var caller;
export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
this.context.startAbilityByCall({
bundleName: "com.example.myservice",
abilityName: "com.example.myservice.MainAbility",
deviceId: ""
}).then((obj) => {
caller = obj;
let msg = new MyMessageAble(1, "world"); // See the definition of Sequenceable.
caller.call(method, msg)
.then(() => {
console.log('Caller call() called');
}).catch((e) => {
console.log('Caller call() catch error ' + e);
});
console.log('Caller GetCaller Get ' + caller);
}).catch((e) => {
console.log('Caller GetCaller error ' + e);
});
}
}
```
## Caller.callWithResult
callWithResult(method: string, data: rpc.Sequenceable): Promise&lt;rpc.MessageParcel&gt;;
Sends sequenceable data to the target ability and obtains the sequenceable data returned by the target ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| method | string | Yes| Notification message string negotiated between the two abilities. The message is used to instruct the callee to register a function to receive the sequenceable data.|
| data | rpc.Sequenceable | Yes| Sequenceable data. You need to customize the data.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;rpc.MessageParcel&gt; | Promise used to return the sequenceable data from the target ability.|
**Example**
```js
import Ability from '@ohos.application.Ability';
class MyMessageAble{
constructor(name, str) {
this.name = name;
this.str = str;
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num);
messageParcel.writeString(this.str);
console.log('MyMessageAble marshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt();
this.str = messageParcel.readString();
console.log('MyMessageAble unmarshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
};
var method = 'call_Function';
var caller;
export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
this.context.startAbilityByCall({
bundleName: "com.example.myservice",
abilityName: "com.example.myservice.MainAbility",
deviceId: ""
}).then((obj) => {
caller = obj;
let msg = new MyMessageAble(1, "world");
caller.callWithResult(method, msg)
.then((data) => {
console.log('Caller callWithResult() called');
let retmsg = new MyMessageAble(0, "");
data.readSequenceable(retmsg);
}).catch((e) => {
console.log('Caller callWithResult() catch error ' + e);
});
console.log('Caller GetCaller Get ' + caller);
}).catch((e) => {
console.log('Caller GetCaller error ' + e);
});
}
}
```
## Caller.release
release(): void;
Releases the caller interface of the target ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Example**
```js
import Ability from '@ohos.application.Ability';
var caller;
export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
this.context.startAbilityByCall({
bundleName: "com.example.myservice",
abilityName: "com.example.myservice.MainAbility",
deviceId: ""
}).then((obj) => {
caller = obj;
try {
caller.release();
} catch (e) {
console.log('Caller Release error ' + e);
}
console.log('Caller GetCaller Get ' + caller);
}).catch((e) => {
console.log('Caller GetCaller error ' + e);
});
}
}
```
## Caller.onRelease
onRelease(callback: OnReleaseCallBack): void;
Registers a callback that is invoked when the Stub on the target ability is disconnected.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| callback | OnReleaseCallBack | Yes| Callback used for the **onRelease** API.|
**Example**
```js
import Ability from '@ohos.application.Ability';
var caller;
export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
this.context.startAbilityByCall({
bundleName: "com.example.myservice",
abilityName: "com.example.myservice.MainAbility",
deviceId: ""
}).then((obj) => {
caller = obj;
try {
caller.onRelease((str) => {
console.log(' Caller OnRelease CallBack is called ' + str);
});
} catch (e) {
console.log('Caller Release error ' + e);
}
console.log('Caller GetCaller Get ' + caller);
}).catch((e) => {
console.log('Caller GetCaller error ' + e);
});
}
}
```
## Callee
Implements callbacks for caller notification registration and unregistration.
## Callee.on
on(method: string, callback: CaleeCallBack): void;
Registers a caller notification callback, which is invoked when the target ability registers a function.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| method | string | Yes| Notification message string negotiated between the two abilities.|
| callback | CaleeCallBack | Yes| JS notification synchronization callback of the **rpc.MessageParcel** type. The callback must return at least one empty **rpc.Sequenceable** object. Otherwise, the function execution fails.|
**Example**
```js
import Ability from '@ohos.application.Ability';
class MyMessageAble{
constructor(name, str) {
this.name = name;
this.str = str;
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num);
messageParcel.writeString(this.str);
console.log('MyMessageAble marshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt();
this.str = messageParcel.readString();
console.log('MyMessageAble unmarshalling num[' + this.num + '] str[' + this.str + ']');
return true;
}
};
var method = 'call_Function';
function funcCallBack(pdata) {
console.log('Callee funcCallBack is called ' + pdata);
let msg = new MyMessageAble(0, "");
pdata.readSequenceable(msg);
return new MyMessageAble(10, "Callee test");
}
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('Callee onCreate is called');
this.callee.on(method, funcCallBack);
}
}
```
## Callee.off
off(method: string): void;
Unregisters a caller notification callback, which is invoked when the target ability registers a function.
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| method | string | Yes| Registered notification message string.|
**Example**
```js
import Ability from '@ohos.application.Ability';
var method = 'call_Function';
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('Callee onCreate is called');
this.callee.off(method);
}
}
```
## OnReleaseCallBack
(msg: string): void;
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| (msg: string) | function | Yes| No| Prototype of the listener function interface registered by the caller.|
## CaleeCallBack
(indata: rpc.MessageParcel): rpc.Sequenceable;
**System capability**: SystemCapability.Ability.AbilityRuntime.AbilityCore
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| (indata: rpc.MessageParcel) | rpc.Sequenceable | Yes| No| Prototype of the message listener function interface registered by the callee.|
# AbilityConstant
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides parameters related to ability launch.
## Modules to Import
```js
import AbilityConstant from '@ohos.application.AbilityConstant';
```
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| launchReason | LaunchReason| Yes| Yes| Ability launch reason.|
| lastExitReason | LastExitReason | Yes| Yes| Reason for the last exit.|
## AbilityConstant.LaunchReason
Enumerates ability launch reasons.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name | Value | Description |
| ----------------------------- | ---- | ------------------------------------------------------------ |
| UNKNOWN | 0 | Unknown reason.|
| START_ABILITY | 1 | Ability startup.|
| CALL | 2 | Call.|
| CONTINUATION | 3 | Ability continuation.|
## AbilityConstant.LastExitReason
Enumerates reasons for the last exit.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name | Value | Description |
| ----------------------------- | ---- | ------------------------------------------------------------ |
| UNKNOWN | 0 | Unknown reason.|
| ABILITY_NOT_RESPONDING | 1 | The ability does not respond.|
| NORMAL | 2 | Normal status.|
## AbilityConstant.OnContinueResult
Enumerates ability continuation results.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name | Value | Description |
| ----------------------------- | ---- | ------------------------------------------------------------ |
| AGREE | 0 | Continuation agreed.|
| REJECT | 1 | Continuation denied.|
| MISMATCH | 2 | Mismatch.|
# AbilityMonitor
> **NOTE**
>
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
## Modules to Import
```js
import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
```
## AbilityMonitor
Describes an ability monitor.
| Name | Type | Readable| Writable| Description |
| ------------------------------------------------------------ | -------- | ---- | ---- | ------------------------------------------------------------ |
| abilityName | string | Yes | Yes | Name of the ability bound to the ability monitor.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onAbilityCreate?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the ability is created.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onAbilityForeground?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the ability starts to run in the foreground.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onAbilityBackground?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the ability starts to run in the background.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onAbilityDestroy?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the ability is destroyed.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onWindowStageCreate?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the window stage is created.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onWindowStageRestore?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the window stage is restored.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
| onWindowStageDestroy?:(data: [Ability](js-apis-application-ability.md#Ability)) | function | Yes | Yes | Called when the window stage is destroyed.<br>If this attribute is not set, the corresponding lifecycle callback cannot be received.<br>**System capability**: SystemCapability.Ability.AbilityRuntime.Core|
# AbilityStage
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Runtime class for HAP files. It provides APIs to notify you when a HAP file starts loading. You can then initialize the HAP file, for example, pre-load resources and create threads.
## Modules to Import
```js
import AbilityStage from '@ohos.application.AbilityStage';
```
## AbilityStage.onCreate
onCreate(): void
Called when the application is created.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Example**
```js
class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage.onCreate is called")
}
}
```
## AbilityStage.onAcceptWant
onAcceptWant(want: Want): string;
Called when a specified ability is started.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information about the ability to start, such as the ability name and bundle name.|
**Return value**
| Type| Description|
| -------- | -------- |
| string | Returns an ability ID. If this ability has been started, no new instance is created and the ability is placed at the top of the stack. Otherwise, a new instance is created and started.|
**Example**
```js
class MyAbilityStage extends AbilityStage {
onAcceptWant(want) {
console.log("MyAbilityStage.onAcceptWant called");
return "com.example.test";
}
}
```
## AbilityStage.onConfigurationUpdated
onConfigurationUpdated(config: Configuration): void;
Called when the global configuration is updated.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| config | [Configuration](js-apis-configuration.md) | Yes| Callback invoked when the global configuration is updated. The global configuration indicates the configuration of the environment where the application is running and includes the language and color mode.|
**Example**
```js
class MyAbilityStage extends AbilityStage {
onConfigurationUpdated(config) {
console.log('onConfigurationUpdated, language:' + config.language);
}
}
```
## AbilityStage.context
Describes the configuration information about the context.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name | Type | Description |
| ----------- | --------------------------- | ------------------------------------------------------------ |
| context | [AbilityStageContext](js-apis-featureAbility.md) | Called when initialization is performed during ability startup.|
# Context
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides the context for running code, including **applicationInfo** and **resourceManager**.
## Usage
You must extend **AbilityContext** to implement this module.
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| resourceManager | ResourceManager | Yes| No| **ResourceManager** object.|
| applicationInfo | ApplicationInfo | Yes| No| Information about the application.|
| cacheDir | string | Yes| No| Cache directory of the application on the internal storage.|
| tempDir | string | Yes| No| Temporary file directory of the application.|
| filesDir | string | Yes| No| File directory of the application on the internal storage.|
| databaseDir | string | Yes| No| Storage directory of local data.|
| storageDir | string | Yes| No| Storage directory of lightweight data.|
| bundleCodeDir | string | Yes| No| Application installation path.|
| distributedFilesDir | string | Yes| No| Storage directory of distributed application data files.|
| eventHub | [EventHub](js-apis-eventhub.md) | Yes| No| Event hub information.|
## Context.createBundleContext
createBundleContext(bundleName: string): Context;
Creates an application context.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| bundleName | string | Yes| Application bundle name.|
**Return value**
| Type| Description|
| -------- | -------- |
| Context | Context of the application created.|
**Example**
```js
let test = "com.example.test";
let context = this.context.createBundleContext(test);
```
## Context.getApplicationContext
getApplicationContext(): Context;
Obtains the context of this application.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Return value**
| Type| Description|
| -------- | -------- |
| Context | Context obtained.|
**Example**
```js
// This part is mandatory.
let context = this.context.getApplicationContext();
```
# EventHub
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements event subscription, unsubscription, and triggering.
## Usage
Before using any APIs in the **EventHub**, you must obtain an **EventHub** instance through the member variable **context** of the **Ability** instance.
```js
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onForeground() {
this.context.eventHub.on("123", this.func1);
}
}
```
## EventHub.on
on(event: string, callback: Function): void;
Subscribes to an event.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| event | string | Yes| Event name.|
| callback | Function | Yes| Callback invoked when the event is triggered.|
**Example**
```js
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onForeground() {
this.context.eventHub.on("123", this.func1);
this.context.eventHub.on("123", () => {
console.log("call anonymous func 1");
});
// Result
// func1 is called
// call anonymous func 1
this.context.eventHub.emit("123");
}
func1() {
console.log("func1 is called");
}
}
```
## EventHub.off
off(event: string, callback?: Function): void;
Unsubscribes from an event. If **callback** is specified, this API unsubscribes from the specified callback. If **callback** is not specified, this API unsubscribes from all callbacks in the event.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| event | string | Yes| Event name.|
| callback | Function | No| Callback for the event. If **callback** is unspecified, all callbacks of the event are unsubscribed.|
**Example**
```js
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onForeground() {
this.context.eventHub.on("123", this.func1);
this.context.eventHub.off("123", this.func1); // Unsubscribe from func1.
this.context.eventHub.on("123", this.func1);
this.context.eventHub.on("123", this.func2);
this.context.eventHub.off("123"); // Unsubscribe from func1 and func2.
}
func1() {
console.log("func1 is called");
}
func2() {
console.log("func2 is called");
}
}
```
## EventHub.emit
emit(event: string, ...args: Object[]): void;
Triggers an event.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| event | string | Yes| Event name.|
| ...args | Object[] | Yes| Variable parameters, which are passed to the callback when the event is triggered.|
**Example**
```js
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onForeground() {
this.context.eventHub.on("123", this.func1);
// Result
// func1 is called,undefined,undefined
this.context.eventHub.emit("123");
// Result
// func1 is called,1,undefined
this.context.eventHub.emit("123", 1);
// Result
// func1 is called,1,2
this.context.eventHub.emit("123", 1, 2);
}
func1(a, b) {
console.log("func1 is called," + a + "," + b);
}
}
```
# ExtensionContext
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 8. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements the extension context. This module is inherited from **Context**.
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| currentHapModuleInfo | HapModuleInfo | Yes| No| Information about the current HAP. |
# ExtensionRunningInfo
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 8. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides extension running information.
## Usage
The extension running information is obtained through an **abilityManager** instance.
```
import abilitymanager from '@ohos.application.abilityManager';
abilitymanager.getExtensionRunningInfos(upperLimit, (err,data) => {
console.log("getExtensionRunningInfos err: " + err + " data: " + JSON.stringify(data));
});
```
### Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| extension | ElementName | Yes| No| Information that matches an extension.|
| pid | number | Yes| No| Process ID.|
| uid | number | Yes| No| User ID.|
| processName | string | Yes| No| Process name.|
| startTime | number | Yes| No| Extension start time.|
| clientPackage | Array&lt;String&gt; | Yes| No| Names of all packages in the process.|
| type | [bundle.ExtensionAbilityType](#bundleextensionabilitytype) | Yes| No| Extension type.|
## bundle.ExtensionAbilityType
Enumerates extension types.
**System capability**: SystemCapability.BundleManager.BundleFramework
| Name| Value| Description|
| -------- | -------- | -------- |
| FORM | 0 | Extension information of the form type.< |
| WORK_SCHEDULER | 1 | Extension information of the work scheduler type.< |
| INPUT_METHOD | 2 | Extension information of the input method type.< |
| SERVICE | 3 | Extension information of the service type.< |
| ACCESSIBILITY | 4 | Extension information of the accessibility type.< |
| DATA_SHARE | 5 | Extension information of the data share type.< |
| FILE_SHARE | 6 | Extension information of the file share type.< |
| STATIC_SUBSCRIBER | 7 | Extension information of the static subscriber type.< |
| WALLPAPER | 8 | Extension information of the wallpaper type.< |
| UNSPECIFIED | 9 | Extension information of the unspecified type.< |
# FormExtension
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides **FormExtension** APIs.
## Modules to Import
```
import FormExtension from '@ohos.application.FormExtension';
```
## Required Permissions
None
## Attributes
**System capability**: SystemCapability.Ability.Form
| Name | Type | Readable| Writable| Description |
| ------- | ------------------------------------------------------- | ---- | ---- | --------------------------------------------------- |
| context | [FormExtensionContext](js-apis-formextensioncontext.md) | Yes | No | Context of the **FormExtension**. This class is inherited from **ExtensionContext**.|
## onCreate
onCreate(want: Want): formBindingData.FormBindingData
Called to notify the widget provider that a **Form** instance (widget) has been created.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | -------------------------------------- | ---- | ------------------------------------------------------------ |
| want | [Want](js-apis-featureAbility.md#want) | Yes | Information related to the extension, including the widget ID, name, and style. The information must be managed as persistent data to facilitate subsequent widget update and deletion.|
**Return value**
| Type | Description |
| ------------------------------------------------------------ | ----------------------------------------------------------- |
| [formBindingData.FormBindingData](js-apis-formbindingdata.md#formbindingdata) | A **formBindingData.FormBindingData** object containing the data to be displayed on the widget.|
**Example**
```js
export default class MyFormExtension extends FormExtension {
onCreate(want) {
console.log('FormExtension onCreate, want:' + want.abilityName);
let dataObj1 = {
temperature:"11c",
"time":"11:00"
};
let obj1 = formBindingData.createFormBindingData(dataObj1);
return obj1;
}
}
```
## FormExtension.onCastToNormal
onCastToNormal(formId: string): void
Called to notify the widget provider that a temporary widget has been converted to a normal one.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ------ | ---- | ------------------------ |
| formId | string | Yes | ID of the widget that requests to be converted to a normal one.|
**Example**
```
export default class MyFormExtension extends FormExtension {
onCastToNormal(formId) {
console.log('FormExtension onCastToNormal, formId:' + formId);
}
}
```
## FormExtension.onUpdate
onUpdate(formId: string): void
Called to notify the widget provider that a widget has been updated. After obtaining the latest data, the caller invokes **updateForm** of the [FormExtensionContext](js-apis-formextensioncontext.md) class to update the widget data.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ------ | ---- | ------------------ |
| formId | string | Yes | ID of the widget that requests to be updated.|
**Example**
```js
export default class MyFormExtension extends FormExtension {
onUpdate(formId) {
console.log('FormExtension onUpdate, formId:' + formId);
let obj2 = formBindingData.createFormBindingData({temperature:"22c", time:"22:00"});
this.context.updateForm(formId, obj2)
.then((data)=>{
console.log('FormExtension context updateForm, data:' + data);
}).catch((error) => {
console.error('Operation updateForm failed. Cause: ' + error);});
}
}
```
## FormExtension.onVisibilityChange
onVisibilityChange(newStatus: { [key: string]: number }): void
Called to notify the widget provider of the change of visibility.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name | Type | Mandatory| Description |
| --------- | ------------------------- | ---- | ---------------------------- |
| newStatus | { [key: string]: number } | Yes | ID and visibility status of the widget to be changed.|
**Example**
```js
export default class MyFormExtension extends FormExtension {
onVisibilityChange(newStatus) {
console.log('FormExtension onVisibilityChange, newStatus:' + newStatus);
let obj2 = formBindingData.createFormBindingData({temperature:"22c", time:"22:00"});
for (let key in newStatus) {
console.log('FormExtension onVisibilityChange, key:' + key + ", value=" + newStatus[key]);
this.context.updateForm(key, obj2)
.then((data)=>{
console.log('FormExtension context updateForm, data:' + data);
}).catch((error) => {
console.error('Operation updateForm failed. Cause: ' + error);});
}
}
}
```
## FormExtension.onEvent
onEvent(formId: string, message: string): void
Called to instruct the widget provider to receive and process the widget event.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name | Type | Mandatory| Description |
| ------- | ------ | ---- | ---------------------- |
| formId | string | Yes | ID of the widget that requests the event.|
| message | string | Yes | Event message. |
**Example**
```js
export default class MyFormExtension extends FormExtension {
onEvent(formId, message) {
console.log('FormExtension onEvent, formId:' + formId + ", message:" + message);
}
}
```
## FormExtension.onDestroy
onDestroy(formId: string): void
Called to notify the widget provider that a **Form** instance (widget) has been destroyed.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ------ | ---- | ------------------ |
| formId | string | Yes | ID of the widget to be destroyed.|
**Example**
```js
export default class MyFormExtension extends FormExtension {
onDestroy(formId) {
console.log('FormExtension onDestroy, formId:' + formId);
}
}
```
## FormExtension.onConfigurationUpdated
onConfigurationUpdated(config: Configuration): void;
Called when the configuration of the environment where the ability is running is updated.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| config | [Configuration](#section188911144124715) | Yes| New configuration.|
**Example**
```js
class MyFormExtension extends MyFormExtension {
onConfigurationUpdated(config) {
console.log('onConfigurationUpdated, config:' + JSON.stringify(config));
}
}
```
# FormExtensionContext
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 8. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements the context that provides the capabilities and APIs of **FormExtension**. This class is inherited from **ExtensionContext**.
## FormExtensionContext.updateForm
updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback\<void>): void
Updates a widget. This method uses a callback to return the result.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name | Type | Mandatory| Description |
| --------------- | ------------------------------------------------------------ | ---- | -------------------------------------- |
| formId | string | Yes | ID of the widget that requests to be updated. |
| formBindingData | [formBindingData.FormBindingData](js-apis-formbindingdata.md#formbindingdata) | Yes | New data of the widget. |
| callback | AsyncCallback\<void> | Yes | Callback used to return the result indicating whether the method is successfully called.|
**Example**
```js
let obj2 = formBindingData.createFormBindingData({temperature:"22c", time:"22:00"});
this.context.updateForm(formId, obj2, (data)=>{
console.log('FormExtension context updateForm, data:' + data);
});
```
## FormExtensionContext.updateForm
updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise\<void>
Updates a widget. This method uses a promise to return the result.
**System capability**: SystemCapability.Ability.Form
**Parameters**
| Name | Type | Mandatory| Description |
| --------------- | ------------------------------------------------------------ | ---- | ------------------ |
| formId | string | Yes | ID of the widget that requests to be updated.|
| formBindingData | [formBindingData.FormBindingData](js-apis-formbindingdata.md#formbindingdata) | Yes | New data of the widget. |
**Return value**
| Type | Description |
| -------------- | --------------------------------- |
| Promise\<void> | Promise returned with the result indicating whether the method is successfully called.|
**Example**
```
let obj2 = formBindingData.createFormBindingData({temperature:"22c", time:"22:00"});
this.context.updateForm(formId, obj2)
.then((data)=>{
console.log('FormExtension context updateForm, data:' + data);
}).catch((error) => {
console.error('Operation updateForm failed. Cause: ' + error);});
```
# PermissionRequestResult
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides the permission request result.
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| permissions | Array&lt;string&gt; | Yes| No| Permissions requested.|
| authResults | Array&lt;number&gt; | Yes| No| Whether the requested permissions are granted or denied. The value **0** means that the requests permissions are granted, and **-1** means the opposite. |
# ServiceExtensionAbility
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Provides APIs related to **ServiceExtension**.
## Modules to Import
```
import ServiceExtension from '@ohos.application.ServiceExtensionAbility';
```
## Required Permissions
None.
## Attributes
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| context | [ServiceExtensionContext](js-apis-service-extension-context.md) | Yes| No| Service extension context, which is inherited from **ExtensionContext**.|
## ServiceExtensionAbility.onCreate
onCreate(want: Want): void;
Called when an extension is created to initialize the service logic.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information related to this extension, including the ability name and bundle name.|
**Example**
```js
class ServiceExt extends ServiceExtension {
onCreate(want) {
console.log('onCreate, want:' + want.abilityName);
}
}
```
## ServiceExtensionAbility.onDestroy
onDestroy(): void;
Called when this extension is destroyed to clear resources.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Example**
```js
class ServiceExt extends ServiceExtension {
onDestroy() {
console.log('onDestroy');
}
}
```
## ServiceExtensionAbility.onRequest
onRequest(want: Want, startId: number): void;
Called after **onCreate** is invoked when an ability is started by calling **startAbility**. The value of **startId** is incremented for each ability that is started.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information related to this extension, including the ability name and bundle name.|
| startId | number | Yes| Number of ability start times. The initial value is **1**, and the value is automatically incremented for each ability started.|
**Example**
```js
class ServiceExt extends ServiceExtension {
onRequest(want, startId) {
console.log('onRequest, want:' + want.abilityName);
}
}
```
## ServiceExtensionAbility.onConnect
onConnect(want: Want): rpc.RemoteObject;
Called after **onCreate** is invoked when an ability is started by calling **connectAbility**. A **RemoteObject** object is returned for communication with the client.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want)| Yes| Information related to this extension, including the ability name and bundle name.|
**Return value**
| Type| Description|
| -------- | -------- |
| rpc.RemoteObject | A **RemoteObject** object used for communication with the client.|
**Example**
```js
import rpc from '@ohos.rpc'
class StubTest extends rpc.RemoteObject{
constructor(des) {
super(des);
}
onRemoteRequest(code, data, reply, option) {
}
}
class ServiceExt extends ServiceExtension {
onConnect(want) {
console.log('onConnect , want:' + want.abilityName);
return new StubTest("test");
}
}
```
## ServiceExtensionAbility.onDisconnect
onDisconnect(want: Want): void;
Called when the ability is disconnected.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want |[Want](js-apis-featureAbility.md#Want)| Yes| Information related to this extension, including the ability name and bundle name.|
**Example**
```js
class ServiceExt extends ServiceExtension {
onDisconnect(want) {
console.log('onDisconnect, want:' + want.abilityName);
}
}
```
# ServiceExtensionContext
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 8. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements the context that provides the capabilities and APIs of **ServiceExtension**. This class is inherited from **ExtensionContext**.
## startAbility
startAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void;
Starts an ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want) | Yes| Information about the ability to start, such as the ability name and bundle name.|
| callback | AsyncCallback&lt;void&gt; | No| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```js
let want = {
"bundleName": "com.example.myapp",
"abilityName": "com.example.myapp.MyAbility"
};
this.context.startAbility(want, (err) => {
console.log('startAbility result:' + JSON.stringfy(err));
});
```
## ServiceExtensionContext.startAbility
startAbility(want: Want): Promise&lt;void&gt;;
Starts an ability. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want) | Yes| Information about the ability to start, such as the ability name and bundle name.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```js
let want = {
"bundleName": "com.example.myapp",
"abilityName": "com.example.myapp.MyAbility"
};
this.context.startAbility(want).then((data) => {
console.log('success:' + JSON.stringfy(data));
}).catch((error) => {
console.log('failed:' + JSON.stringfy(error));
});
```
## ServiceExtensionContext.terminateSelf
terminateSelf(callback: AsyncCallback&lt;void&gt;): void;
Terminates this ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;void&gt; | No| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.terminateSelf((err) => {
console.log('terminateSelf result:' + JSON.stringfy(err));
});
```
## ServiceExtensionContext.terminateSelf
terminateSelf(): Promise&lt;void&gt;;
Terminates this ability. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.terminateSelf(want).then((data) => {
console.log('success:' + JSON.stringfy(data));
}).catch((error) => {
console.log('failed:' + JSON.stringfy(error));
});
```
## ServiceExtensionContext.connectAbility
connectAbility(want: Want, options: ConnectOptions): number;
Connects this ability to a Service ability.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| want | [Want](js-apis-featureAbility.md#Want) | Yes| Information about the ability to connect to, such as the ability name and bundle name.|
| options | [ConnectOptions](#connectoptions) | Yes| Callback used to return the information indicating that the connection is successful, interrupted, or failed.|
**Return value**
| Type| Description|
| -------- | -------- |
| number | A number, based on which the connection will be interrupted.|
**Example**
```js
let want = {
"bundleName": "com.example.myapp",
"abilityName": "com.example.myapp.MyAbility"
};
let options = {
onConnect: function(elementName, proxy) {},
onDisConnect: function(elementName) {},
onFailed: function(code) {}
}
let connection = this.context.connectAbility(want,options);
```
## ServiceExtensionContext.disconnectAbility
disconnectAbility(connection: number, callback:AsyncCallback&lt;void&gt;): void;
Disconnects this ability from the Service ability. This API uses a callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| connection | number | Yes| Number returned after **connectAbility** is called.|
| callback | AsyncCallback&lt;void&gt; | No| Callback used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.disconnectAbility(connection, (err) => { // connection is the return value of connectAbility.
console.log('terminateSelf result:' + JSON.stringfy(err));
});
```
## ServiceExtensionContext.disconnectAbility
disconnectAbility(connection: number): Promise&lt;void&gt;;
Disconnects this ability from the Service ability. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| connection | number | Yes| Number returned after **connectAbility** is called.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result indicating whether the API is successfully called.|
**Example**
```js
this.context.disconnectAbility(connection).then((data) => { // connection is the return value of connectAbility.
console.log('success:' + JSON.stringfy(data));
}).catch((error) => {
console.log('failed:' + JSON.stringfy(error));
});
```
## ConnectOptions
Defines the **ConnectOptions** data structure.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name| Description|
| -------- | -------- |
| onConnect(elementName:ElementName,&nbsp;remote:IRemoteObject) | Called when this ability is connected to a Service ability.|
| onDisconnect(elementName:ElementName) | Called when the peer service is abnormal or killed.|
| onFailed(code:&nbsp;number) | Called when the connection fails.|
# uriPermissionManager
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
Implements URI permission management.
## Modules to Import
```
import uriPermissionManager from '@ohos.application.uriPermissionManager';
```
## uriPermissionManager.verifyUriPermission
verifyUriPermission(uri: string, flag: wantConstant.Flags, accessTokenId: number, callback: AsyncCallback&lt;number&gt;): void
Checks whether an application has the permission specified by **flag** for an URI. This API uses a callback to return the result.
**System capability**:
SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| uri | string | Yes| URI of a file, for example, **fileshare:///com.samples.filesharetest.FileShare/person/10**.|
| flag | wantConstant.Flags | Yes| Read or write permission on the file specified by the URI.|
| accessTokenId | number | Yes| Unique ID of an application, which is obtained through the **BundleManager** API.|
| callback | AsyncCallback&lt;number&gt; | Yes| Callback used to return the check result. The value **0** means that the application has the specified permission, and **-1** means the opposite.|
**Example**
```
let uri = "fileshare:///com.samples.filesharetest.FileShare/person/10"
UriPermissionManager.verifyUriPermission(uri, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION, accessTokenId, (result) => {
console.log("result.code = " + result.code)
}) // accessTokenId is obtained through the **BundleManager** API.
```
## uriPermissionManager.verifyUriPermission
verifyUriPermission(uri: string, flag: wantConstant.Flags, accessTokenId: number): Promise&lt;number&gt;
Checks whether an application has the permission specified by **flag** for an URI. This API uses a promise to return the result.
**System capability**:
SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| uri | string | Yes| URI of a file, for example, **fileshare:///com.samples.filesharetest.FileShare/person/10**.|
| flag | wantConstant.Flags | Yes| Read or write permission on the file specified by the URI.|
| accessTokenId | number | Yes| Unique ID of an application, which is obtained through the **BundleManager** API.|
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;number&gt; | Promise used to return the check result. The value **0** means that the application has the specified permission, and **-1** means the opposite.|
**Example**
```
let uri = "fileshare:///com.samples.filesharetest.FileShare/person/10"
UriPermissionManager.verifyUriPermission(uri, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION, accessTokenId)
.then((data) => {
console.log('Verification succeeded.' + data)
}).catch((error) => {
console.log('Verification failed.');
})
```
# Ability开发 # Ability开发
- [FA模型综述](fa-brief.md) - [Ability框架概述](ability-brief.md)
- [PageAbility开发指导](fa-pageability.md) - FA模型
- [ServiceAbility开发指导](fa-serviceability.md) - [FA模型综述](fa-brief.md)
- [DataAbility开发指导](fa-dataability.md) - [PageAbility开发指导](fa-pageability.md)
- [FA卡片开发指导](fa-formability.md) - [ServiceAbility开发指导](fa-serviceability.md)
- 其他 - [DataAbility开发指导](fa-dataability.md)
- [WantAgent开发指导](wantagent.md) - [FA卡片开发指导](fa-formability.md)
- [Ability助手使用指导](ability-assistant-guidelines.md) - Stage模型
- [测试框架使用指导](ability-delegator.md) - [Stage模型综述](stage-brief.md)
- [Ability开发指导](stage-ability.md)
- [ServiceExtensionAbility开发指导](stage-serviceextension.md)
- [跨端迁移开发指导](stage-ability-continuation.md)
- [Call调用开发指导](stage-call.md)
- [Stage卡片开发指导](stage-formextension.md)
- 其他
- [WantAgent开发指导](wantagent.md)
- [Ability助手使用指导](ability-assistant-guidelines.md)
- [测试框架使用指导](ability-delegator.md)
# Ability框架概述
​ Ability是应用所具备能力的抽象,也是应用程序的重要组成部分。Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件,一个应用可以包含一个或多个Ability。
​ Ability框架模型结构具有两种框架形态:
- 第一种形态为FA模型。API 8及其更早版本的应用程序只能使用FA模型进行开发。 FA模型将Ability分为FA(Feature Ability)和PA(Particle Ability)两种类型,其中FA支持Page Ability,PA支持Service Ability、Data Ability、以及FormAbility。
- 第二种形态为Stage模型。从API 9开始,Ability框架引入了Stage模型作为第二种应用框架形态,Stage模型将Ability分为Ability和ExtensionAbility两大类,其中ExtensionAbility又被扩展为ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility等等一系列ExtensionAbility,以便满足更多的使用场景。
​ Stage模型的设计,主要是为了方便开发者更加方便地开发出分布式环境下的复杂应用。下表给出了两种模型在设计上的差异:
| 对比 | FA模型 | Stage模型 |
| -------------- | ------------------------------------------------------------ | -------------------------------------------------------- |
| 开发方式 | 提供类Web的 api,UI开发与Stage模型一致。 | 提供面向对象的开发方式,UI开发与FA模型一致。 |
| 引擎实例 | 每个进程内的每个Ability独享一个JS VM引擎实例。 | 每个进程内的多个Ability实例共享一个JS VM引擎实例。 |
| 进程内对象共享 | 不支持。 | 支持。 |
| 包描述文件 | 使用config.json描述HAP包和组件信息,组件必须使用固定的文件名。 | 使用module.json描述HAP包和组件信息,可以指定入口文件名。 |
| 组件 | 提供PageAbility(页面展示),ServiceAbility(服务),DataAbility(数据分享), FormAbility(卡片)。 | 提供Ability(页面展示)、Extension(基于场景的服务扩展)。 |
​ 除了上述设计上的差异外,对于开发者而言,两种模型的主要区别在于:
* Ability类型存在差异;
![favsstage](figures/favsstage.png)
* Ability生命周期存在差异;
![lifecycle](figures/lifecycle.png)
两种模型的基本介绍,详见[FA模型综述](fa-brief.md)[Stage模型综述](stage-brief.md)
## 相关实例
针对Ability开发,有以下相关实例可供参考:
- [Page内和Page间导航跳转](https://gitee.com/openharmony/codelabs/tree/master/Ability/PageAbility)
\ No newline at end of file
...@@ -22,20 +22,23 @@ Delegator测试框架是OpenHarmony提供的一套开发者应用自测试框架 ...@@ -22,20 +22,23 @@ Delegator测试框架是OpenHarmony提供的一套开发者应用自测试框架
**FA模型:** **FA模型:**
```javascript ```javascript
aa test -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 aa test -b BundleName -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20
``` ```
**Stage模型:** **Stage模型:**
```javascript ```javascript
aa test -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 aa test -b BundleName -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20
``` ```
| 参数 | 是否必选 | 参数说明 | | 参数 | 是否必选 | 参数说明 |
| --------------- | -------- | ------------------------------------------------------------ | | --------------- | -------- | ------------------------------------------------------------ |
| -b | 是 | TestRunner所在hap包的bundle name。 |
| -p | 是 | TestRunner所在hap包的package name,FA模型使用。 | | -p | 是 | TestRunner所在hap包的package name,FA模型使用。 |
| -m | 是 | TestRunner所在hap包的module name,stage模型使用。 | | -m | 是 | TestRunner所在hap包的module name,Stage模型使用。 |
| -s unittest | 是 | 启用的TestRunner名称,TestRunner名称和文件名需要保持一致。 | | -s unittest | 是 | 启用的TestRunner名称,TestRunner名称和文件名需要保持一致。 |
| -w | 否 | 测试用例超时时间,单位为秒,如果未指定,测试框架会一直等待测试代码调用finishTest才退出。 | | -w | 否 | 测试用例超时时间,单位为秒,如果未指定或指定小于等于0的整数,测试框架会一直等待测试代码调用finishTest才退出。 |
| -s <key><value> | 否 | 支持以key-value的方式输入任何参数,输入的参数可通过AbilityDelegatorArgs.parameters以key-value的方式获取。示例:-s classname myTest,key为classname,value为myTest。 | | -s \<key>\<value> | 否 | 支持以key-value的方式输入任何参数,输入的参数可通过AbilityDelegatorArgs.parameters以key-value的方式获取。示例:-s classname myTest,key为"-s classname",value为"myTest"。 |
| -D | 否 | 以Debug模式启动被测试应用。 |
| -h | 否 | 输出帮助信息。 |
### IDE启动 ### IDE启动
...@@ -45,6 +48,14 @@ IDE启动相关介绍见 [IDE指导网址](https://developer.harmonyos.com/cn/do ...@@ -45,6 +48,14 @@ IDE启动相关介绍见 [IDE指导网址](https://developer.harmonyos.com/cn/do
TestRunner是测试框架测试流程入口类,当测试流程启动时,系统会调用TestRunner内相关接口,开发者需要派生该类,并重写onPrepare、onRun方法。IDE在创建应用模板时会初始化一个默认TestRunner,并在onRun方法启动默认的TestAbility。开发者也可以修改TestAbility测试代码内容,也可以修改默认的TestRunner内onPrepare、onRun方法,自行实现测试代码。具体详细内容请参考TestRunnerAPI接口说明[TestRunner](../reference/apis/js-apis-testRunner.md) TestRunner是测试框架测试流程入口类,当测试流程启动时,系统会调用TestRunner内相关接口,开发者需要派生该类,并重写onPrepare、onRun方法。IDE在创建应用模板时会初始化一个默认TestRunner,并在onRun方法启动默认的TestAbility。开发者也可以修改TestAbility测试代码内容,也可以修改默认的TestRunner内onPrepare、onRun方法,自行实现测试代码。具体详细内容请参考TestRunnerAPI接口说明[TestRunner](../reference/apis/js-apis-testRunner.md)
## AbilityDelegatorRegistry介绍
AbilityDelegatorRegistry是测试框架提供的AbilityDelegator仓库类,开发者可以使用AbilityDelegatorRegistry获取AbilityDelegator实例以及执行此次测试时传入和生成的相关参数AbilityDelegatorArgs。开发者可以使用AbilityDelegator调用测试框架提供的函数集进行测试验证。具体详细内容请参考AbilityDelegatorRegistry API接口说明[AbilityDelegatorRegistry](../reference/apis/js-apis-abilityDelegatorRegistry.md)
## AbilityDelegatorArgs介绍
AbilityDelegatorArgs是测试框架提供的测试参数类,开发者可以使用AbilityDelegatorArgs获取执行此次测试时传入和生成的相关参数。具体详细内容请参考AbilityDelegatorArgs API接口说明[AbilityDelegatorArgs](../reference/apis/js-apis-application-abilityDelegatorArgs.md)
## AbilityMonitor介绍 ## AbilityMonitor介绍
AbilityMonitor是测试框架提供用来绑定并监听Ability类,开发者可以使用AbilityMonitor绑定Ability,并将AbilityMonitor添加到监听列表。绑定后Ability的创建、生命周期变化等会触发AbilityMonitor内相关回调函数,开发者可以在对应回调函数内进行测试验证。具体详细内容请参考AbilityMonitor API接口说明[AbilityMonitor](../reference/apis/js-apis-application-abilityMonitor.md) AbilityMonitor是测试框架提供用来绑定并监听Ability类,开发者可以使用AbilityMonitor绑定Ability,并将AbilityMonitor添加到监听列表。绑定后Ability的创建、生命周期变化等会触发AbilityMonitor内相关回调函数,开发者可以在对应回调函数内进行测试验证。具体详细内容请参考AbilityMonitor API接口说明[AbilityMonitor](../reference/apis/js-apis-application-abilityMonitor.md)
...@@ -54,7 +65,7 @@ AbilityMonitor是测试框架提供用来绑定并监听Ability类,开发者 ...@@ -54,7 +65,7 @@ AbilityMonitor是测试框架提供用来绑定并监听Ability类,开发者
```javascript ```javascript
import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
function onAbilityCreateCallback() { function onAbilityCreateCallback(data) {
console.info("onAbilityCreateCallback"); console.info("onAbilityCreateCallback");
} }
...@@ -64,7 +75,7 @@ var monitor = { ...@@ -64,7 +75,7 @@ var monitor = {
} }
var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.addAbilityMonitor(monitor).then((void) => { abilityDelegator.addAbilityMonitor(monitor).then(() => {
console.info("addAbilityMonitor promise"); console.info("addAbilityMonitor promise");
}); });
``` ```
...@@ -94,7 +105,7 @@ var abilityDelegator; ...@@ -94,7 +105,7 @@ var abilityDelegator;
var ability; var ability;
var timeout = 100; var timeout = 100;
function onAbilityCreateCallback() { function onAbilityCreateCallback(data) {
console.info("onAbilityCreateCallback"); console.info("onAbilityCreateCallback");
} }
...@@ -113,8 +124,6 @@ var want = { ...@@ -113,8 +124,6 @@ var want = {
bundleName: "bundleName", bundleName: "bundleName",
abilityName: "abilityName" abilityName: "abilityName"
}; };
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => { abilityDelegator.startAbility(want, (err, data) => {
console.info("startAbility callback"); console.info("startAbility callback");
}); });
...@@ -122,7 +131,7 @@ abilityDelegator.startAbility(want, (err, data) => { ...@@ -122,7 +131,7 @@ abilityDelegator.startAbility(want, (err, data) => {
### 调度Ability生命周期 ### 调度Ability生命周期
AbilityDelegator提供对Ability生命周期进行显示调度,支持Foreground、Background,配合AbilityMonitor中对Ability生命周期监听方法,可以完整的测试Ability生命周期变化。具体详细内容请参考AbilityDelegator API接口说明[AbilityDelegator](../reference/apis/js-apis-application-abilityDelegator.md) AbilityDelegator提供对Ability生命周期进行显示调度的能力,支持Foreground、Background,配合AbilityMonitor中对Ability生命周期监听方法,可以完整的测试Ability生命周期变化。具体详细内容请参考AbilityDelegator API接口说明[AbilityDelegator](../reference/apis/js-apis-application-abilityDelegator.md)
### 执行shellCMD命令 ### 执行shellCMD命令
...@@ -130,10 +139,40 @@ AbilityDelegator提供执行shellCMD命令功能,开发者可以在测试代 ...@@ -130,10 +139,40 @@ AbilityDelegator提供执行shellCMD命令功能,开发者可以在测试代
**示例:** **示例:**
```javascript ```javascript
var abilityDelegator; var abilityDelegator;
var cmd = "cmd"; var cmd = "cmd";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.executeShellCommand(cmd, (err,data) => { abilityDelegator.executeShellCommand(cmd, (err, data) => {
console.info("executeShellCommand callback"); console.info("executeShellCommand callback");
}); });
```
### 打印日志信息
AbilityDelegator提供打印日志信息功能,开发者可以在测试代码中输出过程日志信息到终端控制台。
**示例:**
```javascript
var abilityDelegator;
var msg = "msg";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.print(msg, (err) => {
console.info("print callback");
});
```
### 结束测试并打印日志信息
AbilityDelegator提供主动结束测试的功能,开发者可以在测试代码中主动结束测试过程并输出日志码及信息到终端控制台。
**示例:**
```javascript
var abilityDelegator;
var msg = "msg";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.finishTest(msg, 0, (err) => {
console.info("finishTest callback");
});
``` ```
\ No newline at end of file
# 应用上下文使用指导
## Context概述
​ context是应用中对象的上下文,提供获取应用程序环境信息的能力。
## Context整体结构介绍
​ OpenHarmony的应用框架分为FA模型和Stage两种模型。对应存在两套Context机制适配两种应用框架模型:
**application/BaseContext** 属于一个通用的Context基类,既不属于FA模型也不属于Stage模型,里面只有一个属性stageMode,用来区分开发模型是FA还是Stage。
**FA模型** 只有app/Context中的方法属于FA模型对应的Context。该模式下,应用级别的Context和Ability级别的Context都是该类型的实例,如果在应用级别的Context里面调用了Ability级别的方法,会产生错误。所以开发者需要注意context实例所代表的实际含义。
**Stage模型** 除了app/Context之外的Context都属于Stage模型,分别有application/Context、application/AbilityStageContext、application/ExtensionContext、application/AbilityContext、application/FormExtensionContext和application/ServiceExtensionContext六种Context。这些Context的介绍及使用方式将会在[Stage模型和Context详细介绍](#stage模型和context详细介绍)种进行说明。
![contextIntroduction](figures/contextIntroduction.png)
## FA模型的Context详细介绍
​ 只有app/Context中的方法属于FA模型对应的Context。
​ FA模型只有一个Context定义。Context中所有的功能都是通过方法来提供的,它提供了一些featureAbility中不存在的方法,相当于featureAbility的一个扩展和补全。
​ d.ts文件如下:
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/app/context.d.ts
​ 应用的使用方式:
```javascript
// 1.引入featureAbility
import featureAbility from '@ohos.ability.featureAbility'
export default {
onCreate() {
console.log('Application onCreate')
// 2.获取Context
let context = featureAbility.getContext();
// 3.调用对应的方法
context.setShowOnLockScreen(false, (data) => {
console.log("data: " + JSON.stringify(data));
});
},
onActive() {
console.log('Application onActive')
},
onDestroy() {
console.log('Application onDestroy')
},
}
```
## Stage模型和Context详细介绍
​ Stage模型有6大Context:
### application/Context
**概述**
​ application/Context类型的Context是基类Context,里面提供了应用的一些基础信息:resourceManager、applicationInfo、cacheDir等,还有应用的一些基本方法:createBundleContext、switchArea等。应用级别的Context也是application/Context这种类型。
**获取方法**
​ 需要在AbilityStage、Ability、Extension等组件中通过context.getApplicationContext()拿到。
**示例**
```javascript
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('MainAbility onCreate is called' + want + launchParam);
// 获取ApplicationContext
let appContext = this.context.getApplicationContext();
// 获取路径
console.log('filesDir is ' + appContext.filesDir);
}
onDestroy() {
console.log('MainAbility onDestroy is called');
}
}
```
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/Context.d.ts
### application/AbilityStageContext
**概述**
​ application/AbilityStageContext是Hap包级别的Context。和基类Context相比,Hap包级别的Context中多了HapModuleInfo和Configuration两个信息。
**获取方法**
​ 可以直接在AbilityStage中通过context属性拿到。
**示例**
```javascript
export default class MyAbilityStage extends AbilityStage {
onCreate() {
// 属性context就是AbilityStageContext类型的
console.log('HapModuleInfo is ' + context.currentHapModuleInfo);
}
}
```
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityStageContext.d.ts
### application/AbilityContext
**概述**
​ Stage模型下,每个Ability中都包含了一个Context属性。
​ Ability功能主要是处理生命周期,其余操作Ability的方法(如startAbility、connectAbility等)都是在AbilityContext中实现的。
**获取方法**
​ 在Ability中通过context属性拿到。
**示例**
```javascript
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('MainAbility onCreate is called' + want + launchParam);
var want = {
"bundleName": "com.example.MyApplication",
"abilityName": "ServiceExtAbility",
}
// 1.这里的Context就是AbilityContext
let contxt = this.context;
// 2.startAbility
contxt.startAbility(want).then((data) => {
console.info("startAbility success:" + JSON.stringify(data));
}).catch((error) => {
console.error("startAbility failed:" + JSON.stringify(error));
});
}
onDestroy() {
console.log("MainAbility on Destroy is called");
}
}
```
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityContext.d.ts
### application/ExtensionContext
**概述**
​ 和FA模型不同的是,Stage模型把Service从Ability中剥离出来,单独定义了一组通用扩展类Extension用来处理等同的功能。Extension是一个基类,不承担具体业务功能。业务方根据自己的需要去扩展对应的Extension,例如:ServiceAbility扩展为了ServiceExtensionAbility,卡片扩展为了FormExtension。
​ 因此新增了一种和Extension匹配的ExtensionContext。ExtensionContext中包含HapModuleInfo和Configuration两个属性。
**获取方法**
​ 不会单独使用。
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ExtensionContext.d.ts
### application/ServiceExtensionContext
**概述**
​ ServiceExtensionAbility类似于FA模型的ServiceAbility,里面只有生命周期回调相关的处理。
​ 操作ServiceExtensionAbility的方法移动到了ServiceExtensionContext中(如startAbility、connectAbility等)。
**获取方法**
​ ServiceExtensionAbility中通过context属性获取。
**示例**
```javascript
export default class ServiceExtAbility extends ServiceExtensionAbility {
onCreate(want) {
console.info("ServiceAbility onCreate**");
// 1.这里的Context就是ServiceExtensionContext
let contxt = this.context;
}
onRequest(want, startId) {
console.info("ServiceAbility onRequest**");
}
onConnect(want) {
console.info("ServiceAbility onConnect**");
return new StubTest("test");
}
onDisconnect(want) {
console.info("ServiceAbility onDisconnect**");
}
onDestroy() {
console.info("ServiceAbility onDestroy**");
}
}
```
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ServiceExtensionContext.d.ts
### application/FormExtensionContext
[FormExtensionContext](/zh-cn/application-dev/reference/apis/js-apis-formextensioncontext.md)
**d.ts声明**
​ https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/FormExtensionContext.d.ts
## 常见问题
**通过globalThis去获取Context**
**结论**
​ FA模型可以通过该方式去获取;Stage模型不可通过该方式去获取,要通过对应组件的属性去获取。
**原因**
​ 应用框架在API8上推出了新的应用模型(Stage模型)。在老的模型(FA模型)下,每个Ability实例有一个js虚拟机实例,所以可以从js引擎的global对象上,获取到一个全局的Ability实例,但是在新的模型(Stage模型)下,整个应用进程共用一个js虚拟机实例,其中可以运行多个Ability实例,这样就不存在一个全局的Ability实例。如果开发者在新的模型(Stage模型)下,调用的API实现仍然走到了获取全局Ability实例的方法,就可能会发生错误或者崩溃。
\ No newline at end of file
# Ability综述 # FA模型综述
## 整体架构 ## 整体架构
OpenHarmony用户程序的开发本质上就是开发Ability。OpenHarmony系统是通过对Ability调度,结合系统提供的一致性调度契约对Ability进行生命周期管理,从而实现对用户程序的调度。 OpenHarmony用户程序的开发本质上就是开发Ability。OpenHarmony系统是通过对Ability调度,结合系统提供的一致性调度契约对Ability进行生命周期管理,从而实现对用户程序的调度。
...@@ -35,7 +35,6 @@ Ability框架在API 8及更早版本使用FA模型。FA模型中Ability分为Pag ...@@ -35,7 +35,6 @@ Ability框架在API 8及更早版本使用FA模型。FA模型中Ability分为Pag
![fa-threading-nodel](figures/fa-threading-model.png) ![fa-threading-nodel](figures/fa-threading-model.png)
## 相关实例 ## 相关实例
针对Ability开发,有以下相关实例可供参考: 针对Ability开发,有以下相关实例可供参考:
- [Page内和Page间导航跳转](https://gitee.com/openharmony/codelabs/tree/master/Ability/PageAbility)
- [分布式调度启动远程FA](https://gitee.com/openharmony/codelabs/tree/master/Distributed/RemoteStartFA) - [分布式调度启动远程FA](https://gitee.com/openharmony/codelabs/tree/master/Distributed/RemoteStartFA)
- [分布式新闻客户端](https://gitee.com/openharmony/codelabs/tree/master/Distributed/NewsDemo) - [分布式新闻客户端](https://gitee.com/openharmony/codelabs/tree/master/Distributed/NewsDemo)
- [分布式手写板(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/DistributeDatabaseDrawEts) - [分布式手写板(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/DistributeDatabaseDrawEts)
......
...@@ -231,7 +231,7 @@ Form需要在应用配置文件config.json中进行配置。 ...@@ -231,7 +231,7 @@ Form需要在应用配置文件config.json中进行配置。
} }
``` ```
具体的持久化方法可以参考[轻量级数据存储开发指导](../database/database-storage-guidelines.md) 具体的持久化方法可以参考[轻量级数据存储开发指导](../database/database-preference-guidelines.md)
需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片: 需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片:
......
...@@ -44,6 +44,7 @@ ability支持单实例和多实例两种启动模式。 ...@@ -44,6 +44,7 @@ ability支持单实例和多实例两种启动模式。
缺省情况下是singleton模式。 缺省情况下是singleton模式。
## 开发指导 ## 开发指导
### featureAbility接口说明 ### featureAbility接口说明
...@@ -80,7 +81,7 @@ ability支持单实例和多实例两种启动模式。 ...@@ -80,7 +81,7 @@ ability支持单实例和多实例两种启动模式。
authReadUriPermission: true, authReadUriPermission: true,
// Grant the permission to perform write operations on the URI. // Grant the permission to perform write operations on the URI.
authWriteUriPermission: true, authWriteUriPermission: true,
// support forwarding the intent result to the ability. // support forwarding the Want result to the ability.
abilityForwardResult: true, abilityForwardResult: true,
// Enable abiligy continuation. // Enable abiligy continuation.
abilityContinuation: true, abilityContinuation: true,
......
...@@ -399,4 +399,4 @@ export default { ...@@ -399,4 +399,4 @@ export default {
针对ServiceAbility开发,有以下相关实例可供参考: 针对ServiceAbility开发,有以下相关实例可供参考:
- [`ServiceAbility`:ServiceAbility的创建与使用(eTS)(API8)](https://gitee.com/openharmony/app_samples/tree/master/ability/ServiceAbility) - [`ServiceAbility`:ServiceAbility的创建与使用(eTS)(API8)](https://gitee.com/openharmony/app_samples/tree/master/ability/ServiceAbility)
- [`DMS`:分布式Demo(eTS)(API7)](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS) - [`DMS`:分布式Demo(eTS)(API7)](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS)
\ No newline at end of file
# 跨端迁移开发指导
## 场景介绍
迁移的主要工作是实现将应用当前任务,包括页面控件状态变量、分布式对象等,迁移到远端设备。页面控件状态变量用于同步页面UI数据,分布式对象用于同步内存中的数据。
## 接口说明
迁移提供的能力如下,具体的API详见[接口文档](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-application-ability.md)
**表1** 应用迁移API接口功能介绍
|接口名 | 描述|
|:------ | :------|
| onContinue(wantParam : {[key: string]: any}): OnContinueResult | 迁移**发起端**在该回调中保存迁移所需要的数据,同时返回是否同意迁移:0表示同意,拒绝返回相应错误码。 |
| onCreate(want: Want,param:LaunchParam): void | 迁移**目标端**在该回调中完成数据恢复,并触发页面恢复。 |
| **enum** OnContinueResult | onContinue的返回值类型:AGREE表示同意;REJECT表示拒绝;MISMATCH表示版本不匹配 |
**图1** 迁移开发示意图
![continuation_dev](figures/continuation-info.png)
## 开发步骤
### 迁移应用
1. 配置
- 配置应用支持迁移
在module.json5中配置continuable字段:true表示支持迁移,false表示不支持,默认为false。配置为false的应用将被系统识别为无法迁移。
```javascript
"continuable": true
```
* 配置应用启动类型
迁移当前只支持多实例应用,需要在在module.json5中配置launchType字段为standard。
```javascript
"launchType": "standard"
```
* 申请分布式权限
支持跨端迁移的应用需要在module.json5申请分布式权限 DISTRIBUTED_DATASYNC。
```javascript
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
```
这个权限需要在应用首次启动的时候弹窗让用户授予,可以通过在ability的onWindowStageCreate中添加如下代码实现:
```javascript
requestPermissions = async () => {
let permissions: Array<string> = [
"ohos.permission.DISTRIBUTED_DATASYNC"
];
let needGrantPermission = false
let accessManger = accessControl.createAtManager()
Logger.info("app permission get bundle info")
let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100)
Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`)
for (const permission of permissions) {
Logger.info(`app permission query grant status ${permission}`)
try {
let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission)
if (grantStatus === PERMISSION_REJECT) {
needGrantPermission = true
break;
}
} catch (err) {
Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`)
needGrantPermission = true
break;
}
}
if (needGrantPermission) {
Logger.info("app permission needGrantPermission")
try {
await this.context.requestPermissionsFromUser(permissions)
} catch (err) {
Logger.error(`app permission ${JSON.stringify(err)}`)
}
} else {
Logger.info("app permission already granted")
}
}
```
2. 实现onContinue接口
onContinue接口在**发起端**被调用,主要用于在迁移发起时,通知开发者保存控件状态变量和内存中数据,准备迁移。当应用准备完成后,需要返回OnContinueResult.AGREE(0)表示同意迁移,否则返回相应的错误码拒绝迁移。如果不实现该接口,系统将默认为拒绝迁移。
导入模块
```javascript
import Ability from '@ohos.application.Ability';
import AbilityConstant from '@ohos.application.AbilityConstant';
```
- 要实现迁移,此接口必须实现并返回AGREE,否则默认为拒绝迁移。
- 示例
```javascript
onContinue(wantParam : {[key: string]: any}) {
Logger.info("onContinue using distributedObject")
// set user input data into want params
wantParam["input"] = AppStorage.Get<string>('ContinueInput');
Logger.info(`onContinue input = ${wantParam["input"]}`);
return AbilityConstant.OnContinueResult.AGREE
}
```
3. 在onCreate接口中实现迁移逻辑
onCreate接口在迁移**目标端**被调用,在目标端ability被拉起时,通知开发者同步已保存的内存数据和控件状态,完成后触发页面的恢复。如果不实现该接口中迁移相关逻辑,ability将会作为普通的启动方式拉起,无法恢复页面。
- 远端设备上,在onCreate中根据launchReason判断该次启动是否为迁移LaunchReason.CONTINUATION
- 完成数据恢复后,开发者需要调用**restoreWindowStage**来触发页面恢复。
* 示例
```javascript
onCreate(want, launchParam) {
Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
globalThis.abilityWant = want;
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
let input = want.parameters.input // get user data from want params
AppStorage.SetOrCreate<string>('ContinueInput', input)
Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`)
this.contentStorage = new ContentStorage();
this.context.restoreWindowStage(this.contentStorage);
}
}
```
### 迁移数据
1. 使用分布式对象
分布式数据对象提供了与本地变量类似的操作,实现两个设备的数据同步,当设备1的应用A的分布式数据对象增、删、改数据后,设备2的应用A也可以获取到对应的数据变化,同时还能监听数据变更以及对端数据对象的上下线。用法详见[分布式对象指导文档](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/database/database-distributedobject-guidelines.md)
迁移场景中,分布式对象(distributedDataObject)主要用于将本机内存数据同步到目标设备。
- 发起端在onContinue中,将待迁移的数据存入分布式对象中,然后设置好session id,并通过wantParam将session id传到远端设备。
```javascript
import Ability from '@ohos.application.Ability';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({name:undefined});
export default class MainAbility extends Ability {
contentStorage : ContenStorage
sessionId : string;
onContinue(wantParam : {[key: string]: any}) {
Logger.info("onContinue using distributedObject")
this.sessionId = distributedObject.genSessionId();
//set distributed data object session id
g_object.setSessionId(this.sessionId);
g_object.name = "Amy";
// set session id into want params
wantParam["session"] = this.sessionId;
return AbilityConstant.OnContinueResult.AGREE
}
```
- 目标设备在onCreate中,取出发起端传过来的session id,建立分布式对象并关联该session id,这样就能实现分布式对象的同步。需要注意的是,在调用restoreWindowStage之前,迁移需要的分布式对象必须全部关联完,保证能够获取到正确的数据。
```javascript
import Ability from '@ohos.application.Ability';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({name:undefined});
export default class MainAbility extends Ability {
contentStorage : ContentStorage
sessionId : string;
statusCallback(sessionId, networkid, status) {
Logger.info(`continuation object status change, sessionId: ${sessionId}, status: ${status}, g_object.name: ${g_object.name}`)
}
onCreate(want, launchParam) {
Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
// get distributed data object session id from want params
this.sessionId = want.parameters.session
Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`)
g_object.on("status", this.statusCallback);
// set session id, so it will sync data from remote device
g_object.setSessionId(this.sessionId);
this.contentStorage = new ContentStorage();
this.context.restoreWindowStage(this.contentStorage);
}
}
}
```
以上完整的示例见sample
# Ability开发指导
## 场景介绍
Stage模型是基于API version 9的应用开发模型,对此模型的介绍详见[Stage模型综述](stage-brief.md)。基于Stage模型的Ability应用开发,主要涉及如下功能逻辑:
- 创建Page Ability应用,如视频播放、新闻资讯等,需要通过屏幕进行浏览的应用,以及支持人机交互。
- 获取Ability的配置信息,如ApplicationInfo、AbilityInfo及HapModuleInfo等。
- 启动/带参数启动/带返回结果启动/带AccountId启动其他Ability。
- 应用向用户申请授权。
- 系统环境变化通知给AbilityStage及Ability。
- 通用组件Call功能,详见[Call调用开发指导](stage-call.md)
- 连接ServiceExtensionAbility,与ServiceExtensionAbility断开连接,详见[ServiceExtensionAbility开发指导](stage-serviceextension.md)
- 应用迁移,详见[应用迁移开发指导](stage-ability-continuation.md)
### 启动模式
ability支持单实例、多实例和指定实例3种启动模式。
在module.json中通过launchType配置项,可以配置具体的启动模式,其中:
| 启动模式 | 描述 |说明 |
| ----------- | ------- |---------------- |
| standard | 多实例 | 每次startAbility都会启动一个新的实例 |
| singleton | 单实例 | 系统中只存在唯一一个实例,startAbility时,如果已存在,则复用系统中的唯一一个实例 |
| specified | 指定实例 | 运行时由ability内部业务决定是否创建多实例 |
缺省情况下是singleton模式。
## 接口说明
AbilityStage功能如下(AbilityStage类,拥有context属性,具体的API详见[接口文档](../reference/apis/js-apis-application-abilitystage.md)):
**表1** AbilityStage API接口功能介绍
|接口名|描述|
|:------|:------|
|void onCreate()|AbilityStage初始化时被调用。|
|string onAcceptWant(want: Want)|启动指定Ability时被调用。|
|void onConfigurationUpdated(config: Configuration)|全局配置发生变更时被调用。|
Ability功能如下(Ability类,具体的API详见[接口文档](../reference/apis/js-apis-application-ability.md)):
**表2** Ability API接口功能介绍
|接口名|描述|
|:------|:------|
|void onCreate(want: Want, param: AbilityConstant.LaunchParam)|Ability生命周期回调,Ability启动时被调用。|
|void onDestroy()|Ability生命周期回调,Ability销毁时被调用。|
|void onWindowStageCreate(windowStage: window.WindowStage)|Ability生命周期回调,创建window stage时被调用,应用开发者可通过window.WindowStage的接口执行页面加载等操作。|
|void onWindowStageDestroy()|Ability生命周期回调,销毁window stage时被调用。|
|void onForeground()|Ability生命周期回调,Ability切换至前台时被调用。|
|void onBackground()|Ability生命周期回调,Ability切换至后台时被调用。|
|void onNewWant(want: Want)|Ability回调,Ability的启动模式设置为单例时被调用。|
|void onConfigurationUpdated(config: Configuration)|Ability回调,Ability的系统配置更新时被调用。|
Ability类拥有context属性,context属性为AbilityContext类,AbilityContext类拥有abilityInfo、currentHapModuleInfo等属性,具体的API详见[接口文档](../reference/apis/js-apis-ability-context.md)
**表3** AbilityContext API接口功能介绍
|接口名|描述|
|:------|:------|
|void startAbility(want: Want, callback: AsyncCallback<void>)|启动Ability。|
|void startAbility(want: Want, options: StartOptions, callback: AsyncCallback<void>)|启动Ability。|
|void startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback<void>)|带AccountId启动Ability。|
|void startAbilityWithAccount(want: Want, accountId: number, options: StartOptions, callback: AsyncCallback<void>)|带AccountId启动Ability。|
|void startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>)|带返回结果启动Ability。|
|void startAbilityForResult(want: Want, options: StartOptions, callback: AsyncCallback<AbilityResult>)|带返回结果启动Ability。|
|void startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback<AbilityResult>)|带返回结果及AccountId启动Ability。|
|void startAbilityForResultWithAccount(want: Want, accountId: number, options: StartOptions, callback: AsyncCallback<void>)|带返回结果及AccountId启动Ability。|
|void terminateSelf(callback: AsyncCallback<void>)|销毁当前的Page Ability。|
|void terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>)|带返回结果销毁当前的Page Ability。|
## 开发步骤
### 创建Page Ability应用
创建Stage模型的Page Ability应用,需实现AbilityStage接口及Ability生命周期接口,并使用窗口提供的方法设置页面。具体示例代码如下:
1. 导入AbilityStage模块。
```
import AbilityStage from "@ohos.application.AbilityStage"
```
2. 实现AbilityStage接口。
```ts
export default class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage onCreate")
}
}
```
3. 导入Ability模块。
```js
import Ability from '@ohos.application.Ability'
```
4. 实现Ability生命周期接口。
`onWindowStageCreate(windowStage)`中通过loadContent接口设置应用要加载的页面,window接口的使用详见[窗口开发指导](../windowmanager/window-guidelines.md)
```ts
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
}
onDestroy() {
console.log("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.log("MainAbility onWindowStageCreate")
windowStage.loadContent("pages/index").then((data) => {
console.log("MainAbility load content succeed with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("MainAbility load content failed with error: "+ JSON.stringify(error))
})
}
onWindowStageDestroy() {
console.log("MainAbility onWindowStageDestroy")
}
onForeground() {
console.log("MainAbility onForeground")
}
onBackground() {
console.log("MainAbility onBackground")
}
}
```
### 获取AbilityStage及Ability的配置信息
AbilityStage类及Ability类均拥有context属性,应用可以通过`this.context`获取Ability实例的上下文,进而获取详细的配置信息。如下示例展示了AbilityStage通过context属性获取包代码路径、hap包名、ability名以及系统语言的方法。具体示例代码如下:
```ts
import AbilityStage from "@ohos.application.AbilityStage"
export default class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage onCreate")
let context = this.context
console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir)
let currentHapModuleInfo = context.currentHapModuleInfo
console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name)
console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName)
let config = this.context.config
console.log("MyAbilityStage config language" + config.language)
}
}
```
如下示例展示了Ability通过context属性获取包代码路径、hap包名、ability名以及系统语言的方法。具体示例代码如下:
```ts
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
let context = this.context
console.log("MainAbility bundleCodeDir" + context.bundleCodeDir)
let abilityInfo = this.context.abilityInfo;
console.log("MainAbility ability bundleName" + abilityInfo.bundleName)
console.log("MainAbility ability name" + abilityInfo.name)
let config = this.context.config
console.log("MyAbilityStage config language" + config.language)
}
}
```
### 启动Ability
应用可以通过`this.context`获取Ability实例的上下文,进而使用AbilityContext中的StartAbility相关接口启动Ability。启动Ability可指定Want、StartOptions、accountId,通过callback形式或promise形式实现。具体示例代码如下:
```ts
let context = this.context
var want = {
"deviceId": "",
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
};
var options = {
windowMode: 0,
displayId: 2
};
context.startAbility(want, options).then((data) => {
console.log("Succeed to start ability with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("Failed to start ability with error: "+ JSON.stringify(error))
})
```
### 跨设备启动Ability(当前仅对系统应用开放)
>说明:由于DeviceManager的getTrustedDeviceListSync接口仅对系统应用开放,当前跨设备启动Ability仅支持系统应用
跨设备场景下,需指定对端设备deviceId,具体示例代码如下:
```ts
let context = this.context
var want = {
"deviceId": getRemoteDeviceId(),
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
};
context.startAbility(want).then((data) => {
console.log("Succeed to start remote ability with data: " + JSON.stringify(data))
}).catch((error) => {
console.error("Failed to start remote ability with error: "+ JSON.stringify(error))
})
```
从DeviceManager获取指定设备的deviceId。具体示例代码如下:
```ts
import deviceManager from '@ohos.distributedHardware.deviceManager';
function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) {
var list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
### 应用向用户申请授权
应用需要某些权限如存储、位置信息、访问日历时,需要向用户申请授权。明确需要申请的权限后,在`module.json`中添加待申请的权限,同时通过接口`requestPermissionsFromUser`以动态弹窗的方式向用户申请授权。以访问日历为例,具体示例代码如下:
module.json的修改:
```json
"requestPermissions": [
{
"name": "ohos.permission.READ_CALENDAR"
}
]
```
通过动态弹窗向用户申请授权:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.READ_CALENDAR']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
在跨设备场景下,需要向用户申请数据同步的权限。具体示例代码如下:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
### 系统环境变化通知给AbilityStage及Ability
全局配置,比如系统语言和颜色模式发生变化时,通过`onConfigurationUpdated`接口通知给AbilityStage和Ability。系统应用可以通过`updateConfiguration`接口更新系统语言和颜色模式。如下示例展示了AbilityStage的`onConfigurationUpdated`回调实现,系统语言和颜色模式发生变化时触发该回调。具体示例代码如下:
```ts
import Ability from '@ohos.application.Ability'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
export default class MyAbilityStage extends AbilityStage {
onConfigurationUpdated(config) {
console.log("MyAbilityStage onConfigurationUpdated")
console.log("MyAbilityStage config language" + config.language)
console.log("MyAbilityStage config colorMode" + config.colorMode)
}
}
```
如下示例展示了Ability的`onConfigurationUpdated`回调实现,系统语言、颜色模式以及Display相关的参数,比如方向、Density,发生变化时触发该回调。具体示例代码如下:
```ts
import Ability from '@ohos.application.Ability'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
export default class MainAbility extends Ability { {
onConfigurationUpdated(config) {
console.log("MainAbility onConfigurationUpdated")
console.log("MainAbility config language" + config.language)
console.log("MainAbility config colorMode" + config.colorMode)
console.log("MainAbility config direction" + config.direction)
console.log("MainAbility config screenDensity" + config.screenDensity)
console.log("MainAbility config displayId" + config.displayId)
}
}
```
## 相关实例
针对Stage模型Ability开发,有以下相关示例可供参考:
- [`StageCallAbility`:StageAbility的创建与使用(eTS)(API9)](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
# Stage模型综述
### 设计思想
​ Stage模型的设计,主要是为了解决FA模型无法解决的开发场景问题,方便开发者更加方便地开发出分布式环境下的复杂应用。
​ Stage模型的设计思想如下图所示。
![stagedesign](figures/stagedesign.png)
​ Stage模型的设计基于如下三个出发点:
- **应用的能力与系统总体功能和功耗的平衡**
​ 在系统运行过程中,前台应用的资源占用会被优先保障,与此同时由于应用能力不同而产生的功耗,也需要符合系统整体功耗的要求。Stage模型通过Ability与UI分离、严格的后台管控、基于场景的服务机制及单进程模型来达成这种应用能力与整体系统功耗的平衡。
- **原生支持组件级的迁移和协同**
​ OpenHarmony是原生支持分布式的操作系统,应用框架需要从架构设计上使得组件更易于实现迁移和协同。Stage模型通过Ability与UI分离及UI展示与服务能力合一等模型特性,实现这一设计目标。
- **支持多设备和多窗口形态的特点**
​ 为了支持多种设备形态和更易于实现多种不同的窗口形态,需要组件管理服务和窗口管理服务在架构层面上是解耦的,从而方便裁剪,更有利于定制不同的窗口形态。Stage模型通过重新定义了Ability生命周期定义和设计组件管理服务和窗口管理服务的单向依赖解决这一问题。
### 基本概念
​ 下图展示了Stage模型中的基本概念。
![stageconcept](figures/stageconcept.png)
- **HAP**:即HarmonyAbilityPackage,OpenHarmony应用编译、分发、加载的基本单位,也称为module,每个HAP都有一个应用内唯一的名称,称为moduleName;
- **Bundle**:通过appid标识的OpenHarmony应用,Bundle可以包含多个HAP,每个应用都有一个bundleName,但是bundleName并不能唯一标识一个应用,appid中包含bundleName以及其他的更多信息,能够唯一标识一个应用;
- **AbilityStage**:对应HAP的运行期类,在HAP首次加载到进程中时创建,运行期开发者可见;
- **Application**:对应Bundle的运行期类,运行期开发者不可见;
- **Context**:提供运行期开发者可以调用的各种能力,Ability组件和各种ExtensionAbility都有各自不同的context类,他们都继承自基类Context,基类提供包名、moduleName、路径等信息;
- **Ability**:提供生命周期回调,持有AbilityContext,支持组件迁移/协同;
- **ExtensionAbility**:基于场景的服务扩展能力统称,系统定义了多种基于场景的ExtensionAbility类,它们持有各自的ExtensionContext;
- **WindowStage**:本地窗口管理器;
- **Window**:窗口 管理器管理的基本单元,持有一个ArkUI引擎实例;
- **Ark UI Page**:Ark声明式UI展示。
### 生命周期
​ Ability及AbilityStage的生命周期是应用的基本流程中最重要的概念。在[Ability框架概述](ability-brief.md)中,给出了FA模型与Stage模型的生命周期对比,这里重点对Ability生命周期切换以及和AbilityStage、WindowStage之间的调度关系进行介绍。
![stageabilitylifecyclecallback](figures/stageabilitylifecyclecallback.png)
​ 为了实现多设备形态上的裁剪和多窗口的可扩展性,OpenHarmony对组件管理和窗口管理进行了解耦。Stage模型定义Ability组件的生命周期,只包含创建、销毁、前后台等状态,而将与界面相关内容强相关的获焦、失焦状态放在WindowStage之中,从而实现Ability与窗口之间的弱耦合;在服务侧,窗口管理服务依赖于组件管理服务,前者通知后者前后台变化,这样组件管理服务仅感知前后台变化,不感知焦点变化。
### Ability组件实例与任务
​ Ability组件有三种启动类型:
+ **Singleton**:应用进程中只存在一个该类型的Ability实例,如下图Ability1;
+ **Standard**:每次startAbility调用,都会在应用进程中创建一个该类型的实例,如下图Ability2的两个实例;
+ **Specified**:允许开发者在系统创建AbilityRecord之前,为该实例创建一个key,后续每次创建该类型的Ability实例都会询问应用使用哪个key对应的Ability实例,来响应startAbility请求,如下图Ability3。
​ 每个Ability实例都对应了一个Launcher Recent中看到的Mission(任务)。
​ 每个Ability实例对应的Mission都留有该Ability实例的快照,Ability实例销毁后,Mission中的会保留Ability的类的信息和快照,直到用户删除,或者超过存储上限。
![AbilityComponentInstanceMission](figures/AbilityComponentInstanceMission.png)
### ExtensionAbility机制
​ 不同于用于页面展示的Ability,ExtensionAbility提供的是一种受限的服务运行环境。ExtensionAbility具有如下特点:
- 独立于主进程的单独进程运行,与主进程无IPC,共享一个存储沙箱;
- 独立的Context提供基于业务场景的api能力;
- 由系统触发创建,应用不能直接创建;
- ExtensionAbility和进程的生命周期受系统管理。
​ 下图以卡片服务使用场景为例进行展示,系统提供了FormExtensionAbility基类,开发者通过派生提供卡片的具体信息。FormExtensionAbility实例及其所在的ExtensionAbility进程的整个生命周期,都是由系统服务FormManagerService进行管理。
![ExtensionAbility](figures/ExtensionAbility.png)
### 进程模型
​ OpenHarmony系统中的应用均满足单进程模型。所谓的单进程模型,是指不允许应用配置多进程,应用中所有的进程都是由系统创建和管理的。每个应用至多并存三类进程:
- 主进程:运行所有的Ability组件、页面和业务逻辑;
- Extension进程:运行应用中的ExtensionAbility派生类,该进程由系统中的特定场景的服务管理其生命周期;
- Render进程:专门为webview创建的进程,用于加载webview的渲染库。
下图展示了应用的进程模型。
![stageprocessmodel](figures/stageprocessmodel.png)
# Call调用开发指导
## 场景介绍
Ability Call调用是Ability能力的扩展,它为Ability提供一种能够被外部调用的能力。使Ability既能被拉起到前台展示UI,也支持Ability在后台被创建并运行。应用开发者可通过Call调用,使用IPC通信实现不同Ability之间的数据共享。Call调用的场景主要包括:
- 创建Callee被调用端。
- 访问Callee被调用端。
本文中的Caller和Callee分别表示调用者和被调用者,Call调用流程示意图如下。
![stage-call](figures/stage-call.png)
## 接口说明
Caller及Callee功能如下:具体的API详见[接口文档](../reference/apis/js-apis-application-ability.md#caller)
**表1** Call API接口功能介绍
|接口名|描述|
|:------|:------|
|Promise<Caller> startAbilityByCall(want: Want)|获取指定通用组件的Caller通信接口,拉起指定通用组件并将其切换到后台。|
|void on(method: string, callback: CalleeCallBack)|Callee.on,通用组件Callee注册method对应的callback方法。|
|void off(method: string)|Callee.off,通用组件Callee去注册method的callback方法。|
|Promise<void> call(method: string, data: rpc.Sequenceable)|Caller.call,向通用组件Callee发送约定序列化数据。|
|Promise<rpc.MessageParcel> callWithResult(method: string, data: rpc.Sequenceable)|Caller.callWithResult,向通用组件Callee发送约定序列化数据, 并将返回的约定序列化数据带回。|
|void release()|Caller.release,释放通用组件的Caller通信接口。|
|void onRelease(callback: OnReleaseCallBack)|Caller.onRelease,注册通用组件通信断开监听通知。|
## 开发步骤
### 创建Callee被调用端
Callee被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。
1. 配置Ability的启动模式
配置module.json5,将Callee被调用端所在的Ability配置为单实例"singleton"。
|Json字段|字段说明|
|:------|:------|
|"launchType"|Ability的启动模式,设置为"singleton"类型 |
Ability配置标签示例如下:
```json
"abilities":[{
"name": ".CalleeAbility",
"srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"visible": true
}]
```
2. 导入Ability模块
```
import Ability from '@ohos.application.Ability'
```
3. 定义约定的序列化数据
调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。具体示例代码如下:
```ts
export default class MySequenceable {
num: number = 0
str: String = ""
constructor(num, string) {
this.num = num
this.str = string
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num)
messageParcel.writeString(this.str)
return true
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt()
this.str = messageParcel.readString()
return true
}
}
```
4. 实现Callee.on监听及Callee.off解除监听
被调用端Callee的监听函数注册时机, 取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在Ability的onCreate注册'CalleeSortMethod'监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下:
```ts
const TAG: string = '[CalleeAbility]'
const MSG_SEND_METHOD: string = 'CallSendMsg'
function sendMsgCallback(data) {
Logger.log(TAG, 'CalleeSortFunc called')
// 获取Caller发送的序列化数据
let receivedData = new MySequenceable(0, '')
data.readSequenceable(receivedData)
Logger.log(TAG, `receiveData[${receivedData.num}, ${receivedData.str}]`)
// 作相应处理
// 返回序列化数据result给Caller
return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`)
}
export default class CalleeAbility extends Ability {
onCreate(want, launchParam) {
try {
this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
} catch (error) {
Logger.error(TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
}
}
onDestroy() {
try {
this.callee.off(MSG_SEND_METHOD)
} catch (error) {
console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`)
}
}
}
```
### 访问Callee被调用端
1. 导入Ability模块
```
import Ability from '@ohos.application.Ability'
```
2. 获取Caller通信接口
Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过`this.context`获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease监听。应用开发者根据实际需要做相应处理。具体示例代码如下:
```ts
async onButtonGetCaller() {
try {
this.caller = await context.startAbilityByCall({
bundleName: 'com.samples.CallApplication',
abilityName: 'CalleeAbility'
})
if (this.caller === undefined) {
Logger.error(TAG, 'get caller failed')
return
}
Logger.log(TAG, 'get caller success')
this.regOnRelease(this.caller)
} catch (error) {
Logger.error(TAG, `get caller failed with ${error}`)
}
}.catch((error) => {
console.error(TAG + 'get caller failed with ' + error)
})
```
在跨设备场景下,需指定对端设备deviceId。具体示例代码如下:
```ts
let TAG = '[MainAbility] '
var caller = undefined
let context = this.context
context.startAbilityByCall({
deviceId: getRemoteDeviceId(),
bundleName: 'com.samples.CallApplication',
abilityName: 'CalleeAbility'
}).then((data) => {
if (data != null) {
caller = data
console.log(TAG + 'get remote caller success')
// 注册caller的release监听
caller.onRelease((msg) => {
console.log(TAG + 'remote caller onRelease is called ' + msg)
})
console.log(TAG + 'remote caller register OnRelease succeed')
}
}).catch((error) => {
console.error(TAG + 'get remote caller failed with ' + error)
})
```
从DeviceManager获取指定设备的deviceId,getTrustedDeviceListSync接口仅对系统应用开放。具体示例代码如下:
```ts
import deviceManager from '@ohos.distributedHardware.deviceManager';
var dmClass;
function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) {
var list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
在跨设备场景下,需要向用户申请数据同步的权限。具体示例代码如下:
```ts
let context = this.context
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
context.requestPermissionsFromUser(permissions).then((data) => {
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
}).catch((error) => {
console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
```
3. 发送约定序列化数据
向被调用端发送Sequenceable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。具体示例代码如下:
```ts
const MSG_SEND_METHOD: string = 'CallSendMsg'
async onButtonCall() {
try {
let msg = new MySequenceable(1, 'origin_Msg')
await this.caller.call(MSG_SEND_METHOD, msg)
} catch (error) {
Logger.error(TAG, `caller call failed with ${error}`)
}
}
```
如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据`originMsg`,并将'CallSendMsg'方法处理完毕的数据赋值给`backMsg`。具体示例代码如下:
```ts
const MSG_SEND_METHOD: string = 'CallSendMsg'
originMsg: string = ''
backMsg: string = ''
async onButtonCallWithResult(originMsg, backMsg) {
try {
let msg = new MySequenceable(1, originMsg)
const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg)
Logger.log(TAG, 'caller callWithResult succeed')
let result = new MySequenceable(0, '')
data.readSequenceable(result)
backMsg(result.str)
Logger.log(TAG, `caller result is [${result.num}, ${result.str}]`)
} catch (error) {
Logger.error(TAG, `caller callWithResult failed with ${error}`)
}
}
```
4. 释放Caller通信接口
Caller不再使用后,应用开发者可以通过release接口释放Caller。具体示例代码如下:
```ts
try {
this.caller.release()
this.caller = undefined
Logger.log(TAG, 'caller release succeed')
} catch (error) {
Logger.error(TAG, `caller release failed with ${error}`)
}
```
## 相关实例
针对Stage模型本地Call功能开发,有以下相关实例可供参考:
- [`StageCallAbility`:StageAbility的创建与使用(eTS)(API9)](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
# Stage卡片开发指导
## 卡片概述
卡片是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达,减少体验层级的目的。
卡片常用于嵌入到其他应用(当前只支持系统应用)中作为其界面的一部分显示,并支持拉起页面,发送消息等基础的交互功能。卡片使用方负责显示卡片。
卡片的基本概念:
- 卡片提供方
提供卡片显示内容原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。
- 卡片使用方
显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
- 卡片管理服务
用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 卡片使用方和提供方不要求常驻运行,在需要添加/删除/请求更新卡片时,卡片管理服务会拉起卡片提供方获取卡片信息。
开发者仅需作为卡片提供方进行卡片内容的开发,卡片使用方和卡片管理服务由系统自动处理。
卡片提供方控制卡片实际显示的内容、控件布局以及点击事件。
## 场景介绍
Stage卡片开发,即基于[Stage模型](stage-brief.md)的卡片提供方开发,主要涉及如下功能逻辑:
- 卡片生命周期回调函数FormExtension开发。
- 创建卡片数据FormBindingData对象。
- 通过FormProvider更新卡片。
- 卡片页面开发。
## 接口说明
FormExtension功能如下:FormExtension类,拥有context属性,具体的API详见[接口文档](../reference/apis/js-apis-formextension.md)
**表1** FormExtension API接口功能介绍
| 接口名 | 描述 |
| :----------------------------------------------------------- | :------------------------------------------- |
| onCreate(want: Want): formBindingData.FormBindingData | 卡片提供方接收创建卡片的通知接口。 |
| onCastToNormal(formId: string): void | 卡片提供方接收临时卡片转常态卡片的通知接口。 |
| onUpdate(formId: string): void | 卡片提供方接收更新卡片的通知接口。 |
| onVisibilityChange(newStatus: { [key: string]: number }): void | 卡片提供方接收修改可见性的通知接口。 |
| onEvent(formId: string, message: string): void | 卡片提供方接收处理卡片事件的通知接口。 |
| onDestroy(formId: string): void | 卡片提供方接收销毁卡片的通知接口。 |
| onConfigurationUpdated(config: Configuration): void; | 当系统配置更新时调用。 |
FormExtension类拥有context属性,context属性为FormExtensionContext类,具体的API详见[接口文档](../reference/apis/js-apis-formextensioncontext.md)
**表2** FormExtensionContext API接口功能介绍
| 接口名 | 描述 |
| :----------------------------------------------------------- | :------------------------ |
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback\<void>): void | 回调形式主动更新卡片。 |
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise\<void> | Promise形式主动更新卡片。 |
FormProvider类具体的API详见[接口文档](../reference/apis/js-apis-formprovider.md)
**表3** FormProvider API接口功能介绍
| 接口名 | 描述 |
| :----------------------------------------------------------- | :------------------------------------------------ |
| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback&lt;void&gt;): void; | 设置指定卡片的下一次更新时间。 |
| setFormNextRefreshTime(formId: string, minute: number): Promise&lt;void&gt;; | 设置指定卡片的下一次更新时间,以promise方式返回。 |
| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback&lt;void&gt;): void; | 更新指定的卡片。 |
| updateForm(formId: string, formBindingData: FormBindingData): Promise&lt;void&gt;; | 更新指定的卡片,以promise方式返回。 |
## 开发步骤
### 创建卡片FormExtension
创建Stage模型的卡片,需实现FormExtension生命周期接口。具体示例代码如下:
1. 导入相关模块
```javascript
import FormExtension from '@ohos.application.FormExtension'
import formBindingData from '@ohos.application.formBindingData'
import formInfo from '@ohos.application.formInfo'
import formProvider from '@ohos.application.formProvider'
```
2. 实现FormExtension生命周期接口
```javascript
export default class FormAbility extends FormExtension {
onCreate(want) {
console.log('FormAbility onCreate');
// 由开发人员自行实现,将创建的卡片信息持久化,以便在下次获取/更新该卡片实例时进行使用
let obj = {
"title": "titleOnCreate",
"detail": "detailOnCreate"
};
let formData = formBindingData.createFormBindingData(obj);
return formData;
}
onCastToNormal(formId) {
// 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理
console.log('FormAbility onCastToNormal');
}
onUpdate(formId) {
// 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要覆写该方法以支持数据更新
console.log('FormAbility onUpdate');
let obj = {
"title": "titleOnUpdate",
"detail": "detailOnUpdate"
};
let formData = formBindingData.createFormBindingData(obj);
formProvider.updateForm(formId, formData).catch((error) => {
console.log('FormAbility updateForm, error:' + JSON.stringify(error));
});
}
onVisibilityChange(newStatus) {
// 使用方发起可见或者不可见通知触发,提供方需要做相应的处理
console.log('FormAbility onVisibilityChange');
}
onEvent(formId, message) {
// 若卡片支持触发事件,则需要覆写该方法并实现对事件的触发
console.log('FormAbility onEvent');
}
onDestroy(formId) {
// 删除卡片实例数据
console.log('FormAbility onDestroy');
}
onConfigurationUpdated(config) {
console.log('FormAbility onConfigurationUpdated, config:' + JSON.stringify(config));
}
}
```
### 配置卡片配置文件
Form需要在应用配置文件module.json中进行配置。
- extensionAbility模块,内部字段结构说明:
| 属性名称 | 含义 | 数据类型 | 是否可缺省 |
| ----------- | ------------------------------------------------------------ | ---------- | -------------------- |
| name | 表示extensionAbility的名字。该标签不可缺省。 | 字符串 | 否 |
| srcEntrance | 表示extensionAbility所对应的JS的代码路径。该标签不可缺省。 | 字符串 | 否 |
| description | 表示extensionAbility的描述。可以是表示描述内容的字符串,也可以是对描述内容的资源索引以支持多语言。 | 字符串 | 可缺省,缺省值为空。 |
| icon | 表示extensionAbility的图标资源文件的索引。 | 字符串 | 可缺省,缺省值为空。 |
| label | 表示extensionAbility的标签信息,即extensionAbility对外显示的文字描述信息。取值可以是描述性内容,也可以是标识label的资源索引。 | 字符串 | 可缺省,缺省值为空。 |
| type | 表示extensionAbility的类型。取值form、service等 | 字符串 | 否 |
| permissions | 表示其他应用的Ability调用此Ability时需要申请的权限。 | 字符串数组 | 可缺省,缺省值为空。 |
| metadata | 表示extensionAbility的元信息。用于描述extensionAbility的配置信息。 | 对象 | 可缺省,缺省值为空 |
对于FormExtensionAbility来说,type需要配置为form,并且需要填写metadata元信息,用于配置卡片的具体信息。
配置示例如下:
```json
"extensionAbilities": [{
"name": "FormAbility",
"srcEntrance": "./ets/FormAbility/FormAbility.ts",
"label": "$string:form_FormAbility_label",
"description": "$string:form_FormAbility_desc",
"type": "form",
"metadata": [{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}]
}]
```
- 卡片profile模块。在 FormExtensionAbility 的元信息中,需要使用 ohos.extension.form 指定的资源文件的路径,如使用 $profile:form_config 指定开发视图的 resources/base/profile/ 目录下的 form_config.json 作为卡片profile配置文件。
内部字段结构说明:
| 属性名称 | 含义 | 数据类型 | 是否可缺省 |
| ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ |
| name | 表示卡片的类名。字符串最大长度为127字节。 | 字符串 | 否 |
| description | 表示卡片的描述。取值可以是描述性内容,也可以是对描述性内容的资源索引,以支持多语言。字符串最大长度为255字节。 | 字符串 | 可缺省,缺省为空。 |
| src | 表示卡片对应的UI代码的完整路径。 | 字符串 | 否 |
| window | 用于定义与显示窗口相关的配置。 | 对象 | 可缺省 |
| isDefault | 表示该卡片是否为默认卡片,每个Ability有且只有一个默认卡片。<br />true:默认卡片。<br />false:非默认卡片。 | 布尔值 | 否 |
| colorMode | 表示卡片的主题样式,取值范围如下:<br />auto:自适应。<br />dark:深色主题。<br />light:浅色主题。 | 字符串 | 可缺省,缺省值为“auto”。 |
| supportDimensions | 表示卡片支持的外观规格,取值范围:<br />1 * 2:表示1行2列的二宫格。<br />2 * 2:表示2行2列的四宫格。<br />2 * 4:表示2行4列的八宫格。<br />4 * 4:表示4行4列的十六宫格。 | 字符串数组 | 否 |
| defaultDimension | 表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。 | 字符串 | 否 |
| updateEnabled | 表示卡片是否支持周期性刷新,取值范围:<br />true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。<br />false:表示不支持周期性刷新。 | 布尔类型 | 否 |
| scheduledUpdateTime | 表示卡片的定点刷新的时刻,采用24小时制,精确到分钟。 | 字符串 | 可缺省,缺省值为“0:0”。 |
| updateDuration | 表示卡片定时刷新的更新周期,单位为30分钟,取值为自然数。<br />当取值为0时,表示该参数不生效。<br />当取值为正整数N时,表示刷新周期为30*N分钟。 | 数值 | 可缺省,缺省值为“0”。 |
| formConfigAbility | 表示卡片的配置跳转链接,采用URI格式。 | 字符串 | 可缺省,缺省值为空。 |
| formVisibleNotify | 标识是否允许卡片使用卡片可见性通知 | 字符串 | 可缺省,缺省值为空。 |
| metaData | 表示卡片的自定义信息,包含customizeData数组标签。 | 对象 | 可缺省,缺省值为空。 |
配置示例如下:
```json
{
"forms": [{
"name": "widget",
"description": "This is a service widget.",
"src": "./js/widget/pages/index/index",
"window": {
"autoDesignWidth": true,
"designWidth": 720
},
"isDefault": true,
"colorMode": "auto",
"supportDimensions": ["2*2"],
"defaultDimension": "2*2",
"updateEnabled": true,
"scheduledUpdateTime": "10:30",
"updateDuration": 1,
"formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility"
}]
}
```
### 卡片信息的持久化
因大部分卡片提供方都不是常驻服务,只有在需要使用时才会被拉起获取卡片信息,且卡片管理服务支持对卡片进行多实例管理,卡片ID对应实例ID,因此若卡片提供方支持对卡片数据进行配置,则需要对卡片的业务数据按照卡片ID进行持久化管理,以便在后续获取、更新以及拉起时能获取到正确的卡片业务数据。
```javascript
onCreate(want) {
console.log('FormAbility onCreate');
let formId = want.parameters["ohos.extra.param.key.form_identity"];
let formName = want.parameters["ohos.extra.param.key.form_name"];
let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];
// 由开发人员自行实现,将创建的卡片信息持久化,以便在下次获取/更新该卡片实例时进行使用
storeFormInfo(formId, formName, tempFlag, want);
let obj = {
"title": "titleOnCreate",
"detail": "detailOnCreate"
};
let formData = formBindingData.createFormBindingData(obj);
return formData;
}
```
且需要适配onDestroy卡片删除通知接口,在其中实现卡片实例数据的删除。
```javascript
onDestroy(formId) {
// 删除卡片实例数据
deleteFormInfo(formId);
console.log('FormAbility onDestroy');
}
```
具体的持久化方法可以参考[轻量级数据存储开发指导](../database/database-preference-guidelines.md)。
需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片:
常态卡片:卡片使用方会持久化的卡片;
临时卡片:卡片使用方不会持久化的卡片;
由于临时卡片的数据具有非持久化的特殊性,某些场景比如卡片服务框架死亡重启,此时临时卡片数据在卡片管理服务中已经删除,且对应的卡片ID不会通知到提供方,所以卡片提供方需要自己负责清理长时间未删除的临时卡片数据。同时对应的卡片使用方可能会将之前请求的临时卡片转换为常态卡片。如果转换成功,卡片提供方也需要对对应的临时卡片ID进行处理,把卡片提供方记录的临时卡片数据转换为常态卡片数据,防止提供方在清理长时间未删除的临时卡片时,把已经转换为常态卡片的临时卡片信息删除,导致卡片信息丢失。
### 开发卡片页面
开发者可以使用hml+css+json开发JS卡片页面:
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 当前仅支持JS扩展的类Web开发范式来实现卡片的UI页面。
- hml:
```html
<div class="container">
<stack>
<div class="container-img">
<image src="/common/widget.png" class="bg-img"></image>
</div>
<div class="container-inner">
<text class="title">{{title}}</text>
<text class="detail_text" onclick="routerEvent">{{detail}}</text>
</div>
</stack>
</div>
```
- css:
```css
.container {
flex-direction: column;
justify-content: center;
align-items: center;
}
.bg-img {
flex-shrink: 0;
height: 100%;
}
.container-inner {
flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
height: 100%;
width: 100%;
padding: 12px;
}
.title {
font-size: 19px;
font-weight: bold;
color: white;
text-overflow: ellipsis;
max-lines: 1;
}
.detail_text {
font-size: 16px;
color: white;
opacity: 0.66;
text-overflow: ellipsis;
max-lines: 1;
margin-top: 6px;
}
```
- json:
```json
{
"data": {
"title": "TitleDefault",
"detail": "TextDefault"
},
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.MyApplication.hmservice.FormAbility",
"params": {
"message": "add detail"
}
}
}
}
```
最终可以得到,如下卡片:
![fa-form-example](figures/fa-form-example.png)
## 相关实例
针对Stage模型卡片提供方的开发,有以下相关实例可供参考:
- [`FormExtAbility`:Stage模型卡片(eTS JS)(API9)](https://gitee.com/openharmony/app_samples/tree/master/ability/FormExtAbility)
\ No newline at end of file
# ServiceExtensionAbility开发指导
## 场景介绍
ExtensionAbility,是Stage模型中新增的扩展组件的基类,一般用于处理无界面的任务,生命周期较简单,没有前后台生命周期。ServiceExtensionAbility是ExtensionAbility的扩展类。
开发者可以自定义类继承ServiceExtensionAbility,通过重写基类中相关生命周期方法,来做初始化、连接中、断开连接时相关业务逻辑操作。
## 接口说明
**表1** ServiceExtensionAbility中相关生命周期功能介绍
|接口名|描述|
|:------|:------|
|onCreate|首次调用startAbility、connectAbility时触发,开发者可以进行初始化操作。|
|onRequest|每次调用startAbility都会触发,首次调用时startId为1,重复调用startAbility递增。|
|onConnect|调用connectAbility触发,重复调用不会再次触发,除非调用disconnectAbility解除绑定后再调用;onConnect返回一个进程通信类RemoteObject。|
|onDisconnect|调用disconnectAbility触发,Extension如果是用connectAbility拉起的,并且已经没有其他应用绑定这个Extension,则会触发onDestroy生命周期销毁组件。|
|onDestroy|调用停止当前ability接口terminateSelf会触发。|
## 约束与限制
- OpenHarmony当前不支持三方应用创建ServiceExtensionAbility。
## 开发步骤
1.创建ServiceExtensionAbility
开发者在创建TS文件中自定义类继承ServiceExtensionAbility,重写基类回调函数,示例如下:
```js
import rpc from '@ohos.rpc'
class StubTest extends rpc.RemoteObject {
constructor(des) {
super(des);
}
onRemoteRequest(code, data, reply, option) {
}
}
class ServiceExt extends ServiceExtensionAbility {
onCreate(want) {
console.log('onCreate, want:' + want.abilityName);
}
onRequest(want, startId) {
console.log('onRequest, want:' + want.abilityName);
}
onConnect(want) {
console.log('onConnect , want:' + want.abilityName);
return new StubTest("test");
}
onDisconnect(want) {
console.log('onDisconnect, want:' + want.abilityName);
}
onDestroy() {
console.log('onDestroy');
}
}
```
2.注册ServiceExtensionAbility
需要在应用配置文件module.json中进行注册,注册类型type需要设置为service。
**module.json配置样例**
```json
"extensionAbilities":[{
"name": "ServiceExtAbility",
"icon": "$media:icon",
"description": "service",
"type": "service",
"visible": true,
"srcEntrance": "./ets/ServiceExtAbility/ServiceExtAbility.ts"
}]
```
## 相关实例
针对ServiceExtensionAbility开发,有以下相关实例可供参考:
- [`ServiceExtAbility`:StageAbility的创建与使用(eTS)(API9)](https://gitee.com/openharmony/app_samples/tree/master/ability/ServiceExtAbility)
...@@ -14,15 +14,22 @@ ...@@ -14,15 +14,22 @@
- [SysCap说明](quick-start/syscap.md) - [SysCap说明](quick-start/syscap.md)
- 开发 - 开发
- Ability开发 - Ability开发
- [FA模型综述](ability/fa-brief.md) - [Ability框架概述](ability/ability-brief.md)
- [PageAbility开发指导](ability/fa-pageability.md) - FA模型
- [ServiceAbility开发指导](ability/fa-serviceability.md) - [FA模型综述](ability/fa-brief.md)
- [DataAbility开发指导](ability/fa-dataability.md) - [PageAbility开发指导](ability/fa-pageability.md)
- [FA卡片开发指导](ability/fa-formability.md) - [ServiceAbility开发指导](ability/fa-serviceability.md)
- [DataAbility开发指导](ability/fa-dataability.md)
- [FormAbility开发指导](ability/fa-formability.md)
- Stage模型
- [Stage模型综述](ability/stage-brief.md)
- [Ability开发指导](ability/stage-ability.md)
- [ServiceExtensionAbility开发指导](ability/stage-serviceextension.md)
- [FormExtensionAbility开发指导](ability/stage-formextension.md)
- [应用迁移开发指导](ability/stage-ability-continuation.md)
- 其他 - 其他
- [WantAgent使用指导](ability/wantagent.md) - [WantAgent使用指导](ability/wantagent.md)
- [Ability助手使用指导](ability/ability-assistant-guidelines.md) - [Ability助手使用指导](ability/ability-assistant-guidelines.md)
- [测试框架使用指导](ability-delegator.md)
- UI开发 - UI开发
- [方舟开发框架(ArkUI)概述](ui/arkui-overview.md) - [方舟开发框架(ArkUI)概述](ui/arkui-overview.md)
- 基于JS扩展的类Web开发范式 - 基于JS扩展的类Web开发范式
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册