提交 66d37350 编写于 作者: L LeiiYB 提交者: leiiyb

Merge branch 'master' of gitee.com:openharmony/docs into master

Signed-off-by: NLeiiYB <leiyanbo@huawei.com>

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
......@@ -426,7 +426,7 @@ zh-cn/application-dev/reference/apis/js-apis-socket.md @zhang-hai-feng @zengyawe
zh-cn/application-dev/reference/apis/js-apis-stack.md @gongjunsong @ge-yafang @flyingwolf @BlackStone
zh-cn/application-dev/reference/apis/js-apis-statfs.md @panqinxu @zengyawen @bubble_mao @jinhaihw
zh-cn/application-dev/reference/apis/js-apis-storage-statistics.md @panqinxu @zengyawen @bubble_mao @jinhaihw
zh-cn/application-dev/reference/apis/js-apis-system-app.md @shuaytao @RayShih @wangzhen107 @inter515
zh-cn/application-dev/reference/apis/js-apis-system-app.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy
zh-cn/application-dev/reference/apis/js-apis-system-battery.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-system-bluetooth.md @cheng_guohong @RayShih @cheng_guohong @quanli125
zh-cn/application-dev/reference/apis/js-apis-system-brightness.md @aqxyjay @zengyawen @aqxyjay @alien0208
......
......@@ -2,52 +2,87 @@
- [Application Development Overview](application-dev-guide.md)
- About OpenHarmony
- [OpenHarmony Project](../OpenHarmony-Overview.md)
- [Glossary](../glossary.md)
- [OpenHarmony Release Notes](../release-notes/Readme.md)
- [OpenHarmony Project](../OpenHarmony-Overview.md)
- [Glossary](../glossary.md)
- [OpenHarmony Release Notes](../release-notes/Readme.md)
- Quick Start
- Getting Started
- [Preparations](quick-start/start-overview.md)
- [Getting Started with ArkTS in Stage Model](quick-start/start-with-ets-stage.md)
- [Getting Started with ArkTS in FA Model](quick-start/start-with-ets-fa.md)
- [Getting Started with JavaScript in FA Model](quick-start/start-with-js-fa.md)
- Development Fundamentals
- [Application Package Structure Configuration File (FA Model)](quick-start/package-structure.md)
- [Application Package Structure Configuration File (Stage Model)](quick-start/stage-structure.md)
- [SysCap](quick-start/syscap.md)
- Getting Started
- [Before You Start](quick-start/start-overview.md)
- [Getting Started with ArkTS in Stage Model](quick-start/start-with-ets-stage.md)
- [Getting Started with ArkTS in FA Model](quick-start/start-with-ets-fa.md)
- [Getting Started with JavaScript in FA Model](quick-start/start-with-js-fa.md)
- Development Fundamentals
- Application Package Fundamentals
- [Application Package Overview](quick-start/application-package-overview.md)
- Application Package Structure
- [Application Package Structure in Stage Model)](quick-start/application-package-structure-stage.md)
- [Application Package Structure in FA Model](quick-start/application-package-structure-fa.md)
- [HAR File Structure](quick-start/har-structure.md)
- Multi-HAP Mechanism
- [Multi-HAP Design Objectives](quick-start/multi-hap-objective.md)
- [Multi-HAP Build View](quick-start/multi-hap-build-view.md)
- [Multi-HAP Development, Debugging, Release, and Deployment Process](quick-start/multi-hap-release-deployment.md)
- [Multi-HAP Usage Rules](quick-start/multi-hap-rules.md)
- [Multi-HAP Operation Mechanism and Data Communication Modes](quick-start/multi-hap-principles.md)
- [Application Installation and Uninstallation Process](quick-start/application-package-install-uninstall.md)
- Application Configuration Files in Stage Model
- [Application Configuration File Overview (Stage Model)](quick-start/application-configuration-file-overview-stage.md)
- [app.json5 Configuration File](quick-start/app-configuration-file.md)
- [module.json5 Configuration File](quick-start/module-configuration-file.md)
- Application Configuration Files in FA Model
- [Application Configuration File Overview (FA Model)](quick-start/application-configuration-file-overview-fa.md)
- [Internal Structure of the app Tag](quick-start/app-structure.md)
- [Internal structure of deviceConfig Tag](quick-start/deviceconfig-structure.md)
- [Internal Structure of the module Tag](quick-start/module-structure.md)
- [Resource Categories and Access](quick-start/resource-categories-and-access.md)
- Learning ArkTS
- [Getting Started with ArkTS](quick-start/arkts-get-started.md)
- ArkTS Syntax (Declarative UI)
- [Basic UI Description](quick-start/arkts-basic-ui-description.md)
- State Management
- [Basic Concepts](quick-start/arkts-state-mgmt-concepts.md)
- [State Management with Page-level Variables](quick-start/arkts-state-mgmt-page-level.md)
- [State Management with Application-level Variables](quick-start/arkts-state-mgmt-application-level.md)
- [Dynamic UI Element Building](quick-start/arkts-dynamic-ui-elememt-building.md)
- [Rendering Control](quick-start/arkts-rendering-control.md)
- [Restrictions and Extensions](quick-start/arkts-restrictions-and-extensions.md)
- Development
- [Ability Development](ability/Readme-EN.md)
- [UI Development](ui/Readme-EN.md)
- [Common Event and Notification](notification/Readme-EN.md)
- [Window Manager](windowmanager/Readme-EN.md)
- [WebGL](webgl/Readme-EN.md)
- [Media](media/Readme-EN.md)
- [Security](security/Readme-EN.md)
- [Connectivity](connectivity/Readme-EN.md)
- [Data Management](database/Readme-EN.md)
- [File Management](file-management/Readme-EN.md)
- [Telephony](telephony/Readme-EN.md)
- [Task Management](task-management/Readme-EN.md)
- [Device Management](device/Readme-EN.md)
- [Device Usage Statistics](device-usage-statistics/Readme-EN.md)
- [DFX](dfx/Readme-EN.md)
- [Internationalization](internationalization/Readme-EN.md)
- [OpenHarmony IDL Specifications and User Guide](IDL/idl-guidelines.md)
- [Using Native APIs in Application Projects](napi/Readme-EN.md)
- [Application Models](application-models/Readme-EN.md)
- [UI Development](ui/Readme-EN.md)
- [Common Event and Notification](notification/Readme-EN.md)
- [Window Manager](windowmanager/Readme-EN.md)
- [WebGL](webgl/Readme-EN.md)
- [Media](media/Readme-EN.md)
- [Security](security/Readme-EN.md)
- [Connectivity](connectivity/Readme-EN.md)
- [Data Management](database/Readme-EN.md)
- [File Management](file-management/Readme-EN.md)
- [Telephony](telephony/Readme-EN.md)
- [Task Management](task-management/Readme-EN.md)
- [Device Management](device/Readme-EN.md)
- [Device Usage Statistics](device-usage-statistics/Readme-EN.md)
- [DFX](dfx/Readme-EN.md)
- [Internationalization](internationalization/Readme-EN.md)
- [Application Test](application-test/Readme-EN.md)
- [OpenHarmony IDL Specifications and User Guide](IDL/idl-guidelines.md)
- [Using Native APIs in Application Projects](napi/Readme-EN.md)
- Tools
- [DevEco Studio (OpenHarmony) User Guide](quick-start/deveco-studio-user-guide-for-openharmony.md)
- Hands-On Tutorials
- [Samples](https://gitee.com/openharmony/applications_app_samples/blob/master/README.md)
- [Codelabs](https://gitee.com/openharmony/codelabs)
- API References
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md)
- [Component Reference (TypeScript-based Declarative Development Paradigm)](reference/arkui-ts/Readme-EN.md)
- APIs
- [JS and TS APIs](reference/apis/Readme-EN.md)
- Native APIs
- [Standard Libraries](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md)
- [SystemCapability](reference/syscap.md)
- [SystemCapability List](reference/syscap-list.md)
- [Component Reference (TypeScript-based Declarative Development Paradigm)](reference/arkui-ts/Readme-EN.md)
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md)
- [JS Service Widget UI Components](reference/js-service-widget-ui/Readme-EN.md)
- APIs
- [ArkTS and JS APIs](reference/apis/Readme-EN.md)
- [Error Codes](reference/errorcodes/Readme-EN.md)
- Native APIs
- [Standard Libraries](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md)
- [FAQs](faqs/Readme-EN.md)
- Contribution
- [How to Contribute](../contribute/documentation-contribution.md)
- [How to Contribute](../contribute/documentation-contribution.md)
......@@ -63,7 +63,7 @@ For details about how to use DevEco Studio to start the test framework, see [Ope
**Example**
```javascript
import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
function onAbilityCreateCallback(data) {
console.info("onAbilityCreateCallback");
......@@ -87,11 +87,11 @@ abilityDelegator.addAbilityMonitor(monitor).then(() => {
**Modules to Import**
```javascript
import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
```
```javascript
var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
```
### Starting an Ability and Listening for the Ability State
......
......@@ -4,11 +4,11 @@
**Context** provides the capability of obtaining contextual information of an application.
The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model.
The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model.
- FA model
- FA model
Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance.
Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance.
- Stage model
......@@ -54,6 +54,7 @@ setDisplayOrientation(orientation: bundle.DisplayOrientation): Promise<void>;
The methods are used to set the display orientation of the current ability.
**Example**
```javascript
import featureAbility from '@ohos.ability.featureAbility'
import bundle from '@ohos.bundle';
......@@ -96,13 +97,13 @@ Obtain the context by calling **context.getApplicationContext()** in **Ability**
**Example**
```javascript
import Ability from "@ohos.application.Ability";
import UIAbility from '@ohos.app.ability.UIAbility';
var lifecycleid;
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onCreate() {
console.log("MainAbility onCreate")
console.log("EntryAbility onCreate")
let AbilityLifecycleCallback = {
onAbilityCreate(ability){
console.log("AbilityLifecycleCallback onAbilityCreate ability:" + JSON.stringify(ability));
......@@ -191,25 +192,25 @@ Obtain the context from the **context** attribute in **Ability**.
**Example**
```javascript
import Ability from '@ohos.application.Ability'
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.log("[Demo] MainAbility onCreate")
console.log("[Demo] EntryAbility onCreate")
globalThis.abilityWant = want;
}
onDestroy() {
console.log("[Demo] MainAbility onDestroy")
console.log("[Demo] EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
// Set the main page for this ability when the main window is created.
console.log("[Demo] MainAbility onWindowStageCreate")
console.log("[Demo] EntryAbility onWindowStageCreate")
// Obtain AbilityContext and print the ability information.
let context = this.context;
console.log("[Demo] MainAbility bundleName " + context.abilityInfo.bundleName)
console.log("[Demo] EntryAbility bundleName " + context.abilityInfo.bundleName)
windowStage.loadContent("pages/index", (err, data) => {
if (err.code) {
......@@ -222,17 +223,17 @@ export default class MainAbility extends Ability {
onWindowStageDestroy() {
// Release the UI related resources when the main window is destroyed.
console.log("[Demo] MainAbility onWindowStageDestroy")
console.log("[Demo] EntryAbility onWindowStageDestroy")
}
onForeground() {
// The ability is switched to run in the foreground.
console.log("[Demo] MainAbility onForeground")
console.log("[Demo] EntryAbility onForeground")
}
onBackground() {
// The ability is switched to run in the background.
console.log("[Demo] MainAbility onBackground")
console.log("[Demo] EntryAbility onBackground")
}
};
```
......@@ -256,16 +257,16 @@ Use the API described in the table below to obtain the context associated with a
**Example**
```ts
// MainAbility.ts
import Ability from '@ohos.application.Ability'
// EntryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.log("[Demo] MainAbility onCreate")
console.log("[Demo] EntryAbility onCreate")
}
onDestroy() {
console.log("[Demo] MainAbility onDestroy")
console.log("[Demo] EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
......@@ -283,7 +284,7 @@ export default class MainAbility extends Ability {
```ts
// pages/index.ets
import context from '@ohos.application.context'
import context from '@ohos.app.ability.context'
type Context = context.Context
......
......@@ -126,7 +126,7 @@ As the entry of the ability continuation capability, **continuationManager** is
if (needGrantPermission) {
try {
// globalThis.context is Ability.context, which must be assigned a value in the MainAbility.ts file in advance.
await globalThis.context.requestPermissionsFromUser(permissions);
await atManger.requestPermissionsFromUser(globalThis.context, permissions);
} catch (err) {
console.error('app permission request permissions error' + JSON.stringify(err));
}
......@@ -175,7 +175,7 @@ As the entry of the ability continuation capability, **continuationManager** is
let want = {
deviceId: remoteDeviceId,
bundleName: 'ohos.samples.continuationmanager',
abilityName: 'MainAbility'
abilityName: 'EntryAbility'
};
globalThis.abilityContext.startAbility(want).then((data) => {
console.info('StartRemoteAbility finished, ' + JSON.stringify(data));
......
......@@ -40,4 +40,4 @@ For details about the project directory structure of the FA model, see [OpenHarm
For details about how to configure the application package structure of the FA model, see [Application Package Structure Configuration File](../quick-start/application-configuration-file-overview-fa.md).
<!--no_check-->
\ No newline at end of file
......@@ -63,9 +63,9 @@ To create an FA widget, you need to implement lifecycle callbacks using the **Li
1. Import the required modules.
```javascript
import formBindingData from '@ohos.application.formBindingData'
import formInfo from '@ohos.application.formInfo'
import formProvider from '@ohos.application.formProvider'
import formBindingData from '@ohos.app.form.formBindingData';
import formInfo from '@ohos.app.form.formInfo';
import formProvider from '@ohos.app.form.formProvider';
```
2. Implement lifecycle callbacks for the widget.
......@@ -158,7 +158,7 @@ The widget configuration file is named **config.json**. Find the **config.json**
| 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.<br>**true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.<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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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) |
| jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes. | String | No |
......@@ -206,7 +206,7 @@ A widget provider is usually started when it is needed to provide information ab
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 or update.
// Persistently store widget data for subsequent use, such as widget instance retrieval or update.
// The storeFormInfo API is not implemented here.
storeFormInfo(formId, formName, tempFlag, want);
......@@ -231,9 +231,9 @@ You should override **onDestroy** to implement widget data deletion.
}
```
For details about how to implement persistence data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
The **Want** passed by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
- Normal widget: a widget persistently used by the widget host
......@@ -254,14 +254,14 @@ onUpdate(formId) {
"detail": "detailOnUpdate"
};
let formData = formBindingData.createFormBindingData(obj);
// Call the updateForm method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged.
// Call the updateForm() method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged.
formProvider.updateForm(formId, formData).catch((error) => {
console.log('FormAbility updateForm, error:' + JSON.stringify(error));
});
}
```
### Developing Widget UI Pages
### Developing the Widget UI Page
You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget.
......@@ -335,7 +335,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.entry.MainAbility",
"abilityName": "com.example.entry.EntryAbility",
"params": {
"message": "add detail"
}
......@@ -353,12 +353,12 @@ Now you've got a widget shown below.
You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows:
1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file.
2. For the router event, set the following attributes:
- **action**: **router**, which indicates a router event.
- **abilityName**: target ability name, for example, **com.example.entry.MainAbility**, which is the default main ability name in DevEco Studio for the FA model.
- **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
3. For the message event, set the following attributes:
- **action**: **message**, which indicates a message event.
2. Set the router event.
- **action**: **"router"**, which indicates a router event.
- **abilityName**: target ability name, for example, **com.example.entry.EntryAbility**, which is the default UIAbility name in DevEco Studio for the FA model.
- **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the EntryAbility in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
3. Set the message event.
- **action**: **"message"**, which indicates a message event.
- **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**.
The code snippet is as follows:
......@@ -388,7 +388,7 @@ The code snippet is as follows:
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.entry.MainAbility",
"abilityName": "com.example.entry.EntryAbility",
"params": {
"message": "add detail"
}
......@@ -401,4 +401,4 @@ The code snippet is as follows:
}
}
}
```
\ No newline at end of file
```
......@@ -135,13 +135,13 @@ Obtain **deviceId** from **DeviceManager**. The sample code is as follows:
if (typeof dmClass === 'object' && dmClass != null) {
let list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
console.log("EntryAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
console.log("EntryAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
console.log("EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
......
......@@ -24,8 +24,6 @@ The differences between **onCommand()** and **onConnect()** are as follows:
1. Override the Service ability-related lifecycle callbacks to implement your own logic for processing interaction requests.
```ts
export default {
onStart() {
......@@ -47,7 +45,7 @@ The differences between **onCommand()** and **onConnect()** are as follows:
}
}
```
2. Register a Service ability.
Declare the Service ability in the **config.json** file by setting its **type** attribute to **service**.
......@@ -155,7 +153,7 @@ You can use either of the following methods to connect to a Service ability:
```ts
import prompt from '@system.prompt'
var option = {
onConnect: function onConnectCallback(element, proxy) {
console.log(`onConnectLocalService onConnectDone`);
......@@ -194,7 +192,7 @@ You can use either of the following methods to connect to a Service ability:
```ts
import featureAbility from '@ohos.ability.featureAbility'
let want = {
bundleName: "com.jstest.service",
abilityName: "com.jstest.service.ServiceAbility"
......@@ -208,7 +206,7 @@ You can use either of the following methods to connect to a Service ability:
```ts
import rpc from "@ohos.rpc"
class ServiceAbilityStub extends rpc.RemoteObject {
constructor(des: any) {
if (typeof des === 'string') {
......@@ -218,7 +216,7 @@ You can use either of the following methods to connect to a Service ability:
return;
}
}
onRemoteRequest(code: number, data: any, reply: any, option: any) {
console.log("onRemoteRequest called");
// Execute the service logic.
......@@ -235,7 +233,7 @@ You can use either of the following methods to connect to a Service ability:
return true;
}
}
export default {
onStart() {
console.log('ServiceAbility onStart');
......
......@@ -127,7 +127,7 @@ The code snippets provided below are all from [Sample](https://gitee.com/openhar
if (needGrantPermission) {
Logger.info("app permission needGrantPermission")
try {
await this.context.requestPermissionsFromUser(permissions)
await accessManger.requestPermissionsFromUser(this.context, permissions)
} catch (err) {
Logger.error(`app permission ${JSON.stringify(err)}`)
}
......@@ -147,8 +147,8 @@ The code snippets provided below are all from [Sample](https://gitee.com/openhar
Modules to import:
```javascript
import Ability from '@ohos.application.Ability';
import AbilityConstant from '@ohos.application.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
```
To implement ability continuation, you must implement this API and have the value **AGREE** returned.
......@@ -185,14 +185,14 @@ The code snippets provided below are all from [Sample](https://gitee.com/openhar
Example
```javascript
import Ability from '@ohos.application.Ability';
import UIAbility from '@ohos.app.ability.UIAbility';
import distributedObject from '@ohos.data.distributedDataObject';
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
storage : LocalStorag;
onCreate(want, launchParam) {
Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
Logger.info(`EntryAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
// Obtain the user data from the want parameter.
let workInput = want.parameters.work
......@@ -207,8 +207,6 @@ The code snippets provided below are all from [Sample](https://gitee.com/openhar
```
For a singleton ability, use **onNewWant()** to achieve the same implementation.
### Data Continuation
Use distributed objects.
......@@ -220,12 +218,12 @@ In the ability continuation scenario, the distributed data object is used to syn
- In **onContinue()**, the initiator saves the data to be migrated to the distributed object, calls the **save()** API to save the data and synchronize the data to the target device, sets the session ID, and sends the session ID to the target device through **wantParam**.
```javascript
import Ability from '@ohos.application.Ability';
import UIAbility from '@ohos.app.ability.UIAbility';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({data:undefined});
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
sessionId : string;
onContinue(wantParam : {[key: string]: any}) {
......@@ -256,34 +254,33 @@ In the ability continuation scenario, the distributed data object is used to syn
- 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.
```javascript
import Ability from '@ohos.application.Ability';
import distributedObject from '@ohos.data.distributedDataObject';
import UIAbility from '@ohos.app.ability.UIAbility';
import distributedObject from '@ohos.data.distributedDataObject';
var g_object = distributedObject.createDistributedObject({data:undefined});
var g_object = distributedObject.createDistributedObject({data:undefined});
export default class MainAbility extends Ability {
storage : LocalStorag;
export default class EntryAbility extends UIAbility {
storage : LocalStorag;
onCreate(want, launchParam) {
Logger.info(`EntryAbility 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}`)
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}`)
// Before fetching data from the remote device, reset g_object.data to undefined.
g_object.data = undefined;
// Set the session ID, so the target will fetch data from the remote device.
g_object.setSessionId(this.sessionId);
// Before fetching data from the remote device, reset g_object.data to undefined.
g_object.data = undefined;
// Set the session ID, so the target will fetch data from the remote device.
g_object.setSessionId(this.sessionId);
AppStorage.SetOrCreate<string>('ContinueStudy', g_object.data)
this.storage = new LocalStorage();
this.context.restoreWindowStage(this.storage);
}
AppStorage.SetOrCreate<string>('ContinueStudy', g_object.data)
this.storage = new LocalStorage();
this.context.restoreWindowStage(this.storage);
}
}
}
}
}
```
......@@ -309,5 +306,3 @@ In the ability continuation scenario, the distributed data object is used to syn
### Best Practice
For better user experience, you are advised to use the **wantParam** parameter to transmit data smaller than 100 KB and use distributed objects to transmit data larger than 100 KB.
<!--no_check-->
\ No newline at end of file
......@@ -56,8 +56,8 @@ The table below describes the APIs provided by the **Ability** class. For detail
### Implementing AbilityStage and Ability Lifecycle Callbacks
To create Page abilities for an application in the stage model, you must implement the **AbilityStage** class and ability lifecycle callbacks, and use the **Window** class to set the pages. The sample code is as follows:
1. Import the **AbilityStage** module.
```
import AbilityStage from "@ohos.application.AbilityStage"
```ts
import AbilityStage from "@ohos.app.ability.AbilityStage";
```
2. Implement the **AbilityStage** class. The default relative path generated by the APIs is **entry\src\main\ets\Application\AbilityStage.ts**.
```ts
......@@ -69,41 +69,41 @@ To create Page abilities for an application in the stage model, you must impleme
```
3. Import the **Ability** module.
```js
import Ability from '@ohos.application.Ability'
import UIAbility from '@ohos.app.ability.UIAbility';
```
4. Implement the lifecycle callbacks of the **Ability** class. The default relative path generated by the APIs is **entry\src\main\ets\MainAbility\MainAbility.ts**.
4. Implement the lifecycle callbacks of the **UIAbility** class. The default relative path generated by the APIs is **entry\src\main\ets\entryability\EntryAbility.ts**.
In the **onWindowStageCreate(windowStage)** API, use **loadContent** to set the application page to be loaded. For details about how to use the **Window** APIs, see [Window Development](../windowmanager/application-window-stage.md).
```ts
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
console.log("EntryAbility onCreate")
}
onDestroy() {
console.log("MainAbility onDestroy")
console.log("EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.log("MainAbility onWindowStageCreate")
console.log("EntryAbility onWindowStageCreate")
windowStage.loadContent("pages/index").then(() => {
console.log("MainAbility load content succeed")
console.log("EntryAbility load content succeed")
}).catch((error) => {
console.error("MainAbility load content failed with error: " + JSON.stringify(error))
console.error("EntryAbility load content failed with error: " + JSON.stringify(error))
})
}
onWindowStageDestroy() {
console.log("MainAbility onWindowStageDestroy")
console.log("EntryAbility onWindowStageDestroy")
}
onForeground() {
console.log("MainAbility onForeground")
console.log("EntryAbility onForeground")
}
onBackground() {
console.log("MainAbility onBackground")
console.log("EntryAbility onBackground")
}
}
```
......@@ -113,7 +113,8 @@ Both the **AbilityStage** and **Ability** classes have the **context** attribute
The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute in the **AbilityStage** class. The sample code is as follows:
```ts
import AbilityStage from "@ohos.application.AbilityStage"
import AbilityStage from "@ohos.app.ability.AbilityStage";
export default class MyAbilityStage extends AbilityStage {
onCreate() {
console.log("MyAbilityStage onCreate")
......@@ -132,52 +133,32 @@ export default class MyAbilityStage extends AbilityStage {
The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute in the **Ability** class. The sample code is as follows:
```ts
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
import UIAbility from '@ohos.app.ability.UIAbility';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.log("MainAbility onCreate")
console.log("EntryAbility onCreate")
let context = this.context
console.log("MainAbility bundleCodeDir" + context.bundleCodeDir)
console.log("EntryAbility bundleCodeDir" + context.bundleCodeDir)
let abilityInfo = this.context.abilityInfo;
console.log("MainAbility ability bundleName" + abilityInfo.bundleName)
console.log("MainAbility ability name" + abilityInfo.name)
console.log("EntryAbility ability bundleName" + abilityInfo.bundleName)
console.log("EntryAbility ability name" + abilityInfo.name)
let config = this.context.config
console.log("MainAbility config language" + config.language)
console.log("EntryAbility config language" + config.language)
}
}
```
### Requesting Permissions
If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from consumers. During application development, you need to specify the involved sensitive permissions, declare the required permissions in **module.json5**, and use the **requestPermissionsFromUser** API to request the permission from consumers in the form of a dialog box. The following uses the permission for calendar access as an example.
Declare the required permission in the **module.json5** file.
```json
"requestPermissions": [
{
"name": "ohos.permission.READ_CALENDAR"
}
]
```
Request the permission from consumers 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))
})
```
### Notifying of Environment Changes
Environment changes include changes of global configurations and ability configurations. Currently, the global configurations include the system language and color mode. The change of global configurations is generally triggered by configuration items in **Settings** or icons in **Control Panel**. The ability configuration is specific to a single **Ability** instance, including the display ID, screen resolution, and screen orientation. The configuration is related to the display where the ability is located, and the change is generally triggered by the window. For details on the configuration, see [Configuration](../reference/apis/js-apis-configuration.md).
Environment changes include changes of global configurations and ability configurations. Currently, the global configurations include the system language and color mode. The change of global configurations is generally triggered by configuration items in **Settings** or icons in **Control Panel**. The ability configuration is specific to a single **Ability** instance, including the display ID, screen resolution, and screen orientation. The configuration is related to the display where the ability is located, and the change is generally triggered by the window. Before configuring a project, define the project in the [Configuration](../reference/apis/js-apis-application-configuration.md) class.
For an application in the stage model, when the configuration changes, its abilities are not restarted, but the **onConfigurationUpdated(config: Configuration)** callback is triggered. If the application needs to perform processing based on the change, you can overwrite **onConfigurationUpdated**. Note that the **Configuration** object in the callback contains all the configurations of the current ability, not only the changed configurations.
For an application in the stage model, when the configuration changes, its abilities are not restarted, but the **onConfigurationUpdated(config: Configuration)** callback is triggered. If the application needs to perform processing based on the change, you can override **onConfigurationUpdated**. Note that the **Configuration** object in the callback contains all the configurations of the current ability, not only the changed configurations.
The following example shows the implementation of the **onConfigurationUpdated** callback in the **AbilityStage** class. The callback is triggered when the system language and color mode are changed.
```ts
import AbilityStage from '@ohos.application.AbilityStage'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
import AbilityStage from '@ohos.app.ability.AbilityStage';
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
export default class MyAbilityStage extends AbilityStage {
onConfigurationUpdated(config) {
......@@ -190,10 +171,10 @@ export default class MyAbilityStage extends AbilityStage {
The following example shows the implementation of the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the direction and density) change.
```ts
import Ability from '@ohos.application.Ability'
import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
import UIAbility from '@ohos.app.ability.UIAbility';
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
direction : number;
onCreate(want, launchParam) {
......@@ -229,7 +210,7 @@ let context = this.context
var want = {
"deviceId": "",
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
"abilityName": "EntryAbility"
};
context.startAbility(want).then(() => {
console.log("Succeed to start ability")
......@@ -246,7 +227,7 @@ let context = this.context
var want = {
"deviceId": getRemoteDeviceId(),
"bundleName": "com.example.MyApplication",
"abilityName": "MainAbility"
"abilityName": "EntryAbility"
};
context.startAbility(want).then(() => {
console.log("Succeed to start remote ability")
......@@ -261,17 +242,17 @@ 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");
console.log("EntryAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
console.log("EntryAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
console.log("EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
Request the permission **ohos.permission.DISTRIBUTED_DATASYNC** from consumers. This permission is used for data synchronization. For details about the sample code for requesting the permission, see [Requesting Permissions](#requesting-permissions).
Request the permission **ohos.permission.DISTRIBUTED_DATASYNC** from consumers. This permission is used for data synchronization. For details about the sample code for requesting permissions, see [abilityAccessCtrl.requestPermissionsFromUse](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9).
### Starting an Ability with the Specified Page
If the launch type of an ability is set to **singleton** and the ability has been started, the **onNewWant** callback is triggered when the ability is started again. You can pass start options through the **want**. For example, to start an ability with the specified page, use the **uri** or **parameters** parameter in the **want** to pass the page information. Currently, the ability in the stage model cannot directly use the **router** capability. You must pass the start options to the custom component and invoke the **router** method to display the specified page during the custom component lifecycle management. The sample code is as follows:
......@@ -281,7 +262,7 @@ async function reStartAbility() {
try {
await this.context.startAbility({
bundleName: "com.sample.MyApplication",
abilityName: "MainAbility",
abilityName: "EntryAbility",
uri: "pages/second"
})
console.log('start ability succeed')
......@@ -293,9 +274,9 @@ async function reStartAbility() {
Obtain the **want** parameter that contains the page information from the **onNewWant** callback of the ability.
```ts
import Ability from '@ohos.application.Ability'
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onNewWant(want, launchParams) {
globalThis.newWant = want
}
......@@ -321,5 +302,3 @@ struct Index {
}
}
```
<!--no_check-->
\ No newline at end of file
......@@ -111,4 +111,4 @@ For details about the project directory structure of the stage model, see [OpenH
For details about how to configure the application package structure of the stage model, see [Application Package Structure Configuration File](../quick-start/application-configuration-file-overview-stage.md).
<!--no_check-->
\ No newline at end of file
......@@ -24,8 +24,10 @@ The ability call process is as follows:
- The callee ability, which holds a **Callee** object, uses **on()** of the **Callee** object to register a callback. This callback is invoked when the callee ability receives data from the caller ability.
![stage-call](figures/stage-call.png)
> **NOTE**<br/>
> **NOTE**
>
> The launch type of the callee ability must be **singleton**.
>
> Currently, only system applications can use the ability call.
## Available APIs
......@@ -34,7 +36,7 @@ The table below describes the ability call APIs. For details, see [Ability](../r
**Table 2** Ability call APIs
|API|Description|
|:------|:------|
|startAbilityByCall(want: Want): Promise\<Caller>|Starts an ability in the foreground (through the **want** configuration) or background (default) and obtains the **Caller** object for communication with the ability. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextstartabilitybycall) or [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartabilitybycall).|
|startAbilityByCall(want: Want): Promise\<Caller>|Starts an ability in the foreground (through the **want** configuration) or background (default) and obtains the **Caller** object for communication with the ability. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextstartabilitybycall) or **ServiceExtensionContext**.|
|on(method: string, callback: CalleeCallBack): void|Callback invoked when the callee ability registers a method.|
|off(method: string): void|Callback invoked when the callee ability deregisters a method.|
|call(method: string, data: rpc.Sequenceable): Promise\<void>|Sends agreed sequenceable data to the callee ability.|
......@@ -210,22 +212,25 @@ 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")
console.log("EntryAbility onButtonClick getRemoteDeviceId err: list is null")
return
}
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId)
console.log("EntryAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId)
return list[0].deviceId
} else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null")
console.log("EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null")
}
}
```
In the cross-device scenario, your application must also apply for the data synchronization permission from end users. The code snippet is as follows:
```ts
import abilityAccessCtrl from '@ohos.abilityAccessCtrl.d.ts';
requestPermission() {
let context = this.context
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
context.requestPermissionsFromUser(permissions).then((data) => {
let atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, 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))
......
......@@ -42,9 +42,9 @@ OpenHarmony does not support creation of a Service Extension ability for third-p
2. Customize a class that inherits from `ServiceExtensionAbility` in the .ts file in the directory where the Service Extension ability is defined (`entry\src\main\ets\ServiceExtAbility\ServiceExtAbility.ts` by default) and override the lifecycle callbacks of the base class. The code sample is as follows:
```js
import ServiceExtensionAbility from '@ohos.application.ServiceExtensionAbility'
import rpc from '@ohos.rpc'
import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
import rpc from '@ohos.rpc';
class StubTest extends rpc.RemoteObject {
constructor(des) {
super(des);
......@@ -52,7 +52,7 @@ OpenHarmony does not support creation of a Service Extension ability for third-p
onRemoteRequest(code, data, reply, option) {
}
}
class ServiceExtAbility extends ServiceExtensionAbility {
onCreate(want) {
console.log('onCreate, want:' + want.abilityName);
......
# WantAgent Development
## When to Use
The **WantAgent** class encapsulates want information that specifies a particular action, which can be starting an ability or publishing a common event. You can either call **wantAgent.trigger** to trigger a **WantAgent** directly or add a **WantAgent** to a notification so that it will be triggered when users tap the notification.
The **WantAgent** class encapsulates want information that specifies a particular action, which can be starting an ability or publishing a common event. You can either call **wantAgent.trigger** to trigger a **WantAgent** directly or add a **WantAgent** to a notification so that it will be triggered when users tap the notification.
## Available APIs
| API | Description|
......@@ -12,13 +12,13 @@ The **WantAgent** class encapsulates want information that specifies a particula
## How to Develop
1. Import the **WantAgent** module.
```
import wantAgent from '@ohos.wantAgent';
```ts
import wantAgent from '@ohos.app.ability.wantAgent';
```
2. Create a **WantAgentInfo** object that will be used for starting an ability. For details about the data types and parameters of **WantAgentInfo**, see [WantAgent](../reference/apis/js-apis-wantAgent.md#wantagentinfo).
```
```ts
private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations.
// wantAgentInfo
......@@ -27,7 +27,7 @@ The **WantAgent** class encapsulates want information that specifies a particula
{
deviceId: "",
bundleName: "com.example.test",
abilityName: "com.example.test.MainAbility",
abilityName: "com.example.test.EntryAbility",
action: "",
entities: [],
uri: "",
......@@ -42,7 +42,7 @@ The **WantAgent** class encapsulates want information that specifies a particula
3. Create a **WantAgentInfo** object for publishing a common event.
```
```ts
private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations.
// wantAgentInfo
......@@ -61,7 +61,7 @@ The **WantAgent** class encapsulates want information that specifies a particula
4. Create a **WantAgent** object and save the returned **wantAgentObj** for subsequent trigger operations.
```
```ts
// Create a WantAgent object.
wantAgent.getWantAgent(wantAgentInfo, (err, wantAgentObj) => {
if (err.code) {
......@@ -75,7 +75,7 @@ The **WantAgent** class encapsulates want information that specifies a particula
5. Trigger the **WantAgent** object.
```
```ts
// Trigger the WantAgent object.
var triggerInfo = {
code:0
......
......@@ -18,7 +18,7 @@ To facilitate your application development, we provide development guidelines fo
First thing first, familiarize yourself with the two cornerstone frameworks in OpenHarmony applications:
- Application framework: [Ability Development](ability/Readme-EN.md)
- Application framework: [Application Models](application-models/Readme-EN.md)
- UI framework: [UI Development](ui/Readme-EN.md)
All applications should be developed on top of these frameworks.
......@@ -37,6 +37,7 @@ Then, equip yourself for developing the key features, with the following guideli
- [Device Usage Statistics](device-usage-statistics/Readme-EN.md)
- [DFX](dfx/Readme-EN.md)
- [Internationalization](internationalization/Readme-EN.md)
- [Application Test](application-test/Readme-EN.md)
- [IDL Specifications and User Guide](IDL/idl-guidelines.md)
- [Using Native APIs in Application Projects](napi/Readme-EN.md)
......@@ -56,11 +57,11 @@ API references encompass all components and APIs available in OpenHarmony, helpi
They are organized as follows:
- [Component Reference (TypeScript-based Declarative Development Paradigm)](reference/arkui-ts/Readme-EN.md)
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md)
- APIs
- [JS and TS APIs](reference/apis/Readme-EN.md)
- Native APIs
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md)
- [JS Service Widget UI Components](reference/js-service-widget-ui/Readme-EN.md)
- APIs
- [JS and TS APIs](reference/apis/Readme-EN.md)
- Native APIs
- [Standard Library](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md)
......
......@@ -18,7 +18,7 @@ To facilitate your application development, we provide development guidelines fo
First thing first, familiarize yourself with the two cornerstone frameworks in OpenHarmony applications:
- Application framework: [Ability Development](ability/fa-brief.md)
- Application framework: [Application Models](application-models/application-model-composition.md)
- UI framework: [UI Development](ui/arkui-overview.md)
All applications should be developed on top of these frameworks.
......@@ -35,8 +35,9 @@ Then, equip yourself for developing the key features, with the following guideli
- [Task Management](task-management/background-task-overview.md)
- [Device](device/usb-overview.md)
- [Device Usage Statistics](device-usage-statistics/device-usage-statistics-overview.md)
- [DFX](dfx/hiappevent-overview.md)
- [DFX](dfx/hiappevent-guidelines.md)
- [Internationalization](internationalization/international-overview.md)
- [Application Test](application-test/arkxtest-guidelines.md)
- [OpenHarmony IDL Specifications and User Guide](IDL/idl-guidelines.md)
- [Using Native APIs in Application Projects](napi/napi-guidelines.md)
......@@ -59,7 +60,9 @@ They are organized as follows:
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md)
- [JS and TS APIs](reference/apis/js-apis-DataUriUtils.md)
- [JS Service Widget UI Components](reference/js-service-widget-ui/Readme-EN.md)
- [JS and TS APIs](reference/apis/js-apis-ability-dataUriUtils.md)
- Native APIs
- [Standard Library](reference/native-lib/third_party_libc/musl.md)
......
......@@ -78,6 +78,5 @@ The **module.json5** of a browser application is as follows:
4. If **type** in the passed **want** parameter is specified and is included in **type** under **skills**, the matching is successful.
2. When there are multiple matching applications, a dialog box is displayed for you to select one of them.
<img src="figures/stage-want1.png" alt="stage-want1" style="zoom:80%;" />
\ No newline at end of file
2. When there are multiple matching applications, a dialog box is displayed for you to select one of them.
<img src="figures/stage-want1.png" alt="stage-want1" style="zoom:80%;" />
......@@ -55,4 +55,3 @@ When an application is switched to the background, it is cached in the backgroun
}
```
<!--no_check-->
\ No newline at end of file
......@@ -2,6 +2,7 @@
The [action](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction) field specifies the common operation (such as viewing, sharing, and application details) to be performed by the caller. In implicit Want, you can define this field and use it together with **uri** or **parameters** to specify the operation to be performed on the data, for example, viewing URI data. For example, if the URI is a website and the action is **ohos.want.action.viewData**, the ability that supports website viewing is matched. Declaring the **action** field in Want indicates that the invoked application should support the declared operation. The **actions** field under **skills** in the configuration file indicates the operations supported by the application.
**Common action Values**
......@@ -15,6 +16,7 @@ The [action](../reference/apis/js-apis-ability-wantConstant.md#wantconstantactio
The [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) field specifies the additional category information (such as browser and video player) of the target ability. It is a supplement to **action** in implicit Want. You can define this field to filter application categories, for example, browser. Declaring the **entities** field in Want indicates that the invoked application should belong to the declared category. The **entities** field under **skills** in the configuration file indicates the categories supported by the application.
**Common entities Values**
......
......@@ -13,8 +13,8 @@ Due to the differences in the thread model and process model, certain APIs (mark
import fa from '@ohos.ability.featureAbility';
let parameter = {
"want": {
bundleName: "ohos.samples.demo",
abilityName: "ohos.samples.demo.MainAbility"
bundleName: "com.example.myapplication",
abilityName: "com.example.myapplication.EntryAbility"
}
}
fa.startAbility(parameter).then((data) => {
......@@ -30,8 +30,8 @@ Due to the differences in the thread model and process model, certain APIs (mark
// context is a member of the ability object and is required for invoking inside a non-ability object.
// Pass in the Context object.
let wantInfo = {
bundleName: "ohos.samples.demo",
abilityName: "ohos.samples.demo.MainAbility"
bundleName: "com.example.myapplication",
abilityName: "EntryAbility"
};
this.context.startAbility(wantInfo).then((data) => {
console.info('startAbility success.');
......
......@@ -28,4 +28,3 @@ OpenHarmony has reconstructed the [deviceConfig](../quick-start/deviceconfig-str
| compressNativeLibs | Whether the **libs** libraries are packaged in the HAP file after being compressed.| / | This configuration is not supported in the stage model.|
| network | Network security configuration.| / | This configuration is not supported in the stage model.|
<!--no_check-->
\ No newline at end of file
......@@ -38,4 +38,3 @@ When developing an application, you may need to configure certain tags to identi
To request component permissions, set the **reqPermission** field under **module** in the **config.json** file. This field declares the name of the permission to request, the reason for requesting the permission, and the scenario where the permission is used. For details about the configuration, see [reqPermission](../quick-start/module-structure.md).
<!--no_check-->
\ No newline at end of file
......@@ -3,8 +3,7 @@
When developing an application, you may need to configure certain tags to identify the application, such as the bundle name and application icon. This topic describes key tags that need to be configured during application development. Icons and labels are usually configured together. There is the application icon, application label, entry icon, and entry label, which correspond to the **icon** and **label** fields in the [app.json5 file](../quick-start/app-configuration-file.md) and [module.json5 file](../quick-start/module-configuration-file.md). The application icon and label are used in **Settings**. For example, they are displayed in the application list in **Settings**. The entry icon is displayed on the device's home screen after the application is installed. The entry icon maps to a [UIAbility](uiability-overview.md) component. Therefore, an application can have multiple entry icons and labels. When you touch one of them, the corresponding UIAbility page is displayed.
**Figure 1** Icons and labels
**Figure 1** Icons and labels
![application-component-configuration-stage](figures/application-component-configuration-stage.png)
......@@ -71,4 +70,3 @@ When developing an application, you may need to configure certain tags to identi
The **requestPermission** field in the [module.json5 file](../quick-start/module-configuration-file.md) is used to configure the permission information required by the module to access the protected part of the system or other applications. This field declares the name of the permission to request, the reason for requesting the permission, and the scenario where the permission is used.
<!--no_check-->
\ No newline at end of file
......@@ -12,7 +12,7 @@
<img src="figures/context-holding.png" alt="context-holding" style="zoom:50%;" />
- The following describes the information provided by different contexts.
- [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md): Each UIAbility has the **Context** attribute, which provides APIs to operate the ability, obtain the ability configuration, request permissions from users, and more.
- [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md): Each UIAbility has the **Context** attribute, which provides APIs to operate the ability, obtain the ability configuration, and more.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -65,15 +65,10 @@ This topic describes how to use the context in the following scenarios:
- [Obtaining the Application Development Path](#obtaining-the-application-development-path)
- [Obtaining and Modifying Encrypted Areas](#obtaining-and-modifying-encrypted-areas)
- [Creating Context of Another Application or Module](#creating-context-of-another-application-or-module)
- [Subscribing to Ability Lifecycle Changes in a Process](#subscribing-to-ability-lifecycle-changes-in-a-process)
- [Requesting Permissions from Users Through AbilityContext](#requesting-permissions-from-users-through-uiabilitycontext)
### Obtaining the Application Development Path
......@@ -180,9 +175,9 @@ The base class **Context** provides the [createBundleContext(bundleName:string)]
> - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
>
> - This is a system API and cannot be called by third-party applications.
For example, application information displayed on the home screen includes the application name and icon. The home screen application calls the foregoing method to obtain the context information, so as to obtain the resource information including the application name and icon.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -194,8 +189,8 @@ The base class **Context** provides the [createBundleContext(bundleName:string)]
// ...
}
}
```
```
- Call **createModuleContext(bundleName:string, moduleName:string)** to obtain the context of a specified module of another application. After obtaining the context, you can obtain the resource information of that module.
> **NOTE**
>
......@@ -204,7 +199,7 @@ The base class **Context** provides the [createBundleContext(bundleName:string)]
> - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
>
> - This is a system API and cannot be called by third-party applications.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -217,7 +212,7 @@ The base class **Context** provides the [createBundleContext(bundleName:string)]
}
}
```
- Call **createModuleContext(moduleName:string)** to obtain the context of another module in the current application. After obtaining the context, you can obtain the resource information of that module.
```ts
......@@ -242,7 +237,7 @@ When the ability lifecycle changes in a process, for example, being created or d
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
const TAG: string = "[Example].[Entry].[EntryAbility]";
......@@ -298,14 +293,3 @@ export default class EntryAbility extends UIAbility {
}
}
```
### Requesting Permissions from Users Through UIAbilityContext
Each ability has the **Context** attribute. The ability is used to process the lifecycle. Methods use to operate the ability (such as **startAbility()**, **connectServiceExtensionAbility()**, and **terminateSelf()**) are implemented in the corresponding context. The context also provides methods for obtaining the ability configuration and requesting permissions from users. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
When an application needs to obtain users' privacy information or use system capabilities, for example, to obtain location information, to access the calendar, or to use the camera to take photos or record videos, the application must request permissions from users, as shown below. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md).
**Figure 2** Requesting the permission to access the calendar from users
<img src="figures/application-context-stage.png" alt="application-context-stage" style="zoom:50%;" />
\ No newline at end of file
......@@ -58,4 +58,3 @@ The table below describes their differences in detail.
| **Mission management model**| - A mission is created for each PageAbility component instance.<br>- Missions are stored persistently until the number of missions exceeds the maximum (customized based on the product configuration) or users delete missions.<br>- PageAbility components do not form a stack structure.<br>For details, see [Mission Management Scenarios](mission-management-overview.md).| - A mission is created for each UIAbility component instance.<br>- Missions are stored persistently until the number of missions exceeds the maximum (customized based on the product configuration) or users delete missions.<br>- UIAbility components do not form a stack structure.<br>For details, see [Mission Management Scenarios](mission-management-overview.md).|
| **Application configuration file**| The **config.json** file is used to describe the application, HAP, and application component information.<br>For details, see [Application Configuration File Overview (FA Model)](../quick-start/application-configuration-file-overview-fa.md).| The **app.json5** file is used to describe the application information, and the **module.json5** file is used to describe the HAP and application component information.<br>For details, see [Application Configuration File Overview (Stage Model)](../quick-start/application-configuration-file-overview-stage.md).|
<!--no_check-->
\ No newline at end of file
......@@ -12,15 +12,15 @@ A UIAbility accesses a ServiceAbility in the same way as it accesses a ServiceEx
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends UIAbility {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate");
console.info("EntryAbility onCreate");
}
onDestroy() {
console.info("MainAbility onDestroy")
console.info("EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
console.info("EntryAbility onWindowStageCreate")
let want = {
bundleName: "com.ohos.fa",
abilityName: "ServiceAbility",
......@@ -40,13 +40,13 @@ export default class MainAbility extends UIAbility {
let connectionId = this.context.connectServiceExtensionAbility(want, options);
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
console.info("EntryAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
console.info("EntryAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
console.info("EntryAbility onBackground")
}
}
```
......
......@@ -25,7 +25,7 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
- **Before starting a component of another application, verify the visible field of the target component.**
- This rule applies only to cross-application scenarios.
- If the **visible** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission.
- For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities-tag)
- For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities).
- **Before starting a component of a background application, verify the BACKGROUND permission.**
- An application is considered as a foreground application only when the application process gains focus or its UIAbility component is running in the foreground.
......@@ -67,4 +67,3 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
![component-startup-rules](figures/component-startup-inter-fa.png)
<!--no_check-->
\ No newline at end of file
......@@ -24,7 +24,7 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
- **Before starting a component of another application, verify the visible field of the target component.**
- If the **visible** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission.
- For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities-tag)
- For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities).
- **Before starting a component of a background application, verify the BACKGROUND permission.**
- An application is considered as a foreground application only when the application process gains focus or its UIAbility component is running in the foreground.
......@@ -62,4 +62,3 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
![component-startup-rules](figures/component-startup-inter-stage.png)
<!--no_check-->
\ No newline at end of file
......@@ -4,4 +4,3 @@ The application configuration file contains information about the application co
The application project code developed based on the FA model contains a **config.json** file. For details about common configuration items, see [Application- or Component-Level Configuration](application-component-configuration-fa.md). For details about the file, see [Application Configuration File Overview (FA Model)](../quick-start/application-configuration-file-overview-fa.md).
<!--no_check-->
\ No newline at end of file
......@@ -4,4 +4,3 @@ The application configuration file contains information about the application co
The application project code developed based on the stage model contains one **app.json5** file and one or more **module.json5** files. For details about common configuration items, see [Application- or Component-Level Configuration (Stage Model)](application-component-configuration-stage.md). For details about the two files, see [Application Configuration File Overview (Stage Model)](../quick-start/application-configuration-file-overview-stage.md).
<!--no_check-->
\ No newline at end of file
......@@ -9,4 +9,3 @@ The stage model uses the [app.json5](../quick-start/app-configuration-file.md) a
**Figure 1** Configuration file differences
![comparison-of-configuration-file](figures/comparison-of-configuration-file.png)
<!--no_check-->
\ No newline at end of file
......@@ -30,7 +30,7 @@ export default {
```
After the PageAbility is created, its abilities-related configuration items are displayed in the **config.json** file. The following is an example **config.json** file of an ability named MainAbility:
After the PageAbility is created, its abilities-related configuration items are displayed in the **config.json** file. The following is an example **config.json** file of an ability named EntryAbility:
```json
{
......@@ -48,13 +48,13 @@ After the PageAbility is created, its abilities-related configuration items are
],
"orientation": "unspecified",
"visible": true,
"srcPath": "MainAbility",
"name": ".MainAbility",
"srcPath": "EntryAbility",
"name": ".EntryAbility",
"srcLanguage": "ets",
"icon": "$media:icon",
"description": "$string:MainAbility_desc",
"description": "$string:EntryAbility_desc",
"formsEnabled": false,
"label": "$string:MainAbility_label",
"label": "$string:EntryAbility_label",
"type": "page",
"launchType": "singleton"
}
......@@ -65,6 +65,7 @@ After the PageAbility is created, its abilities-related configuration items are
In the FA model, you can call **getContext** of **featureAbility** to obtain the application context and then use the capabilities provided by the context.
**Table 1** featureAbility APIs
| API| Description|
......
......@@ -56,20 +56,20 @@ Users often need to share data (such as a text or an image) from one application
}
}
}
```
In the preceding code, the custom field **parameters** is used. The **ability.picker.\*** fields in the first-layer **parameters** are used to pass the information to be displayed on the application selector. The following fields are involved:
```
In the preceding code, the custom field **parameters** is used. The **ability.picker.\*** fields in the first-layer **parameters** are used to pass the information to be displayed on the application selector. The following fields are involved:
- **"ability.picker.type"**: The application selector renders the file type icon based on this field.
- **"ability.picker.fileNames"**: The application selector displays the file name based on this field.
- **"ability.picker.fileSizes"**: The application selector displays the file size based on this field. The unit is byte.
- **"ability.picker.fileNames"** and **"ability.picker.fileSizes"** are arrays and have a one-to-one mapping.
- **"ability.picker.fileNames"** and **"ability.picker.fileSizes"** are arrays and have a one-to-one mapping.
For example, when **"ability.picker.type"** is **"application/pdf"**, **"ability.picker.fileNames"** is **"["APIs.pdf"]"**, and **"ability.picker.fileSizes"** is **"[350 \* 1024]"**, the application selector is displayed as follows:
<img src="figures/stage-want2.png" alt="stage-want2" style="zoom:50%;" />
In the preceding code, the **ability.want.params.INTENT** field is nested Want. In this field, **action** and **type** are used for implicit matching by the application selector. For details about implicit matching, see [Implicit Want Matching Rules](explicit-implicit-want-mappings.md#interpretation-of-implicit-want-matching-rules). After the user selects an application, the nested Want of the **ability.want.params.INTENT** field is passed to that application.
In the preceding code, the **ability.want.params.INTENT** field is nested Want. In this field, **action** and **type** are used for implicit matching by the application selector. For details about implicit matching, see [Matching Rules of Implicit Want](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want). After the user selects an application, the nested Want of the **ability.want.params.INTENT** field is passed to that application.
- Shared party
1. As mentioned above, the application selector performs implicit matching based on the **ability.want.params.INTENT** field. Therefore, you must set **skills** in the ability configuration file (**module.json5** file in the stage model) of the shared party as follows:
......
......@@ -59,4 +59,3 @@ The following is an example **config.json** file:
For details about the configuration items, see [Internal Structure of module](../quick-start/module-structure.md).
<!--no_check-->
\ No newline at end of file
# Matching Rules of Explicit Want and Implicit Want
Both explicit Want and implicit Want can be used to match an ability to start based on certain rules. These rules determine how the parameters set in Want match the configuration file declared by the target ability.
## Matching Rules of Explicit Want
The table below describes the matching rules of explicit Want.
- **Matching rules of explicit Want**
| Name| Type| Matching Item| Mandatory| Rule Description|
| -------- | -------- | -------- | -------- | -------- |
| deviceId | string | Yes| No| If this field is unspecified, only abilities on the local device are matched.|
| bundleName | string | Yes| Yes| If **abilityName** is specified but **bundleName** is unspecified, the matching fails.|
| moduleName | string | Yes| No| If this field is unspecified and multiple modules with the same ability name exist in the application, the first ability is matched by default.|
| abilityName | string | Yes| Yes| To use explicit Want, this field must be specified.|
| uri | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| type | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| action | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| entities | Array&lt;string&gt; | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| flags | number | No| No| This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.|
| Name| Type| Matching Item| Mandatory| Rule Description|
| -------- | -------- | -------- | -------- | -------- |
| deviceId | string | Yes| No| If this field is unspecified, only abilities on the local device are matched.|
| bundleName | string | Yes| Yes| If **abilityName** is specified but **bundleName** is unspecified, the matching fails.|
| moduleName | string | Yes| No| If this field is unspecified and multiple modules with the same ability name exist in the application, the first ability is matched by default.|
| abilityName | string | Yes| Yes| To use explicit Want, this field must be specified.|
| uri | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| type | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| action | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| entities | Array&lt;string&gt; | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
| flags | number | No| No| This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.|
| parameters | {[key:&nbsp;string]:&nbsp;any} | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
- **Matching rules for implicit Want**
| Name| Type| Matching Item| Mandatory| Rule Description|
| -------- | -------- | -------- | -------- | -------- |
| deviceId | string | Yes| No| Implicit invoking is not supported across devices.|
| abilityName | string | No| No| To use implicit Want, this field must be left unspecified.|
| bundleName | string | Yes| No| - When only **bundleName** is specified, matching is limited to that application.<br>- When both **bundleName** and **moduleName** are specified, matching is limited to that module in that application.<br>- When only **moduleName** is specified, the setting is invalid.<br>For details, see [Interpretation of Implicit Want Matching Rules](#interpretation-of-implicit-want-matching-rules). |
| moduleName | string | Yes| No||
| uri | string | Yes| No||
| type | string | Yes| No||
| action | string | Yes| No||
| entities | Array&lt;string&gt; | Yes| No||
| flags | number | No| No| This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.|
| parameters | {[key:&nbsp;string]:&nbsp;any} | No| No| This field is not used for matching. It is passed to the target ability as a parameter.|
## Matching Rules for Implicit Want
## Interpretation of Implicit Want Matching Rules
The table below describes the matching rules of implicit Want.
| Name | Type | Matching Item| Mandatory| Rule Description |
| ----------- | ------------------------------ | ------ | ---- | ------------------------------------------------------------ |
| deviceId | string | Yes | No | Implicit invoking is not supported across devices. |
| abilityName | string | No | No | To use implicit Want, this field must be left unspecified. |
| bundleName | string | Yes | No | - When only **bundleName** is specified, matching is limited to that application.<br>- When both **bundleName** and **moduleName** are specified, matching is limited to that module in that application.<br>- When only **moduleName** is specified, the setting is invalid.<br> <br>These fields will be used for implicit matching.|
| moduleName | string | Yes | No | |
| uri | string | Yes | No | |
| type | string | Yes | No | |
| action | string | Yes | No | |
| entities | Array&lt;string&gt; | Yes | No | |
| flags | number | No | No | This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.|
| parameters | {[key:&nbsp;string]:&nbsp;any} | No | No | This field is not used for matching. It is passed to the target ability as a parameter. |
Get familiar with the following about implicit Want:
- The **want** parameter passed by the caller indicates the operation to be performed by the caller. It also provides data and application type restrictions.
- The **skills** field declares the capabilities of the target ability. For details, see [the skills tag](../quick-start/module-configuration-file.md#skills-tag) in the [module.json5 file](../quick-start/module-configuration-file.md).
- The **skills** field declares the capabilities of the target ability. For details, see [the skills tag](../quick-start/module-configuration-file.md#skills) in the [module.json5 file](../quick-start/module-configuration-file.md).
The system matches the **want** parameter (including the **action**, **entities**, **uri**, and **type** attributes) passed by the caller against the **skills** configuration (including the **actions**, **entities**, **uris**, and **type** attributes) of the abilities one by one. When all the four attributes are matched, a dialog box is displayed for users to select a matched application.
......@@ -60,8 +60,7 @@ The system matches the [action](../reference/apis/js-apis-ability-wantConstant.m
- If **action** in the passed **want** parameter is specified, and **actions** under **skills** of an ability is specified but does not contain **action** in the passed **want** parameter, the matching fails.
Figure 1 Matching rules of action in the want parameter
**Figure 1** Matching rules of action in the want parameter
<img src="figures/want-action.png" alt="want-action" style="zoom:80%;" />
......@@ -112,6 +111,7 @@ There are four combinations of **uri** and **type** settings. The matching rules
To simplify the description, **uri** and **type** passed in the **want** parameter are called **w_uri** and **w_type**, respectively; the **uris** array under **skills** of an ability to match is called **s_uris**; each element in the array is called **s_uri**. Matching is performed from top to bottom.
Figure 4 Matching rules of uri and type in the want parameter
<img src="figures/want-uri-type2.png" alt="want-uri-type2" style="zoom:80%;" />
......@@ -158,5 +158,3 @@ To simplify the description, **uri** in the passed **want** parameter is called
- If the last character of **s_type** is the wildcard `*`, for example, `prefixType/*`, the matching is successful only when **w_type** contains `prefixType/`.
- If the last character of **w_type** is the wildcard `*`, for example, `prefixType/*`, the matching is successful only when **s_type** contains `prefixType/`.
<!--no_check-->
\ No newline at end of file
......@@ -345,21 +345,19 @@ The following describes how to implement multi-device collaboration through cros
3. Create the callee ability.
For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use **on()** to register a listener. When data does not need to be received, use **off()** to deregister the listener.
For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use **on()** to register a listener. When data does not need to be received, use **off()** to deregister the listener.
1. Configure the launch type of the UIAbility.
Set **launchType** of the callee ability to **singleton** in the **module.json5** file.
| JSON Field| Description|
| -------- | -------- |
| "launchType"| Ability launch type. Set this parameter to **singleton**.|
An example of the UIAbility configuration is as follows:
Set **launchType** of the callee ability to **singleton** in the **module.json5** file.
| JSON Field| Description|
| -------- | -------- |
| "launchType"| Ability launch type. Set this parameter to **singleton**.|
An example of the UIAbility configuration is as follows:
```json
"abilities":[{
"name": ".CalleeAbility",
......@@ -377,77 +375,75 @@ For the callee ability, implement the callback to receive data and the methods t
```ts
import Ability from '@ohos.app.ability.UIAbility';
```
3. Define the agreed sequenceable data.
The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string.
The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string.
```ts
export default class MySequenceable {
num: number = 0;
str: string = "";
num: number = 0
str: string = ""
constructor(num, string) {
this.num = num;
this.str = string;
this.num = num
this.str = string
}
marshalling(messageParcel) {
messageParcel.writeInt(this.num);
messageParcel.writeString(this.str);
return true;
messageParcel.writeInt(this.num)
messageParcel.writeString(this.str)
return true
}
unmarshalling(messageParcel) {
this.num = messageParcel.readInt();
this.str = messageParcel.readString();
return true;
this.num = messageParcel.readInt()
this.str = messageParcel.readString()
return true
}
}
```
4. Implement **Callee.on** and **Callee.off**.
In the following example, the **MSG_SEND_METHOD** listener is registered in **onCreate()** of the ability and deregistered in **onDestroy()**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements.
```ts
const TAG: string = '[CalleeAbility]';
const MSG_SEND_METHOD: string = 'CallSendMsg';
function sendMsgCallback(data) {
console.info('CalleeSortFunc called');
// Obtain the sequenceable data sent by the caller ability.
let receivedData = new MySequenceable(0, '');
data.readSequenceable(receivedData);
console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);
// Process the data.
// Return the sequenceable data result to the caller ability.
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) {
console.info(`${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)}`);
}
}
}
```
In the following example, the **MSG_SEND_METHOD** listener is registered in **onCreate()** of the ability and deregistered in **onDestroy()**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements.
```ts
const TAG: string = '[CalleeAbility]'
const MSG_SEND_METHOD: string = 'CallSendMsg'
function sendMsgCallback(data) {
console.info('CalleeSortFunc called')
// Obtain the sequenceable data sent by the caller ability.
let receivedData = new MySequenceable(0, '')
data.readSequenceable(receivedData)
console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`)
// Process the data.
// Return the sequenceable data result to the caller ability.
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) {
console.info(`${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)}`)
}
}
}
```
4. Obtain the caller object and access the callee ability.
1. Import the **UIAbility** module.
......@@ -457,14 +453,13 @@ For the callee ability, implement the callback to receive data and the methods t
2. Obtain the caller object.
The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the caller object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements.
The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the caller object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements.
```ts
async onButtonGetRemoteCaller() {
var caller = undefined;
var context = this.context;
var caller = undefined
var context = this.context
context.startAbilityByCall({
deviceId: getRemoteDeviceId(),
......@@ -472,23 +467,22 @@ For the callee ability, implement the callback to receive data and the methods t
abilityName: 'CalleeAbility'
}).then((data) => {
if (data != null) {
caller = data;
console.info('get remote caller success');
caller = data
console.info('get remote caller success')
// Register the onRelease() listener of the caller ability.
caller.onRelease((msg) => {
console.info(`remote caller onRelease is called ${msg}`);
console.info(`remote caller onRelease is called ${msg}`)
})
console.info('remote caller register OnRelease succeed');
console.info('remote caller register OnRelease succeed')
}
}).catch((error) => {
console.error(`get remote caller failed with ${error}`);
console.error(`get remote caller failed with ${error}`)
})
}
```
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned).
```
```
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned).
5. Sends agreed sequenceable data to the callee ability.
1. The sequenceable data can be sent to the callee ability with or without a return value. The method and sequenceable data must be consistent with those of the callee ability. The following example describes how to send data to the callee ability.
......
......@@ -31,4 +31,3 @@ Every mission retains a snapshot of the UIAbility instance. After the UIAbility
>
> The **specified** mode is supported in the stage model only.
<!--no_check-->
\ No newline at end of file
......@@ -33,4 +33,4 @@ To enable an ability to be called by any application, configure the **config.jso
```
If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#interpretation-of-implicit-want-matching-rules) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant.
If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant.
......@@ -14,4 +14,3 @@ Similar to a PageAbility, a ServiceAbility is configured in **abilities** under
For details about the configuration items, see [Internal Structure of module](../quick-start/module-structure.md).
<!--no_check-->
\ No newline at end of file
......@@ -293,4 +293,3 @@ The ServiceExtensionAbility component returns an IRemoteObject in the **onConnec
})
```
<!--no_check-->
\ No newline at end of file
......@@ -17,7 +17,7 @@ The following figure shows the basic concepts used in the stage model.
- ExtensionAbility is oriented to specific scenarios. You cannot derive directly from ExtensionAbility. Instead, use the derived classes of ExtensionAbility for your scenarios, such as FormExtensionAbility for widget scenarios, InputMethodExtensionAbility for input method scenarios, and WorkSchedulerExtensionAbility for Work Scheduled task scenarios. For example, to enable a user to create an application widget on the home screen, you must derive FormExtensionAbility, implement the callback functions, and configure the capability in the configuration file. The derived class instances are created by developers and their lifecycles are managed by the system. In the stage model, you must use the derived classes of ExtensionAbility to develop custom services based on your service scenarios.
- [WindowStage](../windowmanager/application-window-stage.md)
Each UIAbility class instance is bound to a WindowStage class instance, which functions as the window manager in the application process. The WindowStage class instance contains a main window. That is, UIAbility holds a window through WindowStage, and this window provides an area for ArkUI to render.
Each UIAbility class instance is bound to a WindowStage class instance, which functions as the window manager in the application process. The WindowStage class instance contains a main window. That is, UIAbility holds a main window through WindowStage, and this window provides an area for ArkUI to render.
- [Context](application-context-stage.md)
......@@ -32,12 +32,12 @@ The following figure shows the basic concepts used in the stage model.
During application development based on the stage model, the following tasks are involved in the application model.
**Table 1** Stage model development process
**Table 1** Stage model development process
| Task| Introduction| Guide|
| -------- | -------- | -------- |
| Application component development| Use the UIAbility and ExtensionAbility components of the stage model to develop applications.| - [Application- or Component-Level Configuration](application-component-configuration-stage.md)<br>- [UIAbility Component](uiability-overview.md)<br>- [ExtensionAbility Component](extensionability-overview.md)<br>- [AbilityStage Container Component](abilitystage.md)<br>- [Context](application-context-stage.md)<br>- [Component Startup Rules](component-startup-rules.md) |
| Application component development| Use the UIAbility and ExtensionAbility components of the stage model to develop applications.| - [Application- or Component-Level Configuration](application-component-configuration-stage.md)<br>- [UIAbility Component](uiability-overview.md)<br>- [ExtensionAbility Component](extensionability-overview.md)<br>- [AbilityStage Container Component](abilitystage.md)<br>- [Context](application-context-stage.md)<br>- [Component Startup Rules](component-startup-rules.md)|
| Inter-process communication (IPC)| Learn the process model and common IPC modes of the stage model.| - [Common Events](common-event-overview.md)<br>- [Background Services](background-services.md)|
| Inter-thread communication| Learn the thread model and common inter-thread communication modes of the stage model.| - [Emitter](itc-with-emitter.md)<br>- [Worker](itc-with-worker.md)|
| Mission management| Learn the basic concepts and typical scenarios of mission management in the stage model.| - [Mission Management Scenarios](mission-management-overview.md)<br>- [Mission Management and Launch Type](mission-management-launch-type.md)<br>- [Page Stack and MissionList](page-mission-stack.md) |
| Application configuration file| Learn the requirements for developing application configuration files in the stage model.| [Application Configuration File](config-file-stage.md) |
| Mission management| Learn the basic concepts and typical scenarios of mission management in the stage model.| - [Mission Management Scenarios](mission-management-overview.md)<br>- [Mission Management and Launch Type](mission-management-launch-type.md)<br>- [Page Stack and Mission List](page-mission-stack.md)|
| Application configuration file| Learn the requirements for developing application configuration files in the stage model.| [Application Configuration File](config-file-stage.md)|
......@@ -22,7 +22,7 @@ import featureAbility from '@ohos.ability.featureAbility'
want: {
bundleName: "com.example.myapplication",
moduleName: "entry",
abilityName: "com.example.myapplication.MainAbility"
abilityName: "com.example.myapplication.EntryAbility"
}
}
await featureAbility.startAbility(param)
......
......@@ -12,7 +12,7 @@ import featureAbility from '@ohos.ability.featureAbility';
async function restartAbility() {
let wantInfo = {
bundleName: "com.sample.MyApplication",
abilityName: "MainAbility",
abilityName: "EntryAbility",
parameters: {
page: "pages/second"
}
......@@ -89,7 +89,7 @@ struct Index {
featureAbility.startAbility({
want: {
bundleName: "com.exm.myapplication",
abilityName: "com.exm.myapplication.MainAbility",
abilityName: "com.exm.myapplication.EntryAbility",
parameters: { page: "pages/page1" }
}
}).then((data) => {
......@@ -104,7 +104,7 @@ struct Index {
featureAbility.startAbility({
want: {
bundleName: "com.exm.myapplication",
abilityName: "com.exm.myapplication.MainAbility",
abilityName: "com.exm.myapplication.EntryAbility",
parameters: { page: "pages/page2" }
}
}).then((data) => {
......
......@@ -9,23 +9,23 @@ This topic describes how the two application components of the stage model start
A UIAbility starts a PageAbility in the same way as it starts another UIAbility.
```ts
import UIAbility from '@ohos.app.ability.UIAbility'
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends UIAbility {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate")
console.info("EntryAbility onCreate")
}
onDestroy() {
console.info("MainAbility onDestroy")
console.info("EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
console.info("EntryAbility onWindowStageCreate")
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
let want = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
abilityName: "EntryAbility",
};
this.context.startAbility(want).then(() => {
console.info('Start Ability successfully.');
......@@ -34,13 +34,13 @@ export default class MainAbility extends UIAbility {
});
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
console.info("EntryAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
console.info("EntryAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
console.info("EntryAbility onBackground")
}
}
```
......@@ -54,23 +54,23 @@ A UIAbility starts a PageAbility through **startAbilityForResult()** in the same
```ts
import UIAbility from '@ohos.app.ability.UIAbility'
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends UIAbility {
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate")
console.info("EntryAbility onCreate")
}
onDestroy() {
console.info("MainAbility onDestroy")
console.info("EntryAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
console.info("EntryAbility onWindowStageCreate")
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
let want = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
abilityName: "EntryAbility",
};
this.context.startAbilityForResult(want).then((result) => {
console.info('Ability verify result: ' + JSON.stringify(result));
......@@ -79,13 +79,13 @@ export default class MainAbility extends UIAbility {
});
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
console.info("EntryAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
console.info("EntryAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
console.info("EntryAbility onBackground")
}
}
```
......@@ -110,7 +110,7 @@ export default class ServiceExtension extends Extension {
console.info("ServiceExtension onRequest")
let wantFA = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
abilityName: "EntryAbility",
};
this.context.startAbility(wantFA).then(() => {
console.info('Start Ability successfully.');
......
......@@ -97,13 +97,13 @@ function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) {
let list = dmClass.getTrustedDeviceListSync();
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.info("MainAbility onButtonClick getRemoteDeviceId err: list is null");
console.info("EntryAbility onButtonClick getRemoteDeviceId err: list is null");
return;
}
console.info("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
console.info("EntryAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
return list[0].deviceId;
} else {
console.info("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
console.info("EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null");
}
}
```
......
......@@ -14,7 +14,7 @@ import featureAbility from '@ohos.ability.featureAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
abilityName: "com.ohos.stage.EntryAbility"
}
};
featureAbility.startAbility(parameter).then((code) => {
......@@ -38,7 +38,7 @@ import featureAbility from '@ohos.ability.featureAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
abilityName: "com.ohos.stage.EntryAbility"
}
};
featureAbility.startAbilityForResult(parameter).then((result) => {
......@@ -60,7 +60,7 @@ import particleAbility from '@ohos.ability.particleAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
abilityName: "com.ohos.stage.EntryAbility"
}
};
particleAbility.startAbility(parameter).then(() => {
......
# Interaction Intra-Device Between UIAbility Components
# Intra-Device Interaction Between UIAbility Components
UIAbility is the minimum unit that can be scheduled by the system. Jumping between functional modules in a device involves starting of specific UIAbility components, which belong to the same or a different application (for example, starting UIAbility of a third-party payment application).
......@@ -50,7 +50,7 @@ Assume that your application has two UIAbility components: EntryAbility and Func
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class FuncAbility extends UIAbility {
onCreate(want, launchParam) {
......@@ -196,6 +196,7 @@ This section describes how to start the UIAbility of another application through
```
The following figure shows the effect. When you click **Open PDF**, a dialog box is displayed for you to select.
<img src="figures/uiability-intra-device-interaction.png" alt="uiability-intra-device-interaction" style="zoom:50%;" />
3. To stop the **UIAbility** instance after the document application is used, call **terminateSelf()**.
......@@ -442,7 +443,8 @@ Ability call is usually used in the following scenarios:
The following figure shows the ability call process.
Figure 1 Ability call process
**Figure 1** Ability call process
<img src="figures/call.png" alt="call" style="zoom:67%;" />
- The caller ability uses **startAbilityByCall** to obtain a caller object and uses **call()** of the caller object to send data to the callee ability.
......@@ -461,7 +463,7 @@ Figure 1 Ability call process
The following table describes the main APIs used for the ability call. For details, see [AbilityContext](../reference/apis/js-apis-app-ability-uiAbility.md#caller).
**Table 2** Ability call APIs
**Table 2** Ability call APIs
| API| Description|
| -------- | -------- |
......@@ -486,8 +488,7 @@ For the callee ability, implement the callback to receive data and the methods t
1. Configure the ability launch type.
Set **launchType** of the callee ability to **singleton** in the **module.json5** file.
Set **launchType** of the callee ability to **singleton** in the **module.json5** file.
| JSON Field| Description|
| -------- | -------- |
......@@ -595,9 +596,9 @@ An example of the ability configuration is as follows:
2. Obtain the caller interface.
The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the caller object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements.
```ts
// Register the onRelease() listener of the caller ability.
private regOnRelease(caller) {
......
......@@ -18,6 +18,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility
Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, if a UIAbility instance of this type already exists in the application process, the instance is reused. Therefore, only one UIAbility instance of this type exists in the system, that is, displayed in **Recents**.
**Figure 1** Demonstration effect in singleton mode
<img src="figures/uiability-launch-type1.png" alt="uiability-launch-type1" width="40%;" />
> **NOTE**
......@@ -47,6 +48,7 @@ To use the singleton mode, set **launchType** in the [module.json5 configuration
In standard mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**.
**Figure 2** Demonstration effect in standard mode
<img src="figures/standard-mode.png" alt="standard-mode" width="40%;" />
To use the standard mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **standard**.
......@@ -72,6 +74,7 @@ To use the standard mode, set **launchType** in the [module.json5 configuration
The **specified** mode is used in some special scenarios. For example, in a document application, you want a document instance to be created each time you create a document, but you want to use the same document instance when you repeatedly open an existing document.
**Figure 3** Demonstration effect in specified mode
<img src="figures/uiability-launch-type2.png" alt="uiability-launch-type2" style="zoom:50%;" />
For example, there are EntryAbility and SpecifiedAbility, and the launch type of SpecifiedAbility is set to **specified**. You are required to start SpecifiedAbility from EntryAbility.
......@@ -93,7 +96,7 @@ For example, there are EntryAbility and SpecifiedAbility, and the launch type of
```
2. Before a UIAbility instance is created, you can create a unique string key for the instance. The key is bound to the UIAbility instance when it is created. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application is asked which UIAbility instance is used to respond to the [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) request.
In EntryAbility, add a custom parameter, for example, **instanceKey**, to the **want** parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instances.
In EntryAbility, add a custom parameter, for example, **instanceKey**, to the [want](want-overview.md) parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instances.
```ts
// Configure an independent key for each UIAbility instance.
......@@ -146,7 +149,8 @@ For example, there are EntryAbility and SpecifiedAbility, and the launch type of
For example, in the document application, different key values are bound to different document instances. Each time a document is created, a new key value (for example, file path) is passed, and a new UIAbility instance is created when UIAbility is started in AbilityStage. However, when you open an existing document, the same UIAbility instance is started again in AbilityStage.
The following steps are used as an example.
The following steps are used as an example.
1. Open file A. A UIAbility instance, for example, UIAbility instance 1, is started.
2. Close the process of file A in **Recents**. UIAbility instance 1 is destroyed. Return to the home screen and open file A again. A new UIAbility instance is started, for example, UIAbility instance 2.
......
......@@ -7,7 +7,7 @@ When a user opens, switches, and returns to an application, the UIAbility instan
The lifecycle of UIAbility has four states: **Create**, **Foreground**, **Background**, and **Destroy**, as shown in the figure below.
**Figure 1** UIAbility lifecycle states
**Figure 1** UIAbility lifecycle states
<img src="figures/Ability-Life-Cycle.png" alt="Ability-Life-Cycle" style="zoom:50%;" />
......@@ -21,7 +21,7 @@ The **Create** state is triggered when the UIAbility instance is created during
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
......@@ -36,14 +36,14 @@ export default class EntryAbility extends UIAbility {
After the UIAbility instance is created but before it enters the **Foreground** state, the system creates a WindowStage instance and triggers the **onWindowStageCreate()** callback. You can set UI loading and WindowStage event subscription in the callback.
**Figure 2** WindowStageCreate and WindowStageDestory
**Figure 2** WindowStageCreate and WindowStageDestory
<img src="figures/Ability-Life-Cycle-WindowStage.png" alt="Ability-Life-Cycle-WindowStage" style="zoom:50%;" />
In the **onWindowStageCreate()** callback, use [loadContent()](../reference/apis/js-apis-window.md#loadcontent9-2) to set the page to be loaded, and call [on('windowStageEvent')](../reference/apis/js-apis-window.md#onwindowstageevent9) to subscribe to [WindowStage events](../reference/apis/js-apis-window.md#windowstageeventtype9), for example, having or losing focus, or becoming visible or invisible.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
// ...
......@@ -77,7 +77,7 @@ Before the UIAbility instance is destroyed, the **onWindowStageDestroy()** callb
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
// ...
......@@ -135,7 +135,7 @@ The UIAbility instance is destroyed when **terminateSelf()** is called or the us
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
// ...
......
......@@ -37,4 +37,3 @@ To enable an application to properly use a UIAbility component, declare the UIAb
>
> For the ability composition, see [Adding an Ability to a Module](https://developer.harmonyos.com/en/docs/documentation/doc-guides-V3/ohos-adding-ability-0000001218280664-V3).
<!--no_check-->
\ No newline at end of file
......@@ -11,10 +11,10 @@ If no startup page is specified, a white screen occurs after the application is
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: Window.WindowStage) {
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created. Set a main page for this ability.
windowStage.loadContent('pages/Index', (err, data) => {
// ...
......
......@@ -23,7 +23,7 @@
```
- **Implicit Want**: A type of Want with **abilityName** unspecified when starting the ability.
Implicit Want can be used when the object used to process the request is unclear and the current application wants to use a capability (defined by the [skills tag](../quick-start/module-configuration-file.md#skills-tag)) provided by another application. For example, you can use implicit Want to describe a request for opening a link, since you do not care which application is used to open the link. The system matches all applications that support the request.
Implicit Want can be used when the object used to process the request is unclear and the current application wants to use a capability (defined by the [skills tag](../quick-start/module-configuration-file.md#skills)) provided by another application. For example, you can use implicit Want to describe a request for opening a link, since you do not care which application is used to open the link. The system matches all applications that support the request.
```ts
......@@ -47,5 +47,3 @@
> - If the **want** parameter passed does not contain **abilityName** or **bundleName**, the ServiceExtensionAbility components of all applications cannot be started through implicit Want.
>
> - If the **want** parameter passed contains **bundleName**, the **startServiceExtensionAbility()** method can be used to implicitly start ServiceExtensionAbility. By default, ServiceExtensionAbility with the highest priority is returned. If all the matching ServiceExtensionAbility components have the same priority, the first ServiceExtensionAbility is returned.
<!--no_check-->
\ No newline at end of file
......@@ -184,7 +184,7 @@ The widget configuration file is named **config.json**. Find the **config.json**
| type | Type of the JavaScript component. The value can be:<br>**normal**: indicates an application instance.<br>**form**: indicates a widget instance.| String| Yes (initial value: **normal**)|
| mode | Development mode of the JavaScript component.| Object| Yes (initial value: left empty)|
A configuration example is as follows:
Example configuration:
```json
......@@ -211,14 +211,14 @@ The widget configuration file is named **config.json**. Find the **config.json**
| 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.<br>**true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.<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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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 attribute does not take effect.<br>If the value is a positive integer *N*, the interval is calculated by multiplying *N* and 30 minutes.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number| Yes (initial value: **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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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)|
| jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes.| String| No|
| metaData | Metadata of the widget. This attribute contains the array of the **customizeData** attribute.| Object| 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)|
| customizeData | Custom information about the widget.| Object array| Yes (initial value: left empty)|
A configuration example is as follows:
Example configuration:
```json
......@@ -232,11 +232,11 @@ The widget configuration file is named **config.json**. Find the **config.json**
"type": "service",
"srcLanguage": "ets",
"formsEnabled": true,
"formConfigAbility": "ability://com.example.entry.MainAbility",
"formConfigAbility": "ability://com.example.entry.EntryAbility",
"forms": [{
"colorMode": "auto",
"defaultDimension": "2*2",
"description": "This is a service widget.",
"description": "This is a widget.",
"formVisibleNotify": true,
"isDefault": true,
"jsComponentName": "widget",
......@@ -282,7 +282,7 @@ async function storeFormInfo(formId: string, formName: string, tempFlag: boolean
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 instance acquisition and update.
// Persistently store widget data for subsequent use, such as instance acquisition and update.
// Implement this API based on project requirements.
storeFormInfo(formId, formName, tempFlag);
......@@ -325,7 +325,7 @@ async function deleteFormInfo(formId: string) {
For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
The **Want** object passed by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
- Normal widget: a widget persistently used by the widget host
......@@ -434,7 +434,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.entry.MainAbility",
"abilityName": "com.example.entry.EntryAbility",
"params": {
"message": "add detail"
}
......@@ -451,12 +451,12 @@ You can set router and message events for components on a widget. The router eve
1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file.
2. Set the router event.
- **action**: **router**, which indicates a router event.
- **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default MainAbility name of the FA model created by DevEco Studio is com.example.entry.MainAbility.
- **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
- **action**: **"router"**, which indicates a router event.
- **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name created by DevEco Studio in the FA model is com.example.entry.EntryAbility.
- **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the EntryAbility in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
3. Set the message event.
- **action**: **message**, which indicates a message event.
- **action**: **"message"**, which indicates a message event.
- **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**.
The following is an example:
......@@ -529,7 +529,7 @@ The following is an example:
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.entry.MainAbility",
"abilityName": "com.example.entry.EntryAbility",
"params": {
"message": "add detail"
}
......
......@@ -181,7 +181,7 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo
### Configuring the Widget Configuration File
1. Configure ExtensionAbility information under **extensionAbilities** in the [module.json5 file](../quick-start/module-configuration-file.md). For a FormExtensionAbility, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information.
A configuration example is as follows:
Example configuration:
```json
......@@ -222,19 +222,19 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo
| 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.<br>**true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.<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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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 attribute does not take effect.<br>If the value is a positive integer *N*, the interval is calculated by multiplying *N* and 30 minutes.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number| Yes (initial value: **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.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| 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 attribute contains the array of the **customizeData** attribute.| Object| 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:
Example configuration:
```json
{
"forms": [
{
"name": "widget",
"description": "This is a service widget.",
"description": "This is a widget.",
"src": "./js/widget/pages/index/index",
"window": {
"designWidth": 720,
......@@ -288,7 +288,7 @@ export default class EntryFormAbility extends FormExtension {
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 instance acquisition and update.
// Persistently store widget data for subsequent use, such as instance acquisition and update.
// Implement this API based on project requirements.
storeFormInfo(formId, formName, tempFlag);
......@@ -334,7 +334,7 @@ export default class EntryFormAbility extends FormExtension {
For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
The **Want** object passed by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
- Normal widget: a widget persistently used by the widget host
......@@ -462,12 +462,12 @@ The key steps are as follows:
1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file.
2. Set the router event.
- **action**: **router**, which indicates a router event.
- **action**: **"router"**, which indicates a router event.
- **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name of the stage model created by DevEco Studio is EntryAbility.
- **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field.
3. Set the message event.
- **action**: **message**, which indicates a message event.
- **action**: **"message"**, which indicates a message event.
- **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onFormEvent()**.
The following is an example:
......@@ -597,4 +597,3 @@ The following is an example:
};
```
<!--no_check-->
\ No newline at end of file
......@@ -42,7 +42,7 @@ arkXtest is divided into two parts: unit test framework and UI test framework.
- The feature availability of the unit test framework varies by version. For details about the mappings between the features and versions, see [arkXtest](https://gitee.com/openharmony/testfwk_arkxtest/blob/master/README_en.md).
## Environment preparations
## Preparing the Environment
### Environment Requirements
......@@ -72,7 +72,7 @@ export default function abilityTest() {
it('testUiExample',0, async function (done) {
console.info("uitest: TestUiExample begin");
//start tested ability
await delegator.executeShellCommand('aa start -b com.ohos.uitest -a MainAbility').then(result =>{
await delegator.executeShellCommand('aa start -b com.ohos.uitest -a EntryAbility').then(result =>{
console.info('Uitest, start ability finished:' + result)
}).catch(err => {
console.info('Uitest, start ability failed: ' + err)
......@@ -81,7 +81,7 @@ export default function abilityTest() {
//check top display ability
await delegator.getCurrentTopAbility().then((Ability)=>{
console.info("get top ability");
expect(Ability.context.abilityInfo.name).assertEqual('MainAbility');
expect(Ability.context.abilityInfo.name).assertEqual('EntryAbility');
})
done();
})
......@@ -119,7 +119,7 @@ export default function abilityTest() {
it('testUiExample',0, async function (done) {
console.info("uitest: TestUiExample begin");
//start tested ability
await delegator.executeShellCommand('aa start -b com.ohos.uitest -a MainAbility').then(result =>{
await delegator.executeShellCommand('aa start -b com.ohos.uitest -a EntryAbility').then(result =>{
console.info('Uitest, start ability finished:' + result)
}).catch(err => {
console.info('Uitest, start ability failed: ' + err)
......@@ -128,7 +128,7 @@ export default function abilityTest() {
//check top display ability
await delegator.getCurrentTopAbility().then((Ability)=>{
console.info("get top ability");
expect(Ability.context.abilityInfo.name).assertEqual('MainAbility');
expect(Ability.context.abilityInfo.name).assertEqual('EntryAbility');
})
//ui test code
//init uidriver
......@@ -154,20 +154,173 @@ export default function abilityTest() {
## Running the Test Script
### In DevEco Studio
You can run a test script in DevEco Studio in any of the following modes:
- Test package level: All test cases in the test package are executed.
- Test suite level: All test cases defined in the **describe** method are executed.
- Test method level: The specified **it** method, that is, a single test case, is executed.
1. Test package level: All test cases in the test package are executed.
2. Test suite level: All test cases defined in the **describe** method are executed.
3. Test method level: The specified **it** method, that is, a single test case, is executed.
![](figures/Execute.PNG)
## Viewing the Test Result
**Viewing the Test Result**
After the test is complete, you can view the test result in DevEco Studio, as shown in the following figure.
![](figures/TestResult.PNG)
### In the CLI
To run a test script in the CLI, execute **aa** commands with different execution control keywords.
Parameters in aa test commands
| Keyword | Abbreviation| Description | Example |
| ------------- | ------------ | -------------------------------------- | ---------------------------------- |
| --bundleName | -b | Application bundle name. | - b com.test.example |
| --packageName | -p | Application module name, which is applicable to applications developed in the FA model. | - p com.test.example.entry |
| --moduleName | -m | Application module name, which is applicable to applications developed in the stage model. | -m entry |
| NA | -s | \<key, value> pair.| - s unittest OpenHarmonyTestRunner |
The framework supports multiple test case execution modes, which are triggered by the key-value pair following the **-s** keyword. The table below lists the available keys and values.
| Key | Description | Value | Parameter |
| ------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------- |
| unittest | OpenHarmonyTestRunner object used for test case execution. | **OpenHarmonyTestRunner** or custom runner name. | - s unittest OpenHarmonyTestRunner |
| class | Test suite or test case to be executed. | {describeName}#{itName}, {describeName} | -s class attributeTest#testAttributeIt |
| notClass | Test suite or test case that does not need to be executed. | {describeName}#{itName}, {describeName} | -s notClass attributeTest#testAttributeIt |
| itName | Test case to be executed. | {itName} | -s itName testAttributeIt |
| timeout | Timeout interval for executing a test case. | Positive integer (unit: ms). If no value is set, the default value 5000 is used. | -s timeout 15000 |
| breakOnError | Whether to enable break-on-error mode. When this mode is enabled, the test execution process exits if a test assertion error or any other error occurs.| **true**/**false** (default value) | -s breakOnError true |
| testType | Type of the test case to be executed. | function, performance, power, reliability, security, global, compatibility, user, standard, safety, resilience| -s testType function |
| level | Level of the test case to be executed. | 0, 1, 2, 3, 4 | -s level 0 |
| size | Size of the test case to be executed. | small, medium, large | -s size small |
**Running Commands**
Configure hdc-related environment variables, and then perform the following:
- Open the CLI.
- Run the **aa test** commands.
Example 1: Execute all test cases.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner
```
Example 2: Execute cases in the specified test suites, separated by commas (,).
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s class s1,s2
```
Example 3: Execute specified cases in the specified test suites, separated by commas (,).
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s class testStop#stop_1,testStop1#stop_0
```
Example 4: Execute all test cases except the specified ones, separated by commas (,).
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s notClass testStop
```
Example 5: Execute specified test cases, separated by commas (,).
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s itName stop_0
```
Example 6: Set the timeout interval for executing a test case.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s timeout 15000
```
Example 7: Enable break-on-error mode.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s breakOnError true
```
Example 8: Execute test cases of the specified type.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s testType function
```
Example 9: Execute test cases at the specified level.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s level 0
```
Example 10: Execute test cases with the specified level.
```shell
hdc shell aa test -b xxx -p xxx -s unittest OpenHarmonyTestRunner -s size small
```
**Viewing the Test Result**
- During test execution in the CLI, the log information similar to the following is displayed:
```
OHOS_REPORT_STATUS: class=testStop
OHOS_REPORT_STATUS: current=1
OHOS_REPORT_STATUS: id=JS
OHOS_REPORT_STATUS: numtests=447
OHOS_REPORT_STATUS: stream=
OHOS_REPORT_STATUS: test=stop_0
OHOS_REPORT_STATUS_CODE: 1
OHOS_REPORT_STATUS: class=testStop
OHOS_REPORT_STATUS: current=1
OHOS_REPORT_STATUS: id=JS
OHOS_REPORT_STATUS: numtests=447
OHOS_REPORT_STATUS: stream=
OHOS_REPORT_STATUS: test=stop_0
OHOS_REPORT_STATUS_CODE: 0
OHOS_REPORT_STATUS: consuming=4
```
| Log Field | Description |
| ------- | -------------------------|
| OHOS_REPORT_SUM | Total number of test cases in the current test suite.|
| OHOS_REPORT_STATUS: class | Name of the test suite that is being executed.|
| OHOS_REPORT_STATUS: id | Case execution language. The default value is JS. |
| OHOS_REPORT_STATUS: numtests | Total number of test cases in the test package.|
| OHOS_REPORT_STATUS: stream | Error information of the current test case.|
| OHOS_REPORT_STATUS: test| Name of the current test case.|
| OHOS_REPORT_STATUS_CODE | Execution result of the current test case. The options are as follows:<br>**0**: pass<br>**1**: error<br>**2**: fail|
| OHOS_REPORT_STATUS: consuming | Execution duration of the current test case.|
- After the commands are executed, the log information similar to the following is displayed:
```
OHOS_REPORT_RESULT: stream=Tests run: 447, Failure: 0, Error: 1, Pass: 201, Ignore: 245
OHOS_REPORT_CODE: 0
OHOS_REPORT_RESULT: breakOnError model, Stopping whole test suite if one specific test case failed or error
OHOS_REPORT_STATUS: taskconsuming=16029
```
| Log Field | Description |
| ------------------| -------------------------|
| run | Total number of test cases in the current test package.|
| Failure | Number of failed test cases.|
| Error | Number of test cases whose execution encounters errors. |
| Pass | Number of passed test cases.|
| Ignore | Number of test cases not executed.|
| taskconsuming| Total time spent in executing the current test case.|
> When an error occurs in break-on-error mode, check the **Ignore** and interrupt information.
## FAQs
### FAQs About Unit Test Cases
......@@ -182,7 +335,7 @@ The logs added to the test case are displayed after the test case execution, rat
More than one asynchronous interface is called in the test case.<br>In principle, logs in the test case are printed before the test case execution is complete.
**Solution**
**Solution**
If more than one asynchronous interface is called, you are advised to encapsulate the interface invoking into the promise mode
......@@ -209,14 +362,18 @@ After the test case execution is complete, the console displays the error messag
**Possible Causes**
1. The test case is executed through an asynchronous interface, but the **done** function is not executed during the execution. As a result, the test case execution does not end until it times out.
2. The time taken for API invocation is longer than the timeout interval set for test case execution.
2. The time taken for API invocation is longer than the timeout interval set for test case execution.
3. Test assertion fails, and a failure exception is thrown. As a result, the test case execution does not end until the timeout expires.
**Solution**
1. Check the code logic of the test case to ensure that the **done** function is executed even if the assertion fails.
2. Modify the case execution timeout settings under **Run/Debug Configurations** in DevEco Studio.
2. Modify the case execution timeout settings under **Run/Debug Configurations** in DevEco Studio.
3. Check the code logic and assertion result of the test case and make sure that the assertion is passed.
### FAQs About UI Test Cases
#### The failure log contains "Get windows failed/GetRootByWindow failed"
......
# IPC & RPC Development<a name="EN-US_TOPIC_0000001103710988"></a>
# IPC & RPC Development Guidelines
## When to Use<a name="section18502174174019"></a>
## When to Use
IPC/RPC enables a proxy and a stub that run on different processes to communicate with each other, regardless of whether they run on the same or different devices.
## Available APIs<a name="section1633115419401"></a>
**Table 1** Native IPC APIs
## Available APIs
| Class/Interface | Function | Description |
| --------------- | -------- | ----------- |
| [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr<IRemoteObject> AsObject() | Obtains the holder of a remote proxy object. This method must be implemented by the derived classes of **IRemoteBroker**. If you call this method on the stub, the **RemoteObject** is returned; if you call this method on the proxy, the proxy object is returned. |
| IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) | Called to process a request from the proxy and return the result. Derived classes need to override this method. |
| IRemoteProxy | | Service proxy classes are derived from the **IRemoteProxy** class. |
Table 1 Native IPC APIs
## How to Develop<a name="section4207112818418"></a>
| Class| API| Description|
| -------- | -------- | -------- |
| [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr&lt;IRemoteObject&gt; AsObject() | Holder of a remote proxy object. If you call this API on the stub, the **RemoteObject** is returned; if you call this API on the proxy, the proxy object is returned.|
| IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &amp;data, MessageParcel &amp;reply, MessageOption &amp;option) | Callback used to process a request from the proxy and return the result. Derived classes need to override this API.|
| IRemoteProxy | | Service proxy class, which is derived from the **IRemoteProxy** class.|
**Using Native APIs**
1. Define the IPC interface **ITestAbility**.
## How to Develop
**ITestAbility** inherits the IPC base class **IRemoteBroker** and defines descriptors, functions, and message code. The functions need to be implemented on both the proxy and stub.
### **Using Native APIs**
```
class ITestAbility : public IRemoteBroker {
public:
1. Add dependencies.
SDK dependency:
```
#IPC scenario
external_deps = [
"ipc:ipc_single",
]
#RPC scenario
external_deps = [
"ipc:ipc_core",
]
```
In addition, the refbase implementation on which IPC/RPC depends is stored in **//utils**. Add the dependency on the Utils source code.
```
external_deps = [
"c_utils:utils",
]
```
2. Define the IPC interface **ITestAbility**.
**ITestAbility** inherits the IPC base class **IRemoteBroker** and defines descriptors, functions, and message code. The functions need to be implemented on both the proxy and stub.
```c++
#include "iremote_broker.h"
// Define message codes.
const int TRANS_ID_PING_ABILITY = 5
const std::string DESCRIPTOR = "test.ITestAbility";
class ITestAbility : public IRemoteBroker {
public:
// DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string.
DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility");
int TRANS_ID_PING_ABILITY = 1; // Define the message code.
DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions.
};
```
};
```
2. Define and implement service provider **TestAbilityStub**.
3. Define and implement service provider **TestAbilityStub**.
This class is related to the IPC framework and needs to inherit **IRemoteStub<ITestAbility\>**. You need to override **OnRemoteRequest** on the stub to receive requests from the proxy.
This class is related to the IPC framework and needs to inherit **IRemoteStub&lt;ITestAbility&gt;**. You need to override **OnRemoteRequest** on the stub to receive requests from the proxy.
```
class TestAbilityStub : public IRemoteStub<ITestAbility> {
public:
virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
int TestPingAbility(const std::u16string &dummy) override;
```c++
#include "iability_test.h"
#include "iremote_stub.h"
class TestAbilityStub : public IRemoteStub<ITestAbility> {
public:
virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
int TestPingAbility(const std::u16string &dummy) override;
};
int TestServiceStub::OnRemoteRequest(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
switch (code) {
case TRANS_ID_PING_ABILITY: {
std::u16string dummy = data.ReadString16();
int result = TestPingAbility(dummy);
reply.WriteInt32(result);
return 0;
}
default:
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
}
```
3. Define the **TestAbility** class that implements functions for the stub.
```
class TestAbility : public TestAbilityStub {
public:
int TestPingAbility(const std::u16string &dummy);
}
int TestAbility::TestPingAbility(const std::u16string &dummy) {
return 0;
}
```
4. Define and implement **TestAbilityProxy**.
This class is implemented on the proxy and inherits **IRemoteProxy<ITestAbility\>**. You can call **SendRequest** to send a request to the stub and expose the capabilities provided by the stub.
```
class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
public:
explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
int TestPingService(const std::u16string &dummy) override;
private:
static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
}
TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<ITestAbility>(impl)
{
}
int TestAbilityProxy::TestPingService(const std::u16string &dummy) {
MessageOption option;
MessageParcel dataParcel, replyParcel;
dataParcel.WriteString16(dummy);
int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
return result;
}
```
5. Register and start an SA.
Call **AddSystemAbility** to register the **TestAbilityStub** instance of the SA with **SystemAbilityManager**. The registration parameters vary depending on whether the **SystemAbilityManager** resides on the same device as the SA.
```
// Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
samgr->AddSystemAbility(saId, new TestAbility());
// Register the TestAbilityStub instance with the SystemAbilityManager on a different device.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
ISystemAbilityManager::SAExtraProp saExtra;
saExtra.isDistributed = true; // Set a distributed SA.
int result = samgr->AddSystemAbility(saId, new TestAbility(), saExtra);
```
6. Obtain the SA.
Call the **GetSystemAbility** function of the **SystemAbilityManager** class to obtain the **IRemoteObject** for the SA, and create a **TestAbilityProxy** instance.
```
// Obtain the proxy of the SA registered on the local device.
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type.
// Obtain the proxies of the SAs registered with other devices.
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, deviceId); // deviceId identifies a device.
sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy.
```
int TestAbilityStub::OnRemoteRequest(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
switch (code) {
case TRANS_ID_PING_ABILITY: {
std::u16string dummy = data.ReadString16();
int result = TestPingAbility(dummy);
reply.WriteInt32(result);
return 0;
}
default:
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
}
```
4. Define the **TestAbility** class that implements functions for the stub.
```c++
#include "iability_server_test.h"
class TestAbility : public TestAbilityStub {
public:
int TestPingAbility(const std::u16string &dummy);
}
int TestAbility::TestPingAbility(const std::u16string &dummy) {
return 0;
}
```
5. Define and implement **TestAbilityProxy**.
This class is implemented on the proxy and inherits **IRemoteProxy&lt;ITestAbility&gt;**. You can call **SendRequest** to send a request to the stub and expose the capabilities provided by the stub.
```c++
#include "iability_test.h"
#include "iremote_proxy.h"
#include "iremote_object.h"
class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
public:
explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
int TestPingAbility(const std::u16string &dummy) override;
private:
static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
}
TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<ITestAbility>(impl)
{
}
int TestAbilityProxy::TestPingAbility(const std::u16string &dummy){
MessageOption option;
MessageParcel dataParcel, replyParcel;
dataParcel.WriteString16(dummy);
int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
return result;
}
```
6. Register and start an SA.
Call **AddSystemAbility** to register the **TestAbilityStub** instance of the SA with **SystemAbilityManager**. The registration parameters vary depending on whether the **SystemAbilityManager** resides on the same device as the SA.
```c++
// Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
samgr->AddSystemAbility(saId, new TestAbility());
// Register the TestAbilityStub instance with the SystemAbilityManager on a different device.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
ISystemAbilityManager::SAExtraProp saExtra;
saExtra.isDistributed = true; // Set a distributed SA.
int result = samgr->AddSystemAbility(saId, new TestAbility(), saExtra);
```
7. Obtain the SA.
Call the **GetSystemAbility** function of the **SystemAbilityManager** class to obtain the **IRemoteObject** for the SA, and create a **TestAbilityProxy** instance.
```c++
// Obtain the proxy of the SA registered on the local device.
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type.
// Obtain the proxy of the SA registered with any other devices.
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
// networkId is the device identifier and can be obtained through GetLocalNodeDeviceInfo.
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, networkId);
sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy.
```
### **Using JS APIs**
1. Add dependencies.
```ts
import rpc from "@ohos.rpc"
import featureAbility from "@ohos.ability.featureAbility"
```
2. Bind the desired ability.
Construct the **want** variable, and specify the bundle name and component name of the application where the ability is located. If cross-device communication is involved, also specify the network ID of the target device, which can be obtained through **deviceManager**. Then, construct the **connect** variable, and specify the callback that is called when the binding is successful, the binding fails, or the ability is disconnected. After that, call the API provided by **featureAbility** to bind an ability.
```ts
import rpc from "@ohos.rpc"
import featureAbility from "@ohos.ability.featureAbility"
let proxy = null
let connectId = null
// Bind the ability on a single device.
let want = {
// Enter the bundle name and ability name.
"bundleName": "ohos.rpc.test.server",
"abilityName": "ohos.rpc.test.server.ServiceAbility",
}
let connect = {
onConnect:function(elementName, remote) {
proxy = remote
},
onDisconnect:function(elementName) {
},
onFailed:function() {
proxy = null
}
}
connectId = featureAbility.connectAbility(want, connect)
// If you're binding the ability across devices, use deviceManager to obtain the network ID of the target device.
import deviceManager from '@ohos.distributedHardware.deviceManager'
function deviceManagerCallback(deviceManager) {
let deviceList = deviceManager.getTrustedDeviceListSync()
let networkId = deviceList[0].networkId
let want = {
"bundleName": "ohos.rpc.test.server",
"abilityName": "ohos.rpc.test.service.ServiceAbility",
"networkId": networkId,
"flags": 256
}
connectId = featureAbility.connectAbility(want, connect)
}
// The first parameter specifies the bundle name of the application, and the second parameter specifies the callback used to return the device ID obtained by using DeviceManager.
deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback)
```
3. Process requests sent from the client.
Call the **onConnect** API to return a proxy object inherited from **rpc.RemoteObject** after the ability is successfully bound. Implement the **onRemoteMessageRequest** API for the proxy object to process requests sent from the client.
```ts
onConnect(want: Want) {
var robj:rpc.RemoteObject = new Stub("rpcTestAbility")
return robj
}
class Stub extends rpc.RemoteObject {
constructor(descriptor) {
super(descriptor)
}
onRemoteMessageRequest(code, data, reply, option) {
// Process requests sent from the client based on the code.
return true
}
}
```
4. Process responses sent from the server.
Obtain the proxy object from the **onConnect** callback, call **sendRequestAsync** to send a request, and receive the response using a callback or a promise (an object representing the eventual completion or failure of an asynchronous operation and its result value).
```ts
// Use a promise.
let option = new rpc.MessageOption()
let data = rpc.MessageParcel.create()
let reply = rpc.MessageParcel.create()
// Write parameters to data.
proxy.sendRequestAsync(1, data, reply, option)
.then(function(result) {
if (result.errCode != 0) {
console.error("send request failed, errCode: " + result.errCode)
return
}
// Read the result from result.reply.
})
.catch(function(e) {
console.error("send request got exception: " + e)
}
.finally(() => {
data.reclaim()
reply.reclaim()
})
// Use a callback.
function sendRequestCallback(result) {
try {
if (result.errCode != 0) {
console.error("send request failed, errCode: " + result.errCode)
return
}
// Read the result from result.reply.
} finally {
result.data.reclaim()
result.reply.reclaim()
}
}
let option = new rpc.MessageOption()
let data = rpc.MessageParcel.create()
let reply = rpc.MessageParcel.create()
// Write parameters to data.
proxy.sendRequest(1, data, reply, option, sendRequestCallback)
```
5. Tear down the connection.
Use the API provided by **featureAbility** to tear down the connection when the communication is over.
```ts
import rpc from "@ohos.rpc"
import featureAbility from "@ohos.ability.featureAbility"
function disconnectCallback() {
console.info("disconnect ability done")
}
featureAbility.disconnectAbility(connectId, disconnectCallback)
```
......@@ -3,20 +3,42 @@
## Basic Concepts
Inter-process communication (IPC) and remote procedure call (RPC) are used to implement cross-process communication. IPC uses the Binder driver to implement inter-process communication within a device, whereas RPC uses the intelligent software bus driver to implement inter-process communication across devices.
The inter-process communication (IPC) and remote procedure call (RPC) mechanisms are used to implement cross-process communication. The difference between them lies in that IPC uses the Binder driver to implement cross-process communication within a device, whereas RPC uses the DSoftBus driver to implement cross-process communication across devices.
IPC and RPC generally use the client-server model for communication. The client (service requester) obtains the proxy of the server (service provider) and uses this proxy to read and write data. The server registers system abilities (SAs) with the system ability manager (SAMgr), which manages the SAs and provides interfaces for clients. To interact with an SA, the client must obtain the proxy of the SA from SAMgr.
The reason why cross-process communication is needed is that each process has its own independent resources and memory space and one process is not allowed to access the resources and memory space of other processes. IPC and RPC usually use the client-server model, where the client (service requester, that is, the process that requests a service) obtains the proxy of the server (service provider, that is, the process that provides the service) and uses the proxy to read and write data to implement data communication across processes. More specifically, the client constructs a proxy object of the server. The proxy object has the same functions as the server. To access a certain API of the server, you only need to access the corresponding API in the proxy object. The proxy object sends the request to the server, and the server processes the received request and returns the processing result to the proxy object through the driver. Then, the proxy object forwards the processing result to the client. The server registers system abilities (SAs) with the system ability manager (SAMgr), which manages the SAs and provides APIs for clients. To communicate with a specific SA, the client must obtain the proxy of the SA from SAMgr.
In OpenHarmony documents, proxy represents the service requester, and stub represents the service provider.
In the following sections, proxy represents the service requester, and stub represents the service provider.
![IPC&RPC communication mechanisms](figures/IPC_RPC_communication.PNG)
## Constraints
- The data transmitted for inter-process communication within a device cannot exceed 1 MB. If more data needs to be transmitted, use the anonymous shared memory.
- During cross-process communication within a single device, the maximum amount of data to be transmitted is about 1 MB. If the amount of data to be transmitted exceeds this limit, use the [anonymous shared memory](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-rpc.md#ashmem8).
- Subscription to death notifications of anonymous stub objects (not registered with SAMgr) is prohibited in RPC.
- During cross-process communication across processes, a proxy object cannot be passed back to the device that hosts the stub object pointed by the proxy object. That is, the proxy object pointing to the stub object of the remote device cannot be passed across processes twice on the local device.
## **Recommendations**
First, compile an API class and define message codes in the API class for both communication parties to identify operations. Unimplemented APIs are allowed in the API class because it must be inherited by both communication parties and its inheritance classes cannot be abstract classes. When inheriting the API class, both communication parties must implement the unimplemented APIs, so as to make sure that the inheritance classes are not abstract classes.
Then, implement the API class specific to the stub, and override the **AsObject** and **OnRemoteRequest** APIs. In addition, compile the proxy to implement the APIs in the API class and override the **AsObject** API. You can also encapsulate an additional API for calling **SendRequest** to send data to the peer.
After the preceding operations are done, register a system ability (SA) with SAMgr. Note that the registration should be completed in the process that hosts the stub. Then, obtain the proxy from SAMgr as needed to implement cross-process communication with the stub.
Related steps are as follows:
- Implementing the API class: Inherit **IRemoteBroker**, define message codes, and declare APIs that are not implemented in the API class.
- Implementing the service provider (stub): Inherit **IRemoteStub** or **RemoteObject**, and override the **AsObject** and **OnRemoteRequest** APIs.
- Implementing the service requester (proxy): Inherit **IRemoteProxy** or **RemoteProxy**, override the **AsObject** API, and encapsulate the required API to call **SendRequest**.
- Registering the SA: Apply for a unique ID for the SA, and register the SA with SAMgr.
- The cross-device proxy object cannot be passed to the device hosting the stub object pointed by this proxy object.
- Obtaining the SA: Obtain the proxy based on the SA ID and device ID, and use the proxy to communicate with the remote end.
## Related Modules
[Distributed Scheduler](https://gitee.com/openharmony/ability_dmsfwk)
[Distributed Ability Manager Service Framework](https://gitee.com/openharmony/ability_dmsfwk)
# Subscribing to State Changes of a Remote Object
IPC/RPC allows you to subscribe to the state changes of a remote stub object. When the remote stub object dies, a death notification will be sent to your local proxy object. Such subscription and unsubscription are controlled by APIs. To be specific, you need to implement the **DeathRecipient** callback and the **onRemoteDied** method to clear resources. This callback is invoked when the process accommodating the remote stub object dies, or the device accommodating the remote stub object leaves the network.
IPC/RPC allows you to subscribe to the state changes of a remote stub object. When the remote stub object dies, a death notification will be sent to your local proxy object. Such subscription and unsubscription are controlled by APIs. To be specific, you need to implement the **DeathRecipient** interface and the **onRemoteDied** API to clear resources. This callback is invoked when the process accommodating the remote stub object dies, or the device accommodating the remote stub object leaves the network. It is worth noting that these APIs should be called in the following order: The proxy object must first subscribe to death notifications of the stub object. If the stub object is in the normal state, the proxy object can cancel the subscription as required. If the process of the stub object exits or the device hosting the stub object goes offline, subsequent operations customized by the proxy object will be automatically triggered.
Note that the proxy object must first subscribe to death notifications of the stub object. If the stub object is in the normal state, the proxy object can cancel the subscription as required. If the process of the stub object exits or the device hosting the stub object goes offline, subsequent operations customized by the proxy object will be automatically triggered.
## When to Use
This subscription mechanism is applicable when the local proxy object needs to detect death of the process hosting the remote stub object or network detach of the device hosting the remote stub object. When the proxy detects death of the remote stub object, the proxy can clear local resources. Currently, IPC supports death notification for anonymous objects, but RPC does not. That is, you can only subscribe to death notifications of services that have been registered with SAMgr.
## **Using Native APIs**
## **Development Using Native APIs**
| API| Return Value Type| Feature Description|
| -------- | -------- | -------- |
| AddDeathRecipient(const sptr\<DeathRecipient> &recipient); | bool | Adds a recipient for death notifications of a remote stub object.|
| RemoveDeathRecipient(const sptr\<DeathRecipient> &recipient); | bool | Removes the recipient for death notifications of a remote stub object.|
| OnRemoteDied(const wptr\<IRemoteObject> &object); | void | Called when the remote stub object dies.|
| API| Description|
| -------- | -------- |
| AddDeathRecipient(const sptr\<DeathRecipient> &recipient); | Adds a recipient for death notifications of a remote stub object.|
| RemoveDeathRecipient(const sptr\<DeathRecipient> &recipient); | Removes the recipient for death notifications of a remote stub object.|
| OnRemoteDied(const wptr\<IRemoteObject> &object); | Called when the remote stub object dies.|
### Sample Code
```C++
#include "iremote_broker.h"
#include "iremote_stub.h"
## Sample Code
// Define message codes.
enum {
TRANS_ID_PING_ABILITY = 5,
TRANS_ID_REVERSED_MONITOR
};
const std::string DESCRIPTOR = "test.ITestAbility";
class ITestService : public IRemoteBroker {
public:
// DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string.
DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions.
};
class TestServiceProxy : public IRemoteProxy<ITestAbility> {
public:
explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
virtual int TestPingAbility(const std::u16string &dummy) override;
int TestAnonymousStub();
private:
static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
};
TestServiceProxy::TestServiceProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<ITestAbility>(impl)
{
}
int TestServiceProxy::TestPingAbility(const std::u16string &dummy){
MessageOption option;
MessageParcel dataParcel, replyParcel;
dataParcel.WriteString16(dummy);
int error = PeerHolder::Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
return result;
}
```
```c++
#include "iremote_object.h"
class TestDeathRecipient : public IRemoteObject::DeathRecipient {
public:
virtual void OnRemoteDied(const wptr<IRemoteObject>& remoteObject);
}
void TestDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject)
{
}
```
```c++
sptr<IPCObjectProxy> object = new IPCObjectProxy(1, to_utf16(DESCRIPTOR));
sptr<IRemoteObject::DeathRecipient> deathRecipient (new TestDeathRecipient());// Construct a death notification recipient.
bool result = proxy->AddDeathRecipient(deathRecipient); // Add a recipient for death notifications.
result = proxy->RemoveDeathRecipient(deathRecipient); // Remove the recipient for death notifications.
bool result = object->AddDeathRecipient(deathRecipient); // Add a recipient for death notifications.
result = object->RemoveDeathRecipient(deathRecipient); // Remove the recipient for death notifications.
```
## **Using JS APIs**
| API | Return Value Type| Feature Description |
| -------------------- | ---------- | ------------------------------------------------------------ |
| addDeathRecippient | boolean | Adds a recipient for death notifications of the remote object, including death notifications of the remote proxy.|
| removeDeathRecipient | boolean | Removes the recipient for death notifications of the remote object. |
| onRemoteDied | void | Called to perform subsequent operations when a death notification of the remote object is received.|
### Sample Code
```ts
import FA from "@ohos.ability.featureAbility";
let proxy;
let connect = {
onConnect: function(elementName, remoteProxy) {
console.log("RpcClient: js onConnect called.");
proxy = remoteProxy;
},
onDisconnect: function(elementName) {
console.log("RpcClient: onDisconnect");
},
onFailed: function() {
console.log("RpcClient: onFailed");
}
};
let want = {
"bundleName": "com.ohos.server",
"abilityName": "com.ohos.server.EntryAbility",
};
FA.connectAbility(want, connect);
class MyDeathRecipient {
onRemoteDied() {
console.log("server died");
}
}
let deathRecipient = new MyDeathRecipient();
proxy.addDeathRecippient(deathRecipient, 0);
proxy.removeDeathRecipient(deathRecipient, 0);
```
## Reverse Death Notification (Anonymous Stub)
Forward dead notification is a mechanism that allows the proxy to detect death notifications of the stub. To achieve reverse dead notification, we can leverage the forward dead notification mechanism to allow the stub to detect death notifications of the proxy.
Suppose there are two processes, A (the process hosting the original stub) and B (the process hosting the original proxy). After obtaining the proxy object of process A, process B creates an anonymous stub object (that is, a stub object not registered with SAMgr), which can be called a callback stub. Then, process B calls **SendRequest** to send the callback stub to the original stub of process A. As a result, process A obtains the callback proxy of process B. When process B dies or the device hosting process B detaches from the network, the callback stub dies. The callback proxy detects the death of the callback stub and sends a death notification to the original stub. In this way, reverse death notification is implemented.
> NOTE
> - Reverse death notification can only be used for cross-process communication within a device.
> - When an anonymous stub object is not pointed by any proxy, the kernel automatically reclaims the object.
### Sample Code
```c++
// Proxy
int TestAbilityProxy::TestAnonymousStub()
{
MessageOption option;
MessageParcel dataParcel, replyParcel;
dataParcel.UpdateDataVersion(Remote());
dataParcel.WriteRemoteObject(new TestAbilityStub());
int error = Remote()->SendRequest(TRANS_ID_REVERSED_MONITOR,dataParcel, replyParcel, option);
int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
return result;
}
// Stub
int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
switch (code) {
case TRANS_ID_REVERSED_MONITOR: {
sptr<IRemoteObject> obj = data.ReadRemoteObject();
if (obj == nullptr) {
reply.WriteInt32(ERR_NULL_OBJECT);
return ERR_NULL_OBJECT;
}
bool result = obj->AddDeathRecipient(new TestDeathRecipient());
result ? reply.WriteInt32(ERR_NONE) : reply.WriteInt32(-1);
break;
}
default:
break;
}
return ERR_NONE;
}
```
......@@ -13,7 +13,7 @@ The **DataShare** module allows an application to manage its own data and share
|query?(uri: string, predicates: DataSharePredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;Object&gt;): void|Queries data from the database.|
|delete?(uri: string, predicates: DataSharePredicates, callback: AsyncCallback&lt;number&gt;): void|Deletes data from the database.|
For more information, see [DataShareExtensionAbility](../reference/apis/js-apis-application-DataShareExtensionAbility.md).
For details about the data provider APIs, see [DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md).
**Table 2** APIs of the data consumer
......@@ -38,7 +38,47 @@ Examples are given below.
### Data Provider Application Development (Only for System Applications)
1. Import the dependencies.
[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md) provides the following APIs. You can override the APIs as required.
- **onCreate**
Called by the server to initialize service logic when the **DataShare** client connects to the **DataShareExtensionAbility** server.
- **insert**
Inserts data. This API is called when the client requests to insert data.
- **update**
Updates data. This API is called when the client requests to update data.
- **delete**
Deletes data. This API is called when the client requests to delete data.
- **query**
Queries data. This API is called when the client requests to query data.
- **batchInsert**
Batch inserts data. This API is called when the client requests to batch insert data.
- **normalizeUri**
Converts the URI provided by the client to the URI used by the server. This API can be overridden as required.
- **denormalizeUri**
Converts the URI used by the server to the initial URI passed by the client. This API can be overridden as required.
Before implementing a **DataShare** service, create a **DataShareExtensionAbility** object in the DevEco Studio project as follows:
1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **DataShareAbility**.
2. Right-click the **DataShareAbility** directory, and choose **New > TypeScript File** to create a file named **DataShareAbility.ts**.
3. In the **DataShareAbility.ts** file, import the **DataShareExtensionAbility** and other dependencies.
```ts
import Extension from '@ohos.application.DataShareExtensionAbility';
......@@ -47,9 +87,9 @@ Examples are given below.
import dataSharePredicates from '@ohos.data.dataSharePredicates';
```
2. Override **DataShareExtensionAbility** APIs based on actual requirements. For example, if the data provider provides only data query, override only the **query()** API.
4. Override the **DataShareExtensionAbility** APIs based on actual requirements. For example, if the data provider provides only data query, override only **query()**.
3. Implement the data provider services. For example, implement data storage of the data provider by using a database, reading and writing files, or accessing the network.
5. Implement the data provider services. For example, implement data storage of the data provider by using a database, reading and writing files, or accessing the network.
```ts
const DB_NAME = "DB00.db";
......@@ -63,11 +103,11 @@ Examples are given below.
export default class DataShareExtAbility extends Extension {
private rdbStore_;
// Override the onCreate() API.
// Override onCreate().
onCreate(want, callback) {
result = this.context.cacheDir + '/datashare.txt'
// Create an RDB.
// Create an RDB store.
rdb.getRdbStore(this.context, {
name: DB_NAME
}, 1, function (err, data) {
......@@ -79,7 +119,7 @@ Examples are given below.
});
}
// Override the query() API.
// Override query().
query(uri, predicates, columns, callback) {
if (predicates == null || predicates == undefined) {
console.info('invalid predicates');
......@@ -102,14 +142,17 @@ Examples are given below.
};
```
4. Define **DataShareExtensionAbility** in **module.json5**.
| Field| Description |
| ------------ | ------------------------------------------------------------ |
| "name" | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**. |
| "type" | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template.|
| "uri" | URI used for communication. It is the unique identifier for the data consumer to connect to the provider. |
| "visible" | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**.|
6. Define **DataShareExtensionAbility** in **module.json5**.
| Field | Description |
| --------- | ------------------------------------------------------------ |
| "name" | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**. |
| "type" | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template. |
| "uri" | URI used for communication. It is the unique identifier for the data consumer to connect to the provider. |
| "visible" | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**. |
| | |
**module.json5 example**
......@@ -127,30 +170,32 @@ Examples are given below.
]
```
### Data Consumer Application Development
1. Import the dependencies.
1. Import dependencies.
```ts
import Ability from '@ohos.application.Ability';
import UIAbility from '@ohos.app.ability.UIAbility';
import dataShare from '@ohos.data.dataShare';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
```
2. Define the URI string for communicating with the data provider.
```ts
// Different from the URI defined in the module.json5 file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/).
let dseUri = ("datashare:///com.samples.datasharetest.DataShare");
```
3. Create a **DataShareHelper** instance.
```ts
let dsHelper;
let abilityContext;
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
abilityContext = this.context;
dataShare.createDataShareHelper(abilityContext, dseUri, (err, data)=>{
......@@ -159,7 +204,7 @@ Examples are given below.
}
}
```
4. Use the APIs provided by **DataShareHelper** to access the services provided by the provider, for example, adding, deleting, modifying, and querying data.
```ts
......@@ -182,7 +227,6 @@ Examples are given below.
});
// Delete data.
dsHelper.delete(dseUri, predicates, (err, data) => {
console.log("dsHelper delete result: " + data);
console.log("dsHelper delete result: " + data);
});
```
......@@ -4,6 +4,8 @@
The **DataShare** module allows an application to manage its own data and share data with other applications. Currently, data can be shared only between applications on the same device.
**DataShare** must be used together with [DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md).
Data needs to be shared in a wealth of scenarios. For example, contacts, short message service (SMS), and media gallery always needs to be shared. However, certain data, such as accounts and passwords, cannot be shared. Some data, such as SMS messages, can be queried but not modified by other applications. **DataShare** provides a secure data sharing mechanism for applications in a variety of scenarios.
The data provider can directly use the **DataShare** framework to share data with other applications without complex encapsulation. The data consumer only needs to learn and use a set of interfaces because the data access mode does not vary with the data provisioning mode. This greatly reduces the learning time and development difficulty.
......@@ -16,22 +18,22 @@ Before you get started, familiarize yourself with the following concepts:
- Data provider
An application that provides data and implements related services. It is also called a producer or server.
The **DataShareExtensionAbility** based on the stage model implements functions, such as selectively adding, deleting, modifying, and querying data, and opening files. It implements services related to cross-application data sharing.
- Data consumer
An application that accesses the data or services provided by a data provider. It is also called a client.
The data consumer uses **DataShareHelper**, a utility class created by [createDataShareHelper()](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper), to access the data provided by the data provider.
- **ValuesBucket**
One or more data records stored in the form of key-value (KV) pairs. The keys are of the string type. The values can be of the number, string, Boolean, or Unit8Array type.
- Result set
A collection of query results. Flexible data access modes are provided for users to obtain data.
- Predicate
Conditions specified for updating, deleting, or querying data in the database.
## Working Principles
......@@ -41,7 +43,7 @@ Before you get started, familiarize yourself with the following concepts:
![](figures/en_DataShare.png)
- The **DataShareExtAbility** module, as the data provider, implements data sharing between applications.
- The **DataShareExtAbility** module, as the data provider, implements services related to data sharing between applications.
- The **DataShareHelper** module, as the data consumer, provides interfaces for accessing data, including adding, deleting, modifying, and querying data.
- The data consumer communicates with the data provider using inter-process communication (IPC). The data provider can be implemented through a database or other data storage.
......
......@@ -16,7 +16,8 @@ Call **createDistributedObject()** to create a distributed data object instance.
**Table 1** API for creating a distributed data object instance
| Package| API| Description|
| Bundle Name| API| Description|
| -------- | -------- | -------- |
| ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>- **source**: attributes of the distributed data object to set.<br>- **DistributedObject**: returns the distributed data object created. |
......@@ -25,7 +26,8 @@ Call **createDistributedObject()** to create a distributed data object instance.
Call **genSessionId()** to generate a session ID randomly. The generated session ID can be used to set the session ID of a distributed data object.
**Table 2** API for generating a session ID randomly
| Package| API| Description|
| Bundle Name| API| Description|
| -------- | -------- | -------- |
| ohos.data.distributedDataObject| genSessionId(): string | Generates a session ID, which can be used as the session ID of a distributed data object.|
......@@ -34,9 +36,10 @@ Call **genSessionId()** to generate a session ID randomly. The generated session
Call **setSessionId()** to set a session ID for a distributed data object. The session ID is a unique identifier for one collaboration across devices. The distributed data objects to be synchronized must be associated with the same session ID.
**Table 3** API for setting a session ID
| Class| API| Description|
| -------- | -------- | -------- |
| DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for a distributed data object.<br>**sessionId**: session ID of a distributed data object in a trusted network. To remove a distributed data object from the network, set this parameter to "" or leave it empty. |
| DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for this distributed data object.<br>**sessionId**: ID of the distributed data object on a trusted network. To remove a distributed data object from the network, set this parameter to "" or leave it empty.|
### Observing Data Changes
......@@ -54,6 +57,7 @@ Call **on()** to subscribe to data changes of a distributed data object. When th
Call **on()** to subscribe to status changes of a distributed data object. The status can be online or offline. When the status changes, a callback will be invoked to return the status. You can use **off()** to unsubscribe from the status changes.
**Table 5** APIs for observing status changes of a distributed data object
| Class| API| Description|
| -------- | -------- | -------- |
| DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to the status changes of a distributed data object.|
......@@ -90,86 +94,78 @@ The following example shows how to implement distributed data object synchroniza
2. Apply for the permission.
Add the permissions required (FA model) to the **config.json** file. The sample code is as follows:
Add the permissions required (FA model) to the **config.json** file.
```json
{
```json
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
}
}
```
}
```
For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model).
This permission must also be granted by the user when the application is started for the first time. The sample code is as follows:
This permission must also be granted by the user when the application is started for the first time.
```js
import featureAbility from '@ohos.ability.featureAbility';
```js
import featureAbility from '@ohos.ability.featureAbility';
function grantPermission() {
console.info('grantPermission');
let context = featureAbility.getContext();
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) {
console.info(`result.requestCode=${result.requestCode}`)
function grantPermission() {
console.info('grantPermission');
let context = featureAbility.getContext();
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) {
console.info(`result.requestCode=${result.requestCode}`)
})
console.info('end grantPermission');
}
})
console.info('end grantPermission');
}
grantPermission();
```
grantPermission();
```
3. Obtain a distributed data object instance.
The sample code is as follows:
```js
var local_object = distributedObject.createDistributedObject({
name: undefined,
age: undefined,
isVis: true,
parent: undefined,
list: undefined
let localObject = distributedObject.createDistributedObject({
name: undefined,
age: undefined,
isVis: true,
parent: undefined,
list: undefined
});
var sessionId = distributedObject.genSessionId();
let sessionId = distributedObject.genSessionId();
```
4. Add the distributed data object instance to a network for data synchronization. The data objects in the synchronization network include the local and remote objects.
The sample code is as follows:
```js
```js
// Local object
var local_object = distributedObject.createDistributedObject({
name: "jack",
age: 18,
isVis: true,
parent: { mother: "jack mom", father: "jack Dad" },
list: [{ mother: "jack mom" }, { father: "jack Dad" }]
let localObject = distributedObject.createDistributedObject({
name: "jack",
age: 18,
isVis: true,
parent: { mother: "jack mom", father: "jack Dad" },
list: [{ mother: "jack mom" }, { father: "jack Dad" }]
});
local_object.setSessionId(sessionId);
localObject.setSessionId(sessionId);
// Remote object
var remote_object = distributedObject.createDistributedObject({
name: undefined,
age: undefined,
isVis: true,
parent: undefined,
list: undefined
let remoteObject = distributedObject.createDistributedObject({
name: undefined,
age: undefined,
isVis: true,
parent: undefined,
list: undefined
});
// After learning that the local device goes online, the remote object synchronizes data. That is, name changes to jack and age to 18.
remote_object.setSessionId(sessionId);
remoteObject.setSessionId(sessionId);
```
5. Observe the data changes of the distributed data object.
You can subscribe to data changes of the remote object. When the data in the remote object changes, a callback will be called to return the data changes.
The sample code is as follows:
5. Observe the data changes of the distributed data object. You can subscribe to data changes of the remote object. When the data in the remote object changes, a callback will be invoked to return the data changes.
```js
function changeCallback(sessionId, changeData) {
......@@ -177,89 +173,78 @@ The following example shows how to implement distributed data object synchroniza
if (changeData != null && changeData != undefined) {
changeData.forEach(element => {
console.info("changed !" + element + " " + local_object[element]);
});
}
console.info("changed !" + element + " " + localObject[element]);
});
}
}
// To refresh the page in changeCallback, correctly bind (this) to the changeCallback.
local_object.on("change", this.changeCallback.bind(this));
localObject.on("change", this.changeCallback.bind(this));
```
6. Modify attributes of the distributed data object.
The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types).
The sample code is as follows:
6. Modify attributes of the distributed data object. The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types).
```js
local_object.name = "jack";
local_object.age = 19;
local_object.isVis = false;
local_object.parent = { mother: "jack mom", father: "jack Dad" };
local_object.list = [{ mother: "jack mom" }, { father: "jack Dad" }];
localObject.name = "jack";
localObject.age = 19;
localObject.isVis = false;
localObject.parent = { mother: "jack mom", father: "jack Dad" };
localObject.list = [{ mother: "jack mom" }, { father: "jack Dad" }];
```
> **NOTE**<br>
> For the distributed data object of the complex type, only the root attribute can be modified. The subordinate attributes cannot be modified. Example:
> For the distributed data object of the complex type, only the root attribute can be modified. The subordinate attributes cannot be modified.
```js
// Supported modification.
local_object.parent = { mother: "mom", father: "dad" };
localObject.parent = { mother: "mom", father: "dad" };
// Modification not supported.
local_object.parent.mother = "mom";
localObject.parent.mother = "mom";
```
7. Access the distributed data object.
Obtain the distributed data object attributes, which are the latest data on the network.
The sample code is as follows:
```js
console.info("name " + local_object["name"]);
console.info("name " + localObject["name"]);
```
8. Unsubscribe from data changes.
You can specify the callback to unregister. If you do not specify the callback, all data change callbacks of the distributed data object will be unregistered.
The sample code is as follows:
8. Unsubscribe from data changes. You can specify the callback to unregister. If you do not specify the callback, all data change callbacks of the distributed data object will be unregistered.
```js
// Unregister the specified data change callback.
local_object.off("change", changeCallback);
// Unregister the specified data change callback.
localObject.off("change", changeCallback);
// Unregister all data change callbacks.
local_object.off("change");
localObject.off("change");
```
9. Subscribe to the status (online/offline) changes of the distributed data object. A callback will be invoked to report the status change when the target distributed data object goes online or offline.
The sample code is as follows:
```js
function statusCallback(sessionId, networkId, status) {
this.response += "status changed " + sessionId + " " + status + " " + networkId;
}
local_object.on("status", this.statusCallback);
9. Subscribe to status changes of this distributed data object. A callback will be invoked to report the status change when the target distributed data object goes online or offline.
```js
function statusCallback(sessionId, networkId, status) {
this.response += "status changed " + sessionId + " " + status + " " + networkId;
}
localObject.on("status", this.statusCallback);
```
10. Save a distributed data object and delete it.
```js
// Save a distributed data object.
g_object.save("local").then((result) => {
console.info("save sessionId " + result.sessionId);
console.info("save version " + result.version);
console.info("save deviceId " + result.deviceId);
localObject.save("local").then((result) => {
console.info("save sessionId " + result.sessionId);
console.info("save version " + result.version);
console.info("save deviceId " + result.deviceId);
}, (result) => {
console.info("save local failed.");
console.info("save local failed.");
});
// Delete a distributed data object..
g_object.revokeSave().then((result) => {
console.info("revokeSave success.");
// Revoke the data saving operation.
localObject.revokeSave().then((result) => {
console.info("revokeSave success.");
}, (result) => {
console.info("revokeSave failed.");
console.info("revokeSave failed.");
});
```
......@@ -267,19 +252,15 @@ The following example shows how to implement distributed data object synchroniza
You can specify the callback to unregister. If you do not specify the callback, all status change callbacks of this distributed data object will be unregistered.
The sample code is as follows:
```js
// Unregister the specified status change callback.
local_object.off("status", this.statusCallback);
// Unregister the specified status change callback.
localObject.off("status", this.statusCallback);
// Unregister all status change callbacks.
local_object.off("status");
localObject.off("status");
```
12. Remove a distributed data object from the synchronization network. Data changes on the local object will not be synchronized to the removed distributed data object.
The sample code is as follows:
12. Remove the distributed data object from the synchronization network. The data changes on the local object will not be synchronized to the removed distributed data object.
```js
local_object.setSessionId("");
localObject.setSessionId("");
```
......@@ -14,12 +14,12 @@ For details about the APIs, see [Distributed KV Store](../reference/apis/js-apis
| API | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| createKVManager(config: KVManagerConfig, callback: AsyncCallback&lt;KVManager&gt;): void<br>createKVManager(config: KVManagerConfig): Promise&lt;KVManager> | Creates a **KvManager** object for database management. |
| getKVStore&lt;TextendsKVStore&gt;(storeId: string, options: Options, callback: AsyncCallback&lt;T&gt;): void<br>getKVStore&lt;TextendsKVStore&gt;(storeId: string, options: Options): Promise&lt;T&gt; | Creates and obtains a KV store.|
| getKVStore&lt;T extends KVStore&gt;(storeId: string, options: Options, callback: AsyncCallback&lt;T&gt;): void<br>getKVStore&lt;T extends KVStore&gt;(storeId: string, options: Options): Promise&lt;T&gt; | Creates and obtains a KV store.|
| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback&lt;void&gt;): void<br>put(key: string, value: Uint8Array\|string\|number\|boolean): Promise&lt;void> | Inserts and updates data. |
| delete(key: string, callback: AsyncCallback&lt;void&gt;): void<br>delete(key: string): Promise&lt;void> | Deletes data. |
| get(key: string, callback: AsyncCallback&lt;Uint8Array\|string\|boolean\|number&gt;): void<br>get(key: string): Promise&lt;Uint8Array\|string\|boolean\|number> | Queries data. |
| get(key: string, callback: AsyncCallback&lt;Uint8Array\|string\|boolean\|number&gt;): void<br>get(key: string): Promise&lt;Uint8Array\|string\|boolean\|number> | Obtains data. |
| on(event: 'dataChange', type: SubscribeType, observer: Callback&lt;ChangeNotification&gt;): void<br>on(event: 'syncComplete', syncCallback: Callback&lt;Array&lt;[string,number]&gt;&gt;): void | Subscribes to data changes in the KV store. |
| sync(deviceIdList: string[], mode: SyncMode, allowedDelayMs?: number): void | Triggers database synchronization in manual mode. |
| sync(deviceIdList: string[], mode: SyncMode, delayMs?: number): void | Triggers database synchronization in manual mode. |
## How to Develop
......@@ -61,32 +61,32 @@ The following uses a single KV store as an example to describe the development p
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666).then((data) => {
console.info('success: ${data}');
}).catch((error) => {
console.info('failed: ${error}');
console.error('failed: ${error}');
})
}
grantPermission();
// Stage model
import Ability from '@ohos.application.Ability';
import UIAbility from '@ohos.app.ability.UIAbility';
let context = null;
function grantPermission() {
class MainAbility extends Ability {
onWindowStageCreate(windowStage) {
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
let context = this.context;
}
}
}
let permissions = ['ohos.permission.DISTRIBUTED_DATASYNC'];
context.requestPermissionsFromUser(permissions).then((data) => {
function grantPermission() {
let permissions = ['ohos.permission.DISTRIBUTED_DATASYNC'];
context.requestPermissionsFromUser(permissions).then((data) => {
console.log('success: ${data}');
}).catch((error) => {
console.log('failed: ${error}');
});
}).catch((error) => {
console.error('failed: ${error}');
});
}
grantPermission();
```
......@@ -103,9 +103,9 @@ The following uses a single KV store as an example to describe the development p
let context = featureAbility.getContext();
// Obtain the context of the stage model.
import AbilityStage from '@ohos.application.Ability';
import UIAbility from '@ohos.app.ability.UIAbility';
let context = null;
class MainAbility extends AbilityStage{
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context;
}
......@@ -119,7 +119,7 @@ The following uses a single KV store as an example to describe the development p
}
distributedKVStore.createKVManager(kvManagerConfig, function (err, manager) {
if (err) {
console.error(`Failed to create KVManager.code is ${err.code},message is ${err.message}`);
console.error(`Failed to create KVManager. code is ${err.code},message is ${err.message}`);
return;
}
console.log('Created KVManager successfully');
......
......@@ -24,7 +24,7 @@ Obtain a **Preferences** instance for data operations. A **Preferences** instanc
**Table 1** API for obtaining a **Preferences** instance
| Package | API | Description |
| Bundle Name | API | Description |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ohos.data.preferences | getPreferences(context: Context, name: string): Promise\<Preferences> | Obtains a **Preferences** instance.|
......@@ -75,7 +75,7 @@ You can use the following APIs to delete a **Preferences** instance or data file
**Table 6** APIs for deleting **Preferences**
| Package | API | Description |
| Bundle Name | API | Description |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ohos.data.preferences | deletePreferences(context: Context, name: string): Promise\<void> | Deletes a **Preferences** instance from the memory and its files from the device.|
| ohos.data.preferences | removePreferencesFromCache(context: Context, name: string): Promise\<void> | Removes a **Preferences** instance from the memory to release memory. |
......@@ -113,10 +113,10 @@ You can use the following APIs to delete a **Preferences** instance or data file
```ts
// Obtain the context.
import Ability from '@ohos.application.Ability'
import UIAbility from '@ohos.app.ability.UIAbility';
let context = null;
let preferences = null;
export default class MainAbility extends Ability {
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context;
}
......@@ -159,7 +159,7 @@ You can use the following APIs to delete a **Preferences** instance or data file
5. Store data persistently.
Use **flush()** to flush data from the **Preferences** instance to its file.
Use **preferences.flush()** to flush data from the **Preferences** instance to its file.
```js
preferences.flush();
......@@ -186,7 +186,7 @@ You can use the following APIs to delete a **Preferences** instance or data file
console.info("Failed to flush data. Cause: " + err);
return;
}
console.info("Flushed data successfully."); // The observer will be called.
console.info("Flushed data successfully."); // The observer will be called.
})
})
```
......
# RDB Overview
The relational database (RDB) manages data based on relational models. With the underlying SQLite database, the RDB provides a complete mechanism for managing local databases. To satisfy different needs in complicated scenarios, the RDB offers a series of methods for performing operations such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements.
A relational database (RDB) store manages data based on relational models. With the underlying SQLite database, the RDB store provides a complete mechanism for managing data as in a local database. To satisfy different needs in complicated scenarios, the RDB store offers APIs for performing operations, such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. After an application is uninstalled, the related RDB store will be automatically deleted.
You do not need to care about the implementation of the database locking mechanism.
## Basic concepts
## Basic Concepts
- **RDB**
- **RDB store**
A type of database created on the basis of relational models. The RDB stores data in rows and columns. A RDB is also called RDB store.
A type of database created on the basis of relational models. A RDB store holds data in rows and columns.
- **Predicate**
A representation of the property or feature of a data entity, or the relationship between data entities. It is mainly used to define operation conditions.
A representation of the property or feature of a data entity, or the relationship between data entities. Predicates are used to define operation conditions.
- **Result set**
......@@ -24,9 +24,9 @@ You do not need to care about the implementation of the database locking mechani
## Working Principles
The RDB provides common operation APIs for external systems. It uses the SQLite as the underlying persistent storage engine, which supports all SQLite database features.
The RDB store provides common operation APIs for external systems. It uses the SQLite as the underlying persistent storage engine, which supports all SQLite database features.
**Figure 1** How RDB works
**Figure 1** Working mechanism
![how-rdb-works](figures/how-rdb-works.png)
......@@ -38,6 +38,6 @@ The RDB provides common operation APIs for external systems. It uses the SQLite
## Constraints
- A maximum of four connection pools can be connected to an RDB to manage read and write operations.
- An RDB store can be connected to a maximum of four connection pools to manage read and write operations.
- To ensure data accuracy, the RDB supports only one write operation at a time.
- To ensure data accuracy, the RDB store supports only one write operation at a time.
# Geocoding and Reverse Geocoding Capabilities
## When to Use
Describing a location using coordinates is accurate, but neither intuitive nor user-friendly. With the geocoding and reverse geocoding capabilities, you will be able to convert geographic description into specific coordinates and vice versa.
The geographic description helps users understand a location easily by providing several key attributes, for example, country, administrative region, street, house number, and address.
## Available APIs
The following table describes APIs available for mutual conversion between coordinates and geographic description. For details, see [Geolocation Manager](../reference/apis/js-apis-geolocation.md).
**Table1** APIs for geocoding and reverse geocoding
| API | Description |
| -------- | -------- |
| isGeoServiceAvailable(callback: AsyncCallback&lt;boolean&gt;) : void | Checks whether the (reverse) geocoding service is available. This API uses an asynchronous callback to return the result.|
| isGeoServiceAvailable() : Promise&lt;boolean&gt; | Checks whether the (reverse) geocoding service is available. This API uses a promise to return the result.|
| getAddressesFromLocation(request: ReverseGeoCodeRequest, callback: AsyncCallback&lt;Array&lt;GeoAddress&gt;&gt;) : void | Converts coordinates into geographic description through reverse geocoding. This API uses an asynchronous callback to return the result. |
| getAddressesFromLocation(request: ReverseGeoCodeRequest) : Promise&lt;Array&lt;GeoAddress&gt;&gt; | Converts coordinates into geographic description through reverse geocoding. This API uses a promise to return the result. |
| getAddressesFromLocationName(request: GeoCodeRequest, callback: AsyncCallback&lt;Array&lt;GeoAddress&gt;&gt;) : void | Converts geographic description into coordinates through geocoding. This API uses an asynchronous callback to return the result. |
| getAddressesFromLocationName(request: GeoCodeRequest) : Promise&lt;Array&lt;GeoAddress&gt;&gt; | Converts geographic description into coordinates through geocoding. This API uses a promise to return the result. |
## How to Develop
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
>
> The **GeoConvert** instance needs to access backend services to obtain information. Therefore, before performing the following steps, ensure that your device is connected to the network.
1. Import the **geolocation** module by which you can implement all APIs related to the geocoding and reverse geocoding conversion capabilities.
```ts
import geolocation from '@ohos.geolocation';
```
2. Query whether geocoder service is available.
- Call **isGeoServiceAvailable** to query whether the geocoder service is available. If the service is available, continue with step 3.
```ts
geolocation.isGeoServiceAvailable((err, data) => {
if (err) {
console.log('isGeoServiceAvailable err: ' + JSON.stringify(err));
} else {
console.log('isGeoServiceAvailable data: ' + JSON.stringify(data));
}
});
```
3. Obtain the conversion result.
- Call **getAddressesFromLocation** to convert coordinates into geographical location information.
```ts
var reverseGeocodeRequest = {"latitude": 31.12, "longitude": 121.11, "maxItems": 1};
geolocation.getAddressesFromLocation(reverseGeocodeRequest, (err, data) => {
if (err) {
console.log('getAddressesFromLocation err: ' + JSON.stringify(err));
} else {
console.log('getAddressesFromLocation data: ' + JSON.stringify(data));
}
});
```
Your application can obtain the **GeoAddress** list that matches the specified coordinates and then read location information from it. For details, see [Geolocation](../reference/apis/js-apis-geolocation.md).
- Call **getAddressesFromLocationName** to convert geographic description into coordinates.
```ts
var geocodeRequest = {"description": "No. xx, xx Road, Pudong District, Shanghai", "maxItems": 1};
geolocation.getAddressesFromLocationName(geocodeRequest, (err, data) => {
if (err) {
console.log('getAddressesFromLocationName err: ' + JSON.stringify(err));
} else {
console.log('getAddressesFromLocationName data: ' + JSON.stringify(data));
}
});
```
Your application can obtain the **GeoAddress** list that matches the specified location information and read coordinates from it. For details, see [Geolocation](../reference/apis/js-apis-geolocation.md).
To improve the accuracy of location results, you can set the longitude and latitude ranges in **GeoCodeRequest**.
# Obtaining Device Location Information
## When to Use
You can call location-related APIs in OpenHarmony to obtain the real-time location or last known location of a mobile device.
Real-time location of the device is recommended for location-sensitive services. If you want to lower power consumption when the real-time location of the device is not needed, you may consider obtaining the last known location of the device.
## Available APIs
For details about the APIs used to obtain the device location information, see [Geolocation Manager](../reference/apis/js-apis-geolocation.md).
## How to Develop
To learn more about the APIs for obtaining device location information, see [Geolocation](../reference/apis/js-apis-geolocation.md).
1. Before using basic location capabilities, check whether your application has been granted the permission to access the device location information. If not, your application needs to obtain the permission from the user as described below.
The system provides the following location permissions:
- ohos.permission.LOCATION
- ohos.permission.APPROXIMATELY_LOCATION
- ohos.permission.LOCATION_IN_BACKGROUND
If your application needs to access the device location information, it must first apply for required permissions. Specifically speaking:
API versions earlier than 9: Apply for **ohos.permission.LOCATION**.
API version 9 and later: Apply for **ohos.permission.APPROXIMATELY\_LOCATION**, or apply for **ohos.permission.APPROXIMATELY\_LOCATION** and **ohos.permission.LOCATION**. Note that **ohos.permission.LOCATION** cannot be applied for separately.
| Target API Level| Location Permission| Permission Application Result| Location Accuracy|
| -------- | -------- | -------- | -------- |
| Earlier than 9| ohos.permission.LOCATION | Success| Location accurate to meters|
| 9 and later| ohos.permission.LOCATION | Failure| No location obtained|
| 9 and later| ohos.permission.APPROXIMATELY_LOCATION | Success| Location accurate to 5 kilometers|
| 9 and later| ohos.permission.APPROXIMATELY_LOCATION and ohos.permission.LOCATION| Success| Location accurate to meters|
If your application needs to access the device location information when running on the background, it must be configured to be able to run on the background and be granted the **ohos.permission.LOCATION_IN_BACKGROUND** permission. In this way, the system continues to report device location information after your application moves to the background.
You can declare the required permission in your application's configuration file. For details, see [Access Control (Permission) Development](../security/accesstoken-guidelines.md).
2. Import the **geolocation** module by which you can implement all APIs related to the basic location capabilities.
```
import geolocation from '@ohos.geolocation';
```
3. Instantiate the **LocationRequest** object. This object provides APIs to notify the system of the location service type and the interval of reporting location information.<br>
**Method 1:**
To better serve your needs for using APIs, the system has categorized APIs into different packages to match your common use cases of the location function. In this way, you can directly use the APIs specific to a certain use case, making application development much easier. The following table lists the use cases currently supported.
```
export enum LocationRequestScenario {
UNSET = 0x300,
NAVIGATION,
TRAJECTORY_TRACKING,
CAR_HAILING,
DAILY_LIFE_SERVICE,
NO_POWER,
}
```
**Table 2** Common use cases of the location function
| Use Case | Constant | Description |
| ------------ | ------------------- | ------------------------------------------------------------ |
| Navigation | NAVIGATION | Applicable when your application needs to obtain the real-time location of a mobile device outdoors, such as navigation for driving or walking. In this scenario, the GNSS positioning technology is mainly used to ensure the location accuracy. However, due to its limitations, the technology may be unable to provide the location service when navigation is just started or when the user moves into a shielded environment such as indoors or a garage. To resolve this issue, the system uses the network positioning technology as an alternative to provide the location service for your application until the GNSS can provide stable location results. This helps achieve a smooth navigation experience for users.<br>By default, the system reports location results at a minimal interval of 1s. To adopt this use case, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Trajectory tracking| TRAJECTORY_TRACKING | Applicable when your application needs to record user trajectories, for example, the track recording function of sports applications. In this scenario, the GNSS positioning technology is mainly used to ensure the location accuracy.<br>By default, the system reports location results at a minimal interval of 1s. To adopt this use case, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Ride hailing| CAR_HAILING | Applicable when your application needs to obtain the current location of a user who is hailing a taxi.<br>By default, the system reports location results at a minimal interval of 1s. To adopt this use case, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Life service| DAILY_LIFE_SERVICE | Applicable when your application only needs the approximate user location for recommendations and push notifications in scenarios such as when the user is browsing news, shopping online, and ordering food.<br>By default, the system reports location results at a minimal interval of 1s. To adopt this use case, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Power efficiency | NO_POWER | Applicable when your application does not proactively start the location service for a higher battery efficiency. When responding to another application requesting the same location service, the system marks a copy of the location result to your application. In this way, your application will not consume extra power for obtaining the user location.<br>By default, the system reports location results at a minimal interval of 1s. To adopt this use case, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
Sample code for initializing **requestInfo** for navigation:
```ts
var requestInfo = {'scenario': geolocation.LocationRequestScenario.NAVIGATION, 'timeInterval': 0, 'distanceInterval': 0, 'maxAccuracy': 0};
```
**Method 2:**
If the predefined use cases do not meet your needs, you can also use the basic location priority policies provided by the system.
```ts
export enum LocationRequestPriority {
UNSET = 0x200,
ACCURACY,
LOW_POWER,
FIRST_FIX,
}
```
**Table 3** Location priority policies
| Policy | Constant | Description |
| ------------------ | -------------- | ------------------------------------------------------------ |
| Location accuracy priority | ACCURACY | This policy mainly uses the GNSS positioning technology. In an open area, the technology can achieve the meter-level location accuracy, depending on the hardware performance of the device. However, in a shielded environment, the location accuracy may significantly decrease.<br>To use this policy, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Fast location priority | FAST_FIRST_FIX | This policy uses the GNSS positioning, base station positioning, WLAN positioning, and Bluetooth positioning technologies simultaneously to obtain the device location in both the indoor and outdoor scenarios. When all positioning technologies provide a location result, the system provides the most accurate location result for your application. This policy can lead to significant hardware resource consumption and power consumption.<br>To use this policy, you must declare the **ohos.permission.LOCATION** permission and obtain users' authorization.|
| Power efficiency priority| LOW_POWER | This policy mainly uses the base station positioning, WLAN positioning, and Bluetooth positioning technologies to obtain device location in both indoor and outdoor scenarios. The location accuracy depends on the distribution of surrounding base stations, visible WLANs, and Bluetooth devices and therefore may fluctuate greatly. This policy is recommended and can reduce power consumption when your application does not require high location accuracy or when base stations, visible WLANs, and Bluetooth devices are densely distributed.<br>To use this policy, you must declare at least the **ohos.permission.LOCATION** permission and obtain users' authorization.|
Sample code for initializing **requestInfo** for the location accuracy priority policy:
```ts
var requestInfo = {'priority': geolocation.LocationRequestPriority.ACCURACY, 'timeInterval': 0, 'distanceInterval': 0, 'maxAccuracy': 0};
```
4. Instantiate the **Callback** object for the system to report location results.
Your application needs to implement the callback defined by the system. When the system successfully obtains the real-time location of a device, it will report the location result to your application through the callback interface. Your application can implement the callback interface in such a way to complete your own service logic.
```ts
var locationChange = (location) => {
console.log('locationChanger: data: ' + JSON.stringify(location));
};
```
5. Start device location.
```ts
geolocation.on('locationChange', requestInfo, locationChange);
```
6. (Optional) Stop device location.
```ts
geolocation.off('locationChange', locationChange);
```
If your application does not need the real-time device location, it can use the last known device location cached in the system instead.
```ts
geolocation.getLastLocation((err, data) => {
if (err) {
console.log('getLastLocation: err: ' + JSON.stringify(err));
} else {
console.log('getLastLocation: data: ' + JSON.stringify(data));
}
});
```
To call this method, your application needs to request the **ohos.permission.LOCATION** permission from the user.
# Location Overview
People take their mobile devices wherever they go. Mobile devices have become a necessity in people's daily routines, whether it be for looking at the weather forecast, browsing news, hailing a taxi, navigating, or recording data from a workout. All these activities are so much associated with the location services on mobile devices.
With the location awareness capability offered by , mobile devices will be able to obtain real-time, accurate location data. Building location awareness into your application can also lead to a better contextual experience for application users.
Your application can call location-specific APIs to obtain the location information of a mobile device for offering location-based services such as drive navigation and motion track recording.
## Basic Concepts
Location awareness helps determine where a mobile device locates. The system identifies the location of a mobile device with its coordinates, and uses location technologies such as Global Navigation Satellite System (GNSS) and network positioning (for example, base station positioning or WLAN/Bluetooth positioning) to provide diverse location-based services. These advanced location technologies make it possible to obtain the accurate location of the mobile device, regardless of whether it is indoors or outdoors.
- **Coordinate**
A coordinate describes a location on the earth using the longitude and latitude in reference to the World Geodetic Coordinate System 1984.
- **GNSS positioning**
GNSS positioning locates a mobile device by using the location algorithm offered by the device chip to compute the location information provided by the Global Navigation Satellite System, for example, GPS, GLONASS, BeiDou, and Galileo. Whichever positioning system will be used during the location process depends on a hardware capability of the device.
- **Base station positioning**
Base station positioning estimates the current location of a mobile device based on the location of the resident base station in reference to the neighboring base stations. This technology provides only a low accuracy and requires access to the cellular network.
- **WLAN or Bluetooth positioning**
WLAN or Bluetooth positioning estimates the current location of a mobile device based on the locations of WLANs and Bluetooth devices that can be discovered by the device. The location accuracy of this technology depends on the distribution of fixed WLAN access points (APs) and Bluetooth devices around the device. A high density of WLAN APs and Bluetooth devices can produce a more accurate location result than base station positioning. This technology also requires access to the network.
## Working Principles
Location awareness is offered by the system as a basic service for applications. Depending on the service scenario, an application needs to initiate a location request to the system and stop the location request when the service scenario ends. In this process, the system reports the location information to the application on a real-time basis.
## Limitations and Constraints
Your application can use the location function only after the user has granted the permission and turned on the function. If the location function is off, the system will not provide the location service for any application.
Since the location information is considered sensitive, your application still needs to obtain the location access permission from the user even if the user has turned on the location function. The system will provide the location service for your application only after it has been granted the permission to access the device location information.
## Samples
The following sample is provided to help you better understand how to develop location services:
-[`Location`: Location (eTS) (API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/device/Location)
......@@ -16,8 +16,8 @@ The following table lists the common APIs for input device management. For detai
| Instance| API | Description|
| ----------- | ------------------------------------------------------------ | -------------------------- |
| inputDevice | function getDeviceList(callback: AsyncCallback\<Array\<number>>): void; | Obtains the list of input devices.|
| inputDevice | function getKeyboardType(deviceId: number, callback: AsyncCallback\<KeyboardType>): void; | Obtains the keyboard type of the input device.|
| inputDevice | function getDeviceList(): Promise\<Array\<number>>; | Obtains the list of input devices.|
| inputDevice | function getKeyboardType(deviceId: number): Promise\<KeyboardType>; | Obtains the keyboard type of the input device.|
| inputDevice | function on(type: "change", listener: Callback\<DeviceListener>): void; | Enables listening for device hot swap events.|
| inputDevice | function off(type: "change", listener?: Callback\<DeviceListener>): void; | Disables listening for device hot swap events.|
......@@ -40,8 +40,8 @@ try {
// 1. Obtain the list of input devices and check whether a physical keyboard is connected.
inputDevice.getDeviceList().then(data => {
for (let i = 0; i < data.length; ++i) {
inputDevice.getKeyboardType(data[i]).then(res => {
if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD) {
inputDevice.getKeyboardType(data[i]).then(type => {
if (type === inputDevice.KeyboardType.ALPHABETIC_KEYBOARD) {
// The physical keyboard is connected.
isPhysicalKeyboardExist = true;
}
......@@ -51,9 +51,9 @@ try {
// 2. Listen for device hot swap events.
inputDevice.on("change", (data) => {
console.log(`Device event info: ${JSON.stringify(data)}`);
inputDevice.getKeyboardType(data.deviceId, (error, type) => {
inputDevice.getKeyboardType(data.deviceId).then((type) => {
console.log("The keyboard type is: " + type);
if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD && data.type == 'add') {
if (type === inputDevice.KeyboardType.ALPHABETIC_KEYBOARD && data.type == 'add') {
// The physical keyboard is inserted.
isPhysicalKeyboardExist = true;
} else if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD && data.type == 'remove') {
......
......@@ -7,7 +7,7 @@ Mouse pointer management provides the functions such as displaying or hiding the
## Modules to Import
```js
import inputDevice from '@ohos.multimodalInput.pointer';
import pointer from '@ohos.multimodalInput.pointer';
```
## Available APIs
......
......@@ -14,11 +14,10 @@ The following table lists the USB APIs currently available. For details, see the
| API | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| hasRight(deviceName: string): boolean | Checks whether the user, for example, the application or system, has the device access permissions. The value **true** is returned if the user has the device access permissions; the value **false** is returned otherwise. |
| requestRight(deviceName: string): Promise\<boolean> | Requests the temporary permission for a given application to access the USB device. |
| removeRight(deviceName: string): boolean | Removes the permission for a given application to access the USB device. |
| connectDevice(device: USBDevice): Readonly\<USBDevicePipe> | Connects to the USB device based on the device information returned by `getDevices()`. |
| getDevices(): Array<Readonly\<USBDevice>> | Obtains the USB device list. |
| hasRight(deviceName: string): boolean | Checks whether the user has the device access permissions. |
| requestRight(deviceName: string): Promise\<boolean> | Requests the temporary permission for a given application to access the USB device. This API uses a promise to return the result. |
| connectDevice(device: USBDevice): Readonly\<USBDevicePipe> | Connects to the USB device based on the device list returned by `getDevices()`. |
| getDevices(): Array<Readonly\<USBDevice>> | Obtains the list of USB devices connected to the USB host. If no USB device is connected, an empty list is returned. |
| setConfiguration(pipe: USBDevicePipe, config: USBConfig): number | Sets the USB device configuration. |
| setInterface(pipe: USBDevicePipe, iface: USBInterface): number | Sets a USB interface. |
| claimInterface(pipe: USBDevicePipe, iface: USBInterface, force?: boolean): number | Claims a USB interface. |
......@@ -37,7 +36,7 @@ You can set a USB device as the USB host to connect to other USB devices for dat
```js
// Import the USB API package.
import usb from '@ohos.usb';
import usb from '@ohos.usbV9';
// Obtain the USB device list.
let deviceList = usb.getDevices();
/*
......@@ -82,16 +81,17 @@ You can set a USB device as the USB host to connect to other USB devices for dat
number: 1,
type: 3,
interfaceId: 0,
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
*/
```
2. Obtain the device operation permissions.
......
......@@ -60,7 +60,7 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Configure the **startWindowIcon** attribute under **abilities** in the **module.json5** file.
Reference: [Application Package Structure Configuration File](../quick-start/stage-structure.md)
Reference: [Application Package Structure (Stage Model)](../quick-start/module-configuration-file.md)
Example:
......@@ -83,17 +83,15 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Implement the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the orientation and density) change.
Reference: [Ability Development](../ability/stage-ability.md)
## Can I obtain the context through globalThis in the stage model?
Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
Do not use **globalThis** to obtain the context in the stage model. This is because all the processes of an application share a JS VM instance in the stage model. Multiple abilities can run on these processes and share the same global object. If **globalThis** is used, the context of different abilities of the same JS VM instance may be returned.
For details about the recommended operation, see [Context in the Stage Model](../ability/context-userguide.md#context-in-the-stage-model).
Reference of the recommended operation: [Context (Stage Model)](../application-models/application-context-stage.md)
## How do I obtain the HAP file installation path of application B from application A?
## How do I obtain the HAP installation path of application B from application A?
Applicable to: OpenHarmony SDK 3.0 or later, stage model of API version 9
......@@ -109,7 +107,7 @@ The callee uses **AbilityContext.terminateSelfWithResult** to destroy its abilit
Applicable to: OpenHarmony SDK 3.2.5.5, FA model of API version 8
After a widget is added, the **onCreate()** lifecycle is triggered so that related user information (silent login) can be displayed even when the application is not started. However, users must manually add the widget after the application is installed.
After a widget is added, the **oncreate()** lifecycle is triggered so that related user information (silent login) can be displayed even when the application is not started. However, users must manually add the widget after the application is installed.
## How do I obtain the context?
......
......@@ -9,7 +9,6 @@ Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9
- Method 2: Run the screenshot script. Connect to the development board to a computer running Windows. Create a text file on the computer, copy the following script content to the file, change the file name extension to **.bat** (the HDC environment variables must be configured in advance), and click **Run**. The screenshot is saved to the same directory as the **.bat** script file.
Example:
```
set filepath=/data/%date:~0,4%%date:~5,2%%date:~8,2%%time:~1,1%%time:~3,2%%time:~6,2%.png
echo %filepath%
......@@ -29,10 +28,11 @@ Applicable to: DevEco Studio 3.0.0.991
![en-us_image_0000001361254285](figures/en-us_image_0000001361254285.png)
2. Set the profile parameters as follows:
Device type : default
Resolution: 720\*1280
DPI: 240
## What should I do if Device Manager incorrectly identifies a development board as FT232R USB UART even when the development board already has a driver installed?
......
......@@ -16,15 +16,15 @@ Reference: [Notification](../reference/apis/js-apis-notification.md#notification
Example:
```
import WantAgent from '@ohos.wantAgent';
```ts
import WantAgent from '@ohos.app.ability.wantAgent';
async function publishNotification() {
let wantAgentInfo = {
wants: [
{
bundleName: "com.example.notification",
abilityName: "MainAbility",
bundleName: "com.example.myapplication",
abilityName: "EntryAbility",
}
],
operationType: WantAgent.OperationType.START_ABILITIES,
......
......@@ -59,7 +59,7 @@ Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
The **ohos.permission.READ_MEDIA** is required for using **getAlbums()**. In addition, this permission needs user authorization. For details, see [OpenHarmony Permission List](../security/permission-list.md).
1. Configure the required permission in the **module.json5** file.
```
"requestPermissions": [
{
......@@ -69,13 +69,16 @@ The **ohos.permission.READ_MEDIA** is required for using **getAlbums()**. In add
```
2. Add the code for user authorization before the **MainAbility.ts -> onWindowStageCreate** page is loaded.
```
import abilityAccessCtrl from '@ohos.abilityAccessCtrl.d.ts';
private requestPermissions() {
let permissionList: Array<string> = [
"ohos.permission.READ_MEDIA"
];
this.context.requestPermissionsFromUser(permissionList)
let atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(this.context, permissionList)
.then(data => {
console.info(`request permission data result = ${data.authResults}`)
})
......
......@@ -18,10 +18,10 @@ Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9
1. Use the **onWindowStageCreate** to obtain a **windowClass** object.
```
```ts
onWindowStageCreate(windowStage) {
// When the main window is created, set the main page for this ability.
console.log("[Demo] MainAbility onWindowStageCreate")
console.log("[Demo] EntryAbility onWindowStageCreate")
windowStage.getMainWindow((err, data) => {
if (err.code) {
console.error('Failed to obtain the main window.')
......@@ -35,7 +35,7 @@ Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9
2. Enable the full-screen mode for the window and hide the status bar.
```
```ts
globalThis.windowClass.setFullScreen(isFullScreen, (err, data) => {
if (err.code) {
console.error('Failed to enable the full-screen mode. Cause:' + JSON.stringify(err));
......@@ -54,7 +54,7 @@ Use **window.getProperties()** to obtain the window properties. The **windowRect
Example:
```
```ts
let promise = windowClass.getProperties();
promise.then((data)=> {
console.info('Succeeded in obtaining the window properties. Data: ' + JSON.stringify(data.windowRect));
......@@ -70,7 +70,7 @@ Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
Refer to the following code:
```
```ts
window.getTopWindow(globalThis.mainContext).then(win => {
var systemBarProperties = {
statusBarColor: '#19B6FF', // Set the background color of the status bar.
......
......@@ -155,7 +155,9 @@ The global function **encodeURI** is used for URI encoding, and **decodeURI** is
Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
Yes. The **convert** API of the **convertxml** module can be used to convert XML text into JavaScript objects. Reference: [@ohos.convertxml](../reference/apis/js-apis-convertxml.md)
Yes. The **convert** API of the **convertxml** module can be used to convert XML text into JavaScript objects.
Reference: [@ohos.convertxml](../reference/apis/js-apis-convertxml.md)
## How do I configure application icons to be used across devices?
......@@ -287,4 +289,4 @@ Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
No. Relational database operations cannot be performed in the worker thread.
<!--no_check-->
\ No newline at end of file
<!--no_check-->
\ No newline at end of file
......@@ -42,7 +42,7 @@ cameraInput = await this.cameraManager.createCameraInput(cameraId)
Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9
1. Create an **ImageSource** instance based on the input URI.
```
let path = this.context.getApplicationContext().fileDirs + "test.jpg";
const imageSourceApi = image.createImageSource(path);
......@@ -52,7 +52,7 @@ Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9
- Set **desiredSize** to specify the target size after scaling. If the values are all set to **0**, scaling will not be performed.
- Set **desiredRegion** to specify the target rectangular area after cropping. If the values are all set to **0**, cropping will not be performed.
- Set **rotateDegrees** to specify the rotation angle. The image will be rotated clockwise at the center.
```
const decodingOptions = {
desiredSize: {
......@@ -85,7 +85,7 @@ Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
1. Configure the permissions **ohos.permission.READ_MEDIA** and **ohos.permission.WRITE_MEDIA** in the **module.json5** file.
Example:
```
{
"module" : {
......@@ -104,10 +104,14 @@ Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9
```
2. Call **requestPermissionsFromUser** to request the permissions from end users in the form of a dialog box. This operation is required because the grant mode of both permissions is **user_grant**.
```
import abilityAccessCtrl from '@ohos.abilityAccessCtrl.d.ts';
let permissions: Array<string> = ['ohos.permission.READ_MEDIA','ohos.permission.WRITE_MEDIA']
context.requestPermissionsFromUser(permissions).then((data) => {
let atManager = abilityAccessCtrl.createAtManager();
// context is the ability-level context of the initiator UIAbility.
atManager.requestPermissionsFromUser(context, 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,4 +3,8 @@
- [MediaLibrary Overview](medialibrary-overview.md)
- [Media Asset Management](medialibrary-resource-guidelines.md)
- [File Path Management](medialibrary-filepath-guidelines.md)
- [Album Management](medialibrary-album-guidelines.md)
\ No newline at end of file
- [Album Management](medialibrary-album-guidelines.md)
- File Access Framework
- [File Access Framework Overview](file-access-framework-overview.md)
- [FilePicker Guide](filepicker-guidelines.md)
\ No newline at end of file
# Internationalization
- [Internationalization Overview](international-overview.md)
- [Internationalization Development (intl)](intl-guidelines.md)
- [Internationalization Development (i18n)](i18n-guidelines.md)
- [intl Development](intl-guidelines.md)
- [i18n Development](i18n-guidelines.md)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册