提交 700a0558 编写于 作者: Mr-YX's avatar Mr-YX 提交者: Gitee

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

此差异已折叠。
此差异已折叠。
...@@ -7,35 +7,42 @@ ...@@ -7,35 +7,42 @@
- [OpenHarmony Release Notes](../release-notes/Readme.md) - [OpenHarmony Release Notes](../release-notes/Readme.md)
- Quick Start - Quick Start
- Getting Started - Getting Started
- [Preparations](start-overview.md) - [Preparations](quick-start/start-overview.md)
- [Getting Started with eTS](start-with-ets.md) - [Getting Started with eTS in the Traditional Coding Approach](quick-start/start-with-ets.md)
- [Getting Started with JavaScript in the Traditional Coding Approach](start-with-js.md) - [Getting Started with eTS in the Low-Code Approach](quick-start/start-with-ets-low-code.md)
- [Getting Started with JavaScript in the Low-Code Approach](start-with-js-low-code.md) - [Getting Started with JavaScript in the Traditional Coding Approach](quick-start/start-with-js.md)
- [Getting Started with JavaScript in the Low-Code Approach](quick-start/start-with-js-low-code.md)
- Development Fundamentals - Development Fundamentals
- [Application Development Package Structure (FA Model)](package-structure.md) - [Application Package Structure Configuration File (FA Model)](quick-start/package-structure.md)
- [Application Development Package Structure (Stage Model)](module-structure.md) - [Application Package Structure Configuration File (Stage Model)](quick-start/stage-structure.md)
- [Resource File Categories](basic-resource-file-categories.md) - [Resource File Categories](quick-start/basic-resource-file-categories.md)
- [SysCap](syscap.md) - [SysCap](quick-start/syscap.md)
- Development - Development
- [Ability Development](ability/Readme-EN.md) - [Ability Development](ability/Readme-EN.md)
- [UI Development](ui/Readme-EN.md) - [UI Development](ui/Readme-EN.md)
- Basic Feature Development - Basic Feature Development
- [Common Event and Notification](notification/Readme-EN.md)
- [Window Manager](windowmanager/Readme-EN.md) - [Window Manager](windowmanager/Readme-EN.md)
- [WebGL](webgl/Readme-EN.md) - [WebGL](webgl/Readme-EN.md)
- [Media](media/Readme-EN.md) - [Media](media/Readme-EN.md)
- [Security](security/Readme-EN.md) - [Security](security/Readme-EN.md)
- [Connectivity](connectivity/Readme-EN.md) - [Connectivity](connectivity/Readme-EN.md)
- [Data Management](database/Readme-EN.md) - [Data Management](database/Readme-EN.md)
- [Telephony](telephony/Readme-EN.md)
- [Agent-Powered Scheduled Reminders](background-agent-scheduled-reminder/Readme-EN.md) - [Agent-Powered Scheduled Reminders](background-agent-scheduled-reminder/Readme-EN.md)
- [Background Task Management](background-task-management/Readme-EN.md) - [Background Task Management](background-task-management/Readme-EN.md)
- [Work Scheduler](work-scheduler/Readme-EN.md)
- [Device Management](device/Readme-EN.md) - [Device Management](device/Readme-EN.md)
- [Device Usage Statistics](device-usage-statistics/Readme-EN.md) - [Device Usage Statistics](device-usage-statistics/Readme-EN.md)
- [DFX](dfx/Readme-EN.md) - [DFX](dfx/Readme-EN.md)
- [Internationalization](internationalization/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/napi-guidelines.md)
- Tools - Tools
- [DevEco Studio (OpenHarmony) User Guide](quick-start/deveco-studio-user-guide-for-openharmony.md) - [DevEco Studio (OpenHarmony) User Guide](quick-start/deveco-studio-user-guide-for-openharmony.md)
- Hands-On Tutorials - Hands-On Tutorials
- [Samples](https://gitee.com/openharmony/app_samples/blob/master/README.md) - [Samples](https://gitee.com/openharmony/app_samples/blob/master/README.md)
- [Codelabs](https://gitee.com/openharmony/codelabs)
- API References - API References
- [Component Reference (JavaScript-based Web-like Development Paradigm)](reference/arkui-js/Readme-EN.md) - [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) - [Component Reference (TypeScript-based Declarative Development Paradigm)](reference/arkui-ts/Readme-EN.md)
......
# Ability Development # Ability Development
- [Ability Framework Overview](ability-brief.md) - [Ability Framework Overview](ability-brief.md)
- FA Model - [Context Usage](context-userguide.md)
- [FA Model Overview](fa-brief.md) - FA Model
- [Page Ability Development](fa-pageability.md) - [FA Model Overview](fa-brief.md)
- [Service Ability Development](fa-serviceability.md) - [Page Ability Development](fa-pageability.md)
- [Data Ability Development](fa-dataability.md) - [Service Ability Development](fa-serviceability.md)
- [FA Widget Development](fa-formability.md) - [Data Ability Development](fa-dataability.md)
- Stage Model - [FA Widget Development](fa-formability.md)
- [Stage Model Overview](stage-brief.md) - Stage Model
- [Ability Development](stage-ability.md) - [Stage Model Overview](stage-brief.md)
- [Service Extension Ability Development](stage-serviceextension.md) - [Ability Development](stage-ability.md)
- [Ability Continuation Development](stage-ability-continuation.md) - [Service Extension Ability Development](stage-serviceextension.md)
- [Ability Call Development](stage-call.md) - [Ability Continuation Development](stage-ability-continuation.md)
- [Stage Widget Development](stage-formextension.md) - [Ability Call Development](stage-call.md)
- Other - [Stage Widget Development](stage-formextension.md)
- [WantAgent Development](wantagent.md) - Other
- [Ability Assistant Usage](ability-assistant-guidelines.md) - [WantAgent Development](wantagent.md)
- [Test Framework Usage](ability-delegator.md) - [Ability Assistant Usage](ability-assistant-guidelines.md)
- [Test Framework Usage](ability-delegator.md)
# Test Framework Usage # Test Framework Usage
## Overview ## Overview
The delegator test framework provides a self-test framework (environment) for OpenHarmony applications. Using this framework, you can start an ability, schedule its lifecycle, listen for its state changes, run a shell command, and print the test result. The delegator test framework provides a self-test environment for OpenHarmony applications. Using this framework, you can start an ability, schedule its lifecycle, listen for its state changes, run a shell command, and print the test result.
## Constraints ## Constraints
The APIs provided by the test framework can be used only in the test HAP. They take effect only after the test framework is started by running the **aa test** command or using the Integrated Development Environment (IDE). The APIs provided by the test framework can be used only in the test HAP. They take effect only after the test framework is started.
## Starting the Test Framework ## Starting the Test Framework
The test framework can be started using either of the following methods: The test framework can be started in either of the following ways:
- Method 1: Run the **aa test** command. - Method 1: Run the <idp:inline class="- topic/inline " val="code" displayname="code" id="code779717408187" tempcmdid="code779717408187">aa test</idp:inline> command.
- Method 2: Use the IDE. - Method 2: Use the IDE.
### Running aa test ### Running aa test
You can run the **aa test** command to start the test framework. You can specify the **TestRunner** to be used and the package name or module name of the HAP where the **TestRunner** is located. To start the test framework, specify the **TestRunner** and the package name or module name of the HAP where the **TestRunner** is located.
An example command in the FA model is as follows: An example command in the FA model is as follows:
```javascript ```javascript
aa test -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 aa test -b BundleName -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20
``` ```
An example command in the stage model is as follows: An example command in the stage model is as follows:
```javascript ```javascript
aa test -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 aa test -b BundleName -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20
``` ```
| Parameter | Mandatory| Description | | Parameter | Mandatory| Description |
| --------------- | -------- | ------------------------------------------------------------ | | --------------- | -------- | ------------------------------------------------------------ |
| -b | Yes | Bundle name of the HAP where the **TestRunner** is located. |
| -p | Yes | Package name of the HAP where the **TestRunner** is located. This parameter is used by the FA model. | | -p | Yes | Package name of the HAP where the **TestRunner** is located. This parameter is used by the FA model. |
| -m | Yes | Module name of the HAP where the **TestRunner** is located. This parameter is used by the stage model. | | -m | Yes | Module name of the HAP where the **TestRunner** is located. This parameter is used by the stage model. |
| -s unittest | Yes | Name of the **TestRunner** to be used. The TestRunner name must be the same as the file name. | | -s unittest | Yes | Name of the **TestRunner** to be used. The TestRunner name must be the same as the file name. |
| -w | No | Timeout interval of a test case, in seconds. If this parameter is not specified, the test framework exits only after **finishTest** is invoked.| | -w | No | Timeout interval of a test case, in seconds. If this parameter is not specified or is set to a value less than or equal to **0**, the test framework exits only after **finishTest** is invoked.|
| -s <key><value> | No | It can be any parameter in the key-value format. The entered parameters can be obtained in key-value mode through **AbilityDelegatorArgs.parameters**. For example, in **-s classname myTest**, **classname** is the key and **myTest** is the value.| | -s \<key>\<value> | No | **-s** can be followed by any key-value pair obtained through **AbilityDelegatorArgs.parameters**. For example, in **-s classname myTest**, **-s classname** is the key and **myTest** is the value.|
| -D | No | Debug mode for starting the tested application. |
| -h | No | Help information. |
### Using the IDE ### Using the IDE
For details about how to start the IDE, see [IDE Guide](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001263160453#section1034420367508). For details about how to use the IDE to start the test framework, see [IDE Guide](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001263160453#section1034420367508).
## Introduction to TestRunner ## Introduction to TestRunner
**TestRunner** is the entry class of the test framework test process. When the test process is started, the system calls related APIs in **TestRunner**. You need to inherit this class and override the **onPrepare** and **onRun** APIs. When creating an application template, the IDE initializes the default **TestRunner** and starts the default **TestAbility** in the **onRun** API. You can modify the test code of **TestAbility** or override **onPrepare** and **onRun** in **TestRunner** to implement your own test code. For details, see [TestRunner](../reference/apis/js-apis-testRunner.md). **TestRunner** is the entry class of the test framework test process. When the test process is started, the system calls related APIs in **TestRunner**. You need to inherit this class and override the **onPrepare** and **onRun** APIs. When creating an application template, the IDE initializes the default **TestRunner** and starts the default **TestAbility** in the **onRun** API. You can modify the test code of **TestAbility** or override **onPrepare** and **onRun** in **TestRunner** to implement your own test code. For details, see [TestRunner](../reference/apis/js-apis-testRunner.md).
## Introduction to AbilityDelegatorRegistry
**AbilityDelegatorRegistry** is the **AbilityDelegator** repository class provided by the test framework. You can use **AbilityDelegatorRegistry** to obtain an **AbilityDelegator** instance and the input and generated parameters **AbilityDelegatorArgs** during the test. You can use **AbilityDelegator** to invoke the function set provided by the test framework for testing and verification. For details, see [AbilityDelegatorRegistry](../reference/apis/js-apis-abilityDelegatorRegistry.md).
## Introduction to AbilityDelegatorArgs
**AbilityDelegatorArgs** is a test parameter class provided by the test framework. You can use **AbilityDelegatorArgs** to obtain the parameters passed and generated during the test. For details, see [AbilityDelegatorArgs](../reference/apis/js-apis-application-abilityDelegatorArgs.md).
## Introduction to AbilityMonitor ## Introduction to AbilityMonitor
**AbilityMonitor** is provided by the test framework for binding to and listening for abilities. You can use **AbilityMonitor** to bind to an **Ability** instance and add **AbilityMonitor** to the listening list. After an ability is bound, the creation and lifecycle changes of the ability will trigger the related callback in **AbilityMonitor**. You can test and verify the ability in these callbacks. For details, see [AbilityMonitor](../reference/apis/js-apis-application-abilityMonitor.md). **AbilityMonitor** is provided by the test framework for binding to and listening for abilities. You can use **AbilityMonitor** to bind to an **Ability** instance and add **AbilityMonitor** to the listening list. When **AbilityMonitor** is bound to an ability, the creation and lifecycle changes of the ability will trigger the related callback in **AbilityMonitor**. You can test and verify the ability in these callbacks. For details, see [AbilityMonitor](../reference/apis/js-apis-application-abilityMonitor.md).
**Example** **Example**
```javascript ```javascript
import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'
function onAbilityCreateCallback() { function onAbilityCreateCallback(data) {
console.info("onAbilityCreateCallback"); console.info("onAbilityCreateCallback");
} }
...@@ -64,7 +75,7 @@ var monitor = { ...@@ -64,7 +75,7 @@ var monitor = {
} }
var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.addAbilityMonitor(monitor).then((void) => { abilityDelegator.addAbilityMonitor(monitor).then(() => {
console.info("addAbilityMonitor promise"); console.info("addAbilityMonitor promise");
}); });
``` ```
...@@ -94,7 +105,7 @@ var abilityDelegator; ...@@ -94,7 +105,7 @@ var abilityDelegator;
var ability; var ability;
var timeout = 100; var timeout = 100;
function onAbilityCreateCallback() { function onAbilityCreateCallback(data) {
console.info("onAbilityCreateCallback"); console.info("onAbilityCreateCallback");
} }
...@@ -113,8 +124,6 @@ var want = { ...@@ -113,8 +124,6 @@ var want = {
bundleName: "bundleName", bundleName: "bundleName",
abilityName: "abilityName" abilityName: "abilityName"
}; };
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => { abilityDelegator.startAbility(want, (err, data) => {
console.info("startAbility callback"); console.info("startAbility callback");
}); });
...@@ -126,14 +135,44 @@ abilityDelegator.startAbility(want, (err, data) => { ...@@ -126,14 +135,44 @@ abilityDelegator.startAbility(want, (err, data) => {
### Running a Shell Command ### Running a Shell Command
**AbilityDelegator** provides APIs to run shell commands. You can run a shell command in the test code. This feature takes effect only in the test environment. **AbilityDelegator** provides APIs to run shell commands in the test environment.
**Example** **Example**
```javascript ```javascript
var abilityDelegator; var abilityDelegator;
var cmd = "cmd"; var cmd = "cmd";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.executeShellCommand(cmd, (err,data) => { abilityDelegator.executeShellCommand(cmd, (err, data) => {
console.info("executeShellCommand callback"); console.info("executeShellCommand callback");
}); });
```
### Printing Log Information
**AbilityDelegator** provides APIs for printing log information. You can call any API in the test code to print process logs to the unit test console.
**Example**
```javascript
var abilityDelegator;
var msg = "msg";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.print(msg, (err) => {
console.info("print callback");
});
```
### Finishing the Test and Printing Log Information
**AbilityDelegator** provides the APIs for actively finishing the test. You can call any API in test code to finish the test and print logs to the unit test console.
**Example**
```javascript
var abilityDelegator;
var msg = "msg";
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.finishTest(msg, 0, (err) => {
console.info("finishTest callback");
});
``` ```
# Context Usage
## Context Overview
**context** provides the capability of obtaining contextual information of an application.
## Context Structure
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, which does not belong to either model. It has only one attribute, **stageMode**, which specifies whether the context is used for the stage model.
The FA model has only one type of context: **app/Context**. 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.
The stage model has six types of contexts: **application/Context**, **application/AbilityStageContext**, **application/ExtensionContext**, **application/AbilityContext**, **application/FormExtensionContext**, and **application/ServiceExtensionContext**. For details about these contexts and how to use them, see [Context in the Stage Model](#context-in-the-stage-model).
![contextIntroduction](figures/contextIntroduction.png)
## Context in the FA Model
Only the methods in **app/Context** can be used for the context in the FA model.
The FA model has only one context definition. All capabilities in the context are provided through methods. The context uses these methods to extend the capabilities of the FA.
The context is defined in the d.ts file below:
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/app/context.d.ts
Use the context as follows:
```javascript
// 1. Import featureAbility.
import featureAbility from '@ohos.ability.featureAbility'
export default {
onCreate() {
console.log('Application onCreate')
// 2. Obtain the context.
let context = featureAbility.getContext();
// 3. Call the methods.
context.setShowOnLockScreen(false, (data) => {
console.log("data: " + JSON.stringify(data));
});
},
onActive() {
console.log('Application onActive')
},
onDestroy() {
console.log('Application onDestroy')
},
}
```
## Context in the Stage Model
The stage model has six contexts. The following describes these contexts in detail.
### application/Context
**Overview**
**application/Context** is the base class context that provides basic application information such as **resourceManager**, **applicationInfo**, and **cacheDir**. It also provides basic application methods such as **createBundleContext** and **switchArea**. The application-level context is of the **application/Context** type.
**How to Obtain**
Obtain the context by calling **context.getApplicationContext()** in **AbilityStage**, **Ability**, and **Extension**.
**Example**
```javascript
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('MainAbility onCreate is called' + want + launchParam);
// Obtain the application context.
let appContext = this.context.getApplicationContext();
// Obtain the path.
console.log('filesDir is ' + appContext.filesDir);
}
onDestroy() {
console.log('MainAbility onDestroy is called');
}
}
```
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/Context.d.ts
### application/AbilityStageContext
**Overview**
**application/AbilityStageContext** is the context for the HAP file. In addition to those provided by the base class **application/Context**, this context contains **HapModuleInfo** and **Configuration**.
**How to Obtain**
Obtain the context from the **context** attribute in **AbilityStage**.
**Example**
```javascript
export default class MyAbilityStage extends AbilityStage {
onCreate() {
// The context attribute is of the AbilityStageContext type.
console.log('HapModuleInfo is ' + context.currentHapModuleInfo);
}
}
```
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityStageContext.d.ts
### application/AbilityContext
**Overview**
In the stage model, each ability has a context attribute.
**Ability** provides methods to manage the ability lifecycle, and **AbilityContext** provides methods to operate abilities (such as **startAbility** and **connectAbility**).
**How to Obtain**
Obtain the context from the **context** attribute in **Ability**.
**Example**
```javascript
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log('MainAbility onCreate is called' + want + launchParam);
var want = {
"bundleName": "com.example.MyApplication",
"abilityName": "ServiceExtAbility",
}
// 1. The context here is of the AbilityContext type.
let contxt = this.context;
// 2. Start the ability.
contxt.startAbility(want).then((data) => {
console.info("startAbility success:" + JSON.stringify(data));
}).catch((error) => {
console.error("startAbility failed:" + JSON.stringify(error));
});
}
onDestroy() {
console.log("MainAbility on Destroy is called");
}
}
```
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityContext.d.ts
### application/ExtensionContext
**Overview**
Unlike the FA model, the stage model separates **Service** from **Ability** and defines a group of **Extension** classes to provide the same capabilities. **Extension** is a base class and does not provide specific service functions. The service party extends the corresponding **Extension** class as required. For example, a Service ability is extended to **ServiceExtensionAbility**, and a form (service widget) is extended to **FormExtensionAbility**.
**ExtensionContext** provides the context for the extension. **ExtensionContext** has the **HapModuleInfo** and **Configuration** attributes.
**How to Obtain**
This type of context is not used independently.
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ExtensionContext.d.ts
### application/ServiceExtensionContext
**Overview**
Similar to **ServiceAbility** of the FA model, **ServiceExtensionAbility** contains only the processing related to lifecycle callbacks.
The methods for operating the Service Extension ability (such as **startAbility** and **connectAbility**) are provided in **ServiceExtensionContext**.
**How to Obtain**
Obtain the context from the **context** attribute in **ServiceExtensionAbility**.
**Example**
```javascript
export default class ServiceExtAbility extends ServiceExtensionAbility {
onCreate(want) {
console.info("ServiceAbility onCreate**");
// The context here is of the ServiceExtensionContext type.
let contxt = this.context;
}
onRequest(want, startId) {
console.info("ServiceAbility onRequest**");
}
onConnect(want) {
console.info("ServiceAbility onConnect**");
return new StubTest("test");
}
onDisconnect(want) {
console.info("ServiceAbility onDisconnect**");
}
onDestroy() {
console.info("ServiceAbility onDestroy**");
}
}
```
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ServiceExtensionContext.d.ts
### application/FormExtensionContext
For details, see [FormExtensionContext](/en/application-dev/reference/apis/js-apis-formextensioncontext.md)
**d.ts statement**
https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/FormExtensionContext.d.ts
## FAQs
Can I obtain the context through globalThis?
**Answer**
You can use **globalThis** to obtain the context in the FA model, but not in the stage model. To obtain the context in the stage model, use the **context** attribute in the corresponding component.
**Reason**
In the FA model, each ability instance has a JS VM instance. Therefore, a global ability instance can be obtained from the **global** object of the JS engine. In the stage model, where all the processes of an application share a JS VM instance, there is no global ability instance, and using **globalThis** may cause an error or crash.
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
## Overview ## Overview
### Concepts ### Concepts
The Page ability implements the ArkUI and provides the capability of interacting with developers. When you create an ability in the integrated development environment (IDE), the IDE automatically creates template code. The capabilities related to the Page ability are implemented through the **featureAbility**, and the lifecycle callbacks are implemented through the callbacks in **app.js/app.ets**. The Page ability implements the ArkUI and provides the capability of interacting with developers. When you create an ability in DevEco Studio, DevEco Studio automatically creates template code. The capabilities related to the Page ability are implemented through the **featureAbility**, and the lifecycle callbacks are implemented through the callbacks in **app.js** or **app.ets**.
### Page Ability Lifecycle ### Page Ability Lifecycle
**Ability lifecycle** **Ability lifecycle**
The Page ability lifecycle is a general term for all states of a Page ability, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**. The Page ability lifecycle defines all states of a Page ability, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**.
The following figure shows the lifecycle state transition of the Page ability. The following figure shows the lifecycle state transition of the Page ability.
...@@ -17,25 +17,25 @@ The following figure shows the lifecycle state transition of the Page ability. ...@@ -17,25 +17,25 @@ The following figure shows the lifecycle state transition of the Page ability.
Description of ability lifecycle states: Description of ability lifecycle states:
- **UNINITIALIZED**: The Page ability is not initialized. This is a temporary state. A Page ability changes directly to the **INITIAL** state upon its creation. - **UNINITIALIZED**: The Page ability is not initialized. This is a temporary state, from which a Page ability changes directly to the **INITIAL** state upon its creation.
- **INITIAL**: This state refers to the initial or stopped state. The Page ability in this state is not running. The Page ability enters the **INACTIVE** state after it is started. - **INITIAL**: The Page ability is initialized but not running. The Page ability enters the **INACTIVE** state after it is started.
- **INACTIVE**: The ability is visible but does not gain focus. - **INACTIVE**: The Page ability is visible but does not gain focus.
- **ACTIVE**: The ability runs in the foreground and gains focus. - **ACTIVE**: The Page ability runs in the foreground and has focus.
- **BACKGROUND**: The Page ability returns to the background. After being re-activated, the Page ability enters the **ACTIVE** state. After being destroyed, the Page ability enters the **INITIAL** state. - **BACKGROUND**: The Page ability runs in the background. After being re-activated, the Page ability enters the **ACTIVE** state. After being destroyed, the Page ability enters the **INITIAL** state.
**The following figure shows the relationship between lifecycle callbacks and lifecycle states of the Page ability.** **The following figure shows the relationship between lifecycle callbacks and lifecycle states of the Page ability.**
![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) ![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png)
You can override the lifecycle callbacks provided by the Page ability in the **app.js/app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. You can override the lifecycle callbacks provided by the Page ability in the **app.js** or **app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks.
### Launch Type ### Launch Type
The ability supports two launch types: singleton and multi-instance. The ability supports two launch types: singleton and multi-instance.
The **launchType** item in the **config.json** file is used to specify the launch type. You can specify the launch type by setting **launchType** in the **config.json** file.
| Launch Type | Description |Description | | Launch Type | Description |Description |
| ----------- | ------- |---------------- | | ----------- | ------- |---------------- |
...@@ -55,7 +55,7 @@ By default, **singleton** is used. ...@@ -55,7 +55,7 @@ By default, **singleton** is used.
| void startAbility(parameter: StartAbilityParameter) | Starts an ability. | | void startAbility(parameter: StartAbilityParameter) | Starts an ability. |
| Context getContext(): | Obtains the application context.| | Context getContext(): | Obtains the application context.|
| void terminateSelf() | Terminates the ability. | | void terminateSelf() | Terminates the ability. |
| bool hasWindowFocus() | Checks whether the ability gains focus. | | bool hasWindowFocus() | Checks whether the ability has focus. |
### Starting a Local Page Ability ### Starting a Local Page Ability
...@@ -76,37 +76,10 @@ By default, **singleton** is used. ...@@ -76,37 +76,10 @@ By default, **singleton** is used.
action: "", action: "",
entities: [""], entities: [""],
type: "", type: "",
options: {
// Grant the permission to perform read operations on the URI.
authReadUriPermission: true,
// Grant the permission to perform write operations on the URI.
authWriteUriPermission: true,
// Support forwarding the Want result to the ability.
abilityForwardResult: true,
// Enable abiligy continuation.
abilityContinuation: true,
// Specify that a component does not belong to ohos.
notOhosComponent: true,
// Specify that an ability is started.
abilityFormEnabled: true,
// Grant the permission for possible persisting on the URI.
authPersistableUriPermission: true,
// Grant the permission for possible persisting on the prefix URI.
authPrefixUriPermission: true,
// Support distributed scheduling system startup on multiple devices.
abilitySliceMultiDevice: true,
// A service ability is started regardless of whether the host application has been started.
startForegroundAbility: true,
// Install the specified ability if it is not installed.
installOnDemand: true,
// Return the result to the ability slice.
abilitySliceForwardResult: true,
// Install the specified ability with background mode if it is not installed.
installWithBackgroundMode: true
},
deviceId: "", deviceId: "",
bundleName: "com.example.startability", bundleName: "com.example.myapplication",
abilityName: "com.example.startability.MainAbility", /* In the FA model, abilityName consists of package and ability name. */
abilityName: "com.example.entry.secondAbility",
uri: "" uri: ""
}, },
}, },
...@@ -122,10 +95,10 @@ You can also include **parameters** in the **want** parameter and set its value ...@@ -122,10 +95,10 @@ You can also include **parameters** in the **want** parameter and set its value
featureAbility.startAbility({ featureAbility.startAbility({
want: want:
{ {
bundleName: "com.example.startability", bundleName: "com.example.myapplication",
uri: "", uri: "",
parameters: { parameters: {
abilityName: "com.example.startability.MainAbility" abilityName: "com.example.entry.secondAbility"
} }
}, },
}, },
...@@ -227,15 +200,15 @@ In the cross-device scenario, the application must also apply for the data synch ...@@ -227,15 +200,15 @@ In the cross-device scenario, the application must also apply for the data synch
| API | Description | | API | Description |
| ------------ | ------------------------------------------------------------ | | ------------ | ------------------------------------------------------------ |
| onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.| | onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.|
| onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible.| | onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible to users.|
| onDestroy() | Called when the ability is destroyed. In this callback, you can make preparations for app exit, such as recycling resources and clearing the cache.| | onDestroy() | Called when the ability is destroyed. In this callback, you can make preparations for application exit, such as recycling resources and clearing the cache.|
| onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.| | onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.|
| onInactive() | Called when the ability loses focus. An ability loses focus before entering the background state.| | onInactive() | Called when the ability loses focus. An ability loses focus when it is about to enter the background state.|
| onActive() | Called when the ability is switched to the foreground and gains focus. | | onActive() | Called when the ability is switched to the foreground and gains focus. |
**Example** **Example**
You need to override the lifecycle callbacks in **app.js/app.ets**. The IDE template generates **onCreate()** and **onDestroy()** by default. You need to override the other callbacks. You need to override the lifecycle callbacks except **onCreate()** and **onDestroy()** in **app.js** or **app.ets**. The **onCreate()** and **onDestroy()** callbacks are automatically generated in the template code provided by DevEco Studio.
```javascript ```javascript
export default { export default {
...@@ -261,4 +234,5 @@ export default { ...@@ -261,4 +234,5 @@ export default {
``` ```
## Samples ## Samples
The following sample is provided to help you better understand how to develop a Page ability: The following sample is provided to help you better understand how to develop a Page ability:
- [`DMS`: Distributed Demo (eTS) (API7)](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS)
- [`DMS`: Distributed Demo (eTS, API version 7)](https://gitee.com/openharmony/app_samples/tree/master/ability/DMS)
...@@ -8,13 +8,17 @@ The following figure shows the ability call process. ...@@ -8,13 +8,17 @@ The following figure shows the ability call process.
![stage-call](figures/stage-call.png) ![stage-call](figures/stage-call.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/>
> The startup mode of the callee must be **singleton**.
> Currently, only system applications and Service Extension abilities can use the **Call** APIs to access the callee.
## Available APIs ## Available APIs
The table below describes the ability call APIs. For details, see [Ability](../reference/apis/js-apis-application-ability.md#caller). The table below describes the ability call APIs. For details, see [Ability](../reference/apis/js-apis-application-ability.md#caller).
**Table 1** Ability call APIs **Table 1** Ability call APIs
|API|Description| |API|Description|
|:------|:------| |:------|:------|
|Promise<Caller> startAbilityByCall(want: Want)|Obtains the caller interface of the specified ability, and if the specified ability is not started, starts the ability in the background.| |Promise<Caller> startAbilityByCall(want: Want)|Obtains the caller interface of the specified ability and, if the specified ability is not running, starts the ability in the background.|
|void on(method: string, callback: CalleeCallBack)|Callee.on: callback invoked when the callee registers a method.| |void on(method: string, callback: CalleeCallBack)|Callee.on: callback invoked when the callee registers a method.|
|void off(method: string)|Callee.off: callback invoked when the callee deregisters a method.| |void off(method: string)|Callee.off: callback invoked when the callee deregisters a method.|
|Promise<void> call(method: string, data: rpc.Sequenceable)|Caller.call: sends agreed sequenceable data to the callee.| |Promise<void> call(method: string, data: rpc.Sequenceable)|Caller.call: sends agreed sequenceable data to the callee.|
...@@ -77,7 +81,7 @@ export default class MySequenceable { ...@@ -77,7 +81,7 @@ export default class MySequenceable {
``` ```
4. Implement **Callee.on** and **Callee.off**. 4. Implement **Callee.on** and **Callee.off**.
The time to register a listener for the callee depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the **CalleeSortMethod** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns them. You need to implement processing based on service requirements. The sample code is as follows: The time to register a listener for the callee depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the **CalleeSortMethod** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The sample code is as follows:
```ts ```ts
const TAG: string = '[CalleeAbility]' const TAG: string = '[CalleeAbility]'
const MSG_SEND_METHOD: string = 'CallSendMsg' const MSG_SEND_METHOD: string = 'CallSendMsg'
...@@ -196,7 +200,7 @@ context.requestPermissionsFromUser(permissions).then((data) => { ...@@ -196,7 +200,7 @@ context.requestPermissionsFromUser(permissions).then((data) => {
``` ```
3. Send agreed sequenceable data. 3. Send agreed sequenceable data.
The sequenceable data can be sent to the callee in either of the following ways: without a return value or obtaining data returned by the callee. The method and sequenceable data must be consistent with those of the callee. The following example describes how to invoke the **Call** API to send data to the callee. The sample code is as follows: The sequenceable data can be sent to the callee with or without a return value. The method and sequenceable data must be consistent with those of the callee. The following example describes how to invoke the **Call** API to send data to the callee. The sample code is as follows:
```ts ```ts
const MSG_SEND_METHOD: string = 'CallSendMsg' const MSG_SEND_METHOD: string = 'CallSendMsg'
async onButtonCall() { async onButtonCall() {
...@@ -242,9 +246,6 @@ try { ...@@ -242,9 +246,6 @@ try {
} }
``` ```
## Development Example ## Samples
The following sample is provided to help you better understand how to develop an ability call in the stage model: The following sample is provided to help you better understand how to develop an ability call in the stage model:
- [`StageCallAbility`: Stage Ability Creation and Usage (eTS, API version 9)](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
[StageCallAbility](https://gitee.com/openharmony/app_samples/tree/master/ability/StageCallAbility)
In this sample, the **AbilityStage** APIs are implemented in the **AbilityStage.ts** file in the **Application** directory, the **Ability** APIs are implemented in the **MainAbility** directory, and **pages/index** is the pages of the ability. Another ability and callee are implemented in the **CalleeAbility** directory, and its pages are the content configured in **pages/second**. The **MainAbility** functions as the caller, and the **CalleeAbility** functions as the callee. After starting the **CalleeAbility**, the **MainAbility** obtains the caller interface, processes the string entered by the user, and transfers the processed string to the **CalleeAbility**. The **CalleeAbility** refreshes the page based on the received data and returns the result to the **MainAbility**.
...@@ -44,7 +44,7 @@ DevEco Studio is a high-performance integrated development environment (IDE) rec ...@@ -44,7 +44,7 @@ DevEco Studio is a high-performance integrated development environment (IDE) rec
### Hands-On Tutorials ### Hands-On Tutorials
To make you better understand how functions work together and jumpstart your application development projects, we provide stripped-down, real-world [samples](https://gitee.com/openharmony/app_samples/blob/master/README.md). To make you better understand how functions work together and jumpstart your application development projects, we provide stripped-down, real-world [samples](https://gitee.com/openharmony/app_samples/blob/master/README.md) and [codelabs](https://gitee.com/openharmony/codelabs).
### API References ### API References
......
...@@ -44,7 +44,7 @@ DevEco Studio is a high-performance integrated development environment (IDE) rec ...@@ -44,7 +44,7 @@ DevEco Studio is a high-performance integrated development environment (IDE) rec
### Hands-On Tutorials ### Hands-On Tutorials
To make you better understand how functions work together and jumpstart your application development projects, we provide stripped-down, real-world [samples](https://gitee.com/openharmony/app_samples/blob/master/README.md). To make you better understand how functions work together and jumpstart your application development projects, we provide stripped-down, real-world [samples](https://gitee.com/openharmony/app_samples/blob/master/README.md) and [codelabs](https://gitee.com/openharmony/codelabs).
### API References ### API References
......
# Agent-Powered Scheduled Reminders # Agent-Powered Scheduled Reminder
- [Overview](background-agent-scheduled-reminder-overview.md) - [Agent-Powered Scheduled Reminder Overview](background-agent-scheduled-reminder-overview.md)
- [Development Guidelines](background-agent-scheduled-reminder-guide.md) - [Agent-Powered Scheduled Reminder Development](background-agent-scheduled-reminder-guide.md)
# Development Guidelines<a name="EN-US_TOPIC_0000001185364575"></a> # Agent-Powered Scheduled Reminder Development<a name="EN-US_TOPIC_0000001185364575"></a>
## When to Use<a name="section18502174174019"></a> ## When to Use<a name="section18502174174019"></a>
......
# Overview<a name="EN-US_TOPIC_0000001139084594"></a> # Agent-Powered Scheduled Reminder Overview<a name="EN-US_TOPIC_0000001139084594"></a>
Your application can call the **ReminderRequest** class to create scheduled reminders for countdown timers, calendar events, and alarm clocks. When the created reminders are published, the timing and pop-up notification functions of your application will be taken over by the reminder agent in the background, even when your application is frozen or exits. Your application can call the **ReminderRequest** class to create scheduled reminders for countdown timers, calendar events, and alarm clocks. When the created reminders are published, the timing and pop-up notification functions of your application will be taken over by the reminder agent in the background, even when your application is frozen or exits.
# Background Task Overview # Background Task Management Overview
Frequent activities of background applications cause user devices to consume power quickly and respond slowly. To meet performance and power consumption requirements, the system allows applications to execute only activities within the specifications in the background. Activities beyond the specifications are suspended by default, and resources allocated to them will be reclaimed when the available resources are insufficient. Frequent activities of background applications cause user devices to consume power quickly and respond slowly. To meet performance and power consumption requirements, the system allows applications to execute only activities within the specifications in the background. Activities beyond the specifications are suspended by default, and resources allocated to them will be reclaimed when the available resources are insufficient.
......
# Network and Connectivity # Connectivity
- Network Management - Network Management
- [Network Management Overview](net-mgmt-overview.md) - [Network Management Overview](net-mgmt-overview.md)
...@@ -7,5 +7,5 @@ ...@@ -7,5 +7,5 @@
- [Socket Connection](socket-connection.md) - [Socket Connection](socket-connection.md)
- IPC & RPC - IPC & RPC
- [IPC & RPC Overview](ipc-rpc-overview.md) - [IPC & RPC Overview](ipc-rpc-overview.md)
- [IPC & RPC Development Guidelines](ipc-rpc-development-guideline.md) - [IPC & RPC Development](ipc-rpc-development-guideline.md)
- [Subscribing to State Changes of a Remote Object](subscribe-remote-state.md) - [Subscribing to State Changes of a Remote Object](subscribe-remote-state.md)
...@@ -12,20 +12,20 @@ To use related APIs, you must declare the **ohos.permission.INTERNET** permissio ...@@ -12,20 +12,20 @@ To use related APIs, you must declare the **ohos.permission.INTERNET** permissio
The following table describes the related APIs. The following table describes the related APIs.
| API | Description | | API | Description |
| ----------------------------------------- | ----------------------------------- | | ----------------------------------------- | --------------------------------------------------------- |
| createHttp() | Creates an HTTP request. | | createHttp() | Creates an HTTP request. |
| request() | Initiates an HTTP request to a given URL. | | request() | Initiates an HTTP request to a given URL. |
| destroy() | Destroys an HTTP request. | | destroy() | Destroys an HTTP request. |
| on(type: 'headersReceive') | Registers an observer for HTTP Response Header events. | | on(type: 'headersReceive') | Registers an observer for HTTP Response Header events. |
| off(type: 'headersReceive') | Unregisters the observer for HTTP Response Header events.| | off(type: 'headersReceive') | Unregisters the observer for HTTP Response Header events. |
## How to Develop ## How to Develop
1. Import the required HTTP module. 1. Import the required HTTP module.
2. Create an **HttpRequest** object. 2. Create an **HttpRequest** object.
3. (Optional) Listen for HTTP Response Header events. 3. (Optional) Listen for HTTP Response Header events.
4. Initiates an HTTP request to a given URL. 4. Initiate an HTTP request to a given URL.
5. (Optional) Process the HTTP Response Header event and the return result of the HTTP request. 5. (Optional) Process the HTTP Response Header event and the return result of the HTTP request.
```js ```js
...@@ -71,3 +71,7 @@ httpRequest.request( ...@@ -71,3 +71,7 @@ httpRequest.request(
} }
); );
``` ```
## Samples
The following sample is provided to help you better understand how to develop the HTTP data request feature:
- [`Http`: HTTP Data Request (eTS) (API 8)](https://gitee.com/openharmony/app_samples/tree/master/Network/Http)
...@@ -6,7 +6,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -6,7 +6,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
## Available APIs<a name="section1633115419401"></a> ## Available APIs<a name="section1633115419401"></a>
**Table 1** Native IPC APIs **Table 1** Native IPC APIs
<a name="table178849240013"></a> <a name="table178849240013"></a>
<table><thead align="left"><tr id="row6884924608"><th class="cellrowborder" valign="top" width="14.12141214121412%" id="mcps1.2.4.1.1"><p id="p98846241706"><a name="p98846241706"></a><a name="p98846241706"></a>Class/Interface</p> <table><thead align="left"><tr id="row6884924608"><th class="cellrowborder" valign="top" width="14.12141214121412%" id="mcps1.2.4.1.1"><p id="p98846241706"><a name="p98846241706"></a><a name="p98846241706"></a>Class/Interface</p>
...@@ -44,9 +44,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -44,9 +44,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
**Using Native APIs** **Using Native APIs**
1. Define the IPC interface **ITestAbility**. 1. 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. **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.
``` ```
class ITestAbility : public IRemoteBroker { class ITestAbility : public IRemoteBroker {
...@@ -58,9 +58,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -58,9 +58,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
}; };
``` ```
2. Define and implement service provider **TestAbilityStub**. 2. 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<ITestAbility\>**. You need to override **OnRemoteRequest** on the stub to receive requests from the proxy.
``` ```
class TestAbilityStub : public IRemoteStub<ITestAbility> { class TestAbilityStub : public IRemoteStub<ITestAbility> {
...@@ -85,7 +85,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -85,7 +85,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
} }
``` ```
3. Define the **TestAbility** class that implements functions for the stub. 3. Define the **TestAbility** class that implements functions for the stub.
``` ```
class TestAbility : public TestAbilityStub { class TestAbility : public TestAbilityStub {
...@@ -98,9 +98,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -98,9 +98,9 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
} }
``` ```
4. Define and implement **TestAbilityProxy**. 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. 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> { class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
...@@ -128,7 +128,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -128,7 +128,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
5. Register and start an SA. 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. 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. // Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
...@@ -144,7 +144,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ...@@ -144,7 +144,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat
6. Obtain the SA. 6. Obtain the SA.
Call the **GetSystemAbility** function of the **SystemAbilityManager** class to obtain the **IRemoteObject** for the SA, and create a **TestAbilityProxy** instance. 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. // Obtain the proxy of the SA registered on the local device.
......
...@@ -19,4 +19,4 @@ In OpenHarmony documents, proxy represents the service requester, and stub repre ...@@ -19,4 +19,4 @@ In OpenHarmony documents, proxy represents the service requester, and stub repre
## Related Modules ## Related Modules
Distributed Scheduler [Distributed Scheduler](https://gitee.com/openharmony/distributedschedule_dms_fwk)
...@@ -10,26 +10,26 @@ Your application can transmit data through Socket connections. Currently, the TC ...@@ -10,26 +10,26 @@ Your application can transmit data through Socket connections. Currently, the TC
The Socket connection function is mainly implemented by the Socket module. The following table describes the related APIs. The Socket connection function is mainly implemented by the Socket module. The following table describes the related APIs.
| API| Description| | API| Description |
| -------- | -------- | | -------- | -------- |
| constructUDPSocketInstance() | Creates a **UDPSocket** object.| | constructUDPSocketInstance() | Creates a **UDPSocket** object. |
| constructTCPSocketInstance() | Creates a **TCPSocket** object.| | constructTCPSocketInstance() | Creates a **TCPSocket** object. |
| bind() | Binds the IP address and port number.| | bind() | Binds the IP address and port number. |
| send() | Sends data.| | send() | Sends data.|
| close() | Closes a Socket connection.| | close() | Closes a Socket connection. |
| getState() | Obtains the Socket connection status.| | getState() | Obtains the Socket connection status. |
| connect() | Connects to the specified IP address and port. This function is supported only for TCP.| | connect() | Connects to the specified IP address and port. This function is supported only for TCP. |
| getRemoteAddress() | Obtains the peer address of the Socket connection. This function is supported only for TCP. The **connect** API must have been called before you use this API.| | getRemoteAddress() | Obtains the peer address of the Socket connection. This function is supported only for TCP. The **connect** API must have been called before you use this API. |
| on(type:&nbsp;'message') | Enables listening for **message** events of the Socket connection.| | on(type:&nbsp;'message') | Enables listening for **message** events of the Socket connection. |
| off(type:&nbsp;'message') | Disables listening for **message** events of the Socket connection.| | off(type:&nbsp;'message') | Disables listening for **message** events of the Socket connection. |
| on(type:&nbsp;'close') | Enables listening for **close** events of the Socket connection.| | on(type:&nbsp;'close') | Enables listening for **close** events of the Socket connection. |
| off(type:&nbsp;'close') | Disables listening for **close** events of the Socket connection.| | off(type:&nbsp;'close') | Disables listening for **close** events of the Socket connection. |
| on(type:&nbsp;'error') | Enables listening for **error** events of the Socket connection.| | on(type:&nbsp;'error') | Enables listening for **error** events of the Socket connection. |
| off(type:&nbsp;'error') | Disables listening for **error** events of the Socket connection.| | off(type:&nbsp;'error') | Disables listening for **error** events of the Socket connection. |
| on(type:&nbsp;'listening') | Enables listening for **listening** events of the UDPSocket connection. | | on(type:&nbsp;'listening') | Enables listening for **listening** events of the UDPSocket connection. |
| off(type:&nbsp;'listening') | Disables listening for **listening** events of the UDPSocket connection. | | off(type:&nbsp;'listening') | Disables listening for **listening** events of the UDPSocket connection. |
| on(type:&nbsp;'connect') | Enables listening for **connect** events of the TCPSocket connection. | | on(type:&nbsp;'connect') | Enables listening for **connect** events of the TCPSocket connection. |
| off(type:&nbsp;'connect') | Disables listening for **connect** events of the TCPSocket connection.| | off(type:&nbsp;'connect') | Disables listening for **connect** events of the TCPSocket connection. |
## How to Develop ## How to Develop
...@@ -122,3 +122,7 @@ The implementation is similar for UDPSocket and TCPSocket. The following uses th ...@@ -122,3 +122,7 @@ The implementation is similar for UDPSocket and TCPSocket. The following uses th
tcp.off('close'); tcp.off('close');
}, 30 * 1000); }, 30 * 1000);
``` ```
## Samples
The following sample is provided to help you better understand how to develop the socket connection feature:
- [`Socket`: Socket Connection (eTS) (API 8)](https://gitee.com/openharmony/app_samples/tree/master/Network/Socket)
...@@ -12,20 +12,20 @@ If an error occurs in any of the preceding processes, the client will receive a ...@@ -12,20 +12,20 @@ If an error occurs in any of the preceding processes, the client will receive a
The WebSocket connection function is mainly implemented by the WebSocket module. To use related APIs, you must declare the **ohos.permission.INTERNET** permission. The following table describes the related APIs. The WebSocket connection function is mainly implemented by the WebSocket module. To use related APIs, you must declare the **ohos.permission.INTERNET** permission. The following table describes the related APIs.
| API| Description| | API | Description |
| -------- | -------- | | -------- | -------- |
| createWebSocket() | Creates a WebSocket connection.| | createWebSocket() | Creates a WebSocket connection. |
| connect() | Establishes a WebSocket connection to a given URL.| | connect() | Establishes a WebSocket connection to a given URL. |
| send() | Sends data through the WebSocket connection.| | send() | Sends data through the WebSocket connection. |
| close() | Closes a WebSocket connection.| | close() | Closes a WebSocket connection. |
| on(type:&nbsp;'open') | Enables listening for **open** events of a WebSocket connection.| | on(type:&nbsp;'open') | Enables listening for **open** events of a WebSocket connection. |
| off(type:&nbsp;'open') | Disables listening for **open** events of a WebSocket connection.| | off(type:&nbsp;'open') | Disables listening for **open** events of a WebSocket connection. |
| on(type:&nbsp;'message') | Enables listening for **message** events of a WebSocket connection.| | on(type:&nbsp;'message') | Enables listening for **message** events of a WebSocket connection. |
| off(type:&nbsp;'message') | Disables listening for **message** events of a WebSocket connection.| | off(type:&nbsp;'message') | Disables listening for **message** events of a WebSocket connection. |
| on(type:&nbsp;'close') | Enables listening for **close** events of a WebSocket connection.| | on(type:&nbsp;'close') | Enables listening for **close** events of a WebSocket connection. |
| off(type:&nbsp;'close') | Disables listening for **close** events of a WebSocket connection.| | off(type:&nbsp;'close') | Disables listening for **close** events of a WebSocket connection. |
| on(type:&nbsp;'error') | Enables listening for **error** events of a WebSocket connection.| | on(type:&nbsp;'error') | Enables listening for **error** events of a WebSocket connection. |
| off(type:&nbsp;'error') | Disables listening for **error** events of a WebSocket connection.| | off(type:&nbsp;'error') | Disables listening for **error** events of a WebSocket connection. |
## How to Develop ## How to Develop
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
- Relational Database - Relational Database
- [RDB Overview](database-relational-overview.md) - [RDB Overview](database-relational-overview.md)
- [RDB Development](database-relational-guidelines.md) - [RDB Development](database-relational-guidelines.md)
- Lightweight Data Store - Preferences
- [Lightweight Data Store Overview](database-preference-overview.md) - [Preferences Overview](database-preference-overview.md)
- [Lightweight Data Store Development](database-preference-guidelines.md) - [Preferences Development](database-preference-guidelines.md)
- Distributed Data Object - Distributed Data Object
- [Distributed Data Object Overview](database-distributedobject-overview.md) - [Distributed Data Object Overview](database-distributedobject-overview.md)
- [Distributed Data Object Development](database-distributedobject-guidelines.md) - [Distributed Data Object Development](database-distributedobject-guidelines.md)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
## When to Use ## When to Use
The distributed data objects allow data across devices to be processed like local variables by shielding complex data interaction between devices. For the devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other devices. The devices can listen for the data changes and online and offline states of other devices. The distributed data objects support basic data types, such as number, string, and Boolean, as well as complex data types, such as array and nested basic types. The distributed data objects allow data across devices to be processed like local variables by shielding complex data interaction between devices. For the devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other devices. The devices can listen for the data changes and online and offline status of other devices. The distributed data objects support basic data types, such as number, string, and Boolean, as well as complex data types, such as array and nested basic types.
## Available APIs ## Available APIs
...@@ -15,7 +15,7 @@ Call **createDistributedObject()** to create a distributed data object instance. ...@@ -15,7 +15,7 @@ Call **createDistributedObject()** to create a distributed data object instance.
**Table 1** API for creating a distributed data object instance **Table 1** API for creating a distributed data object instance
| Package| API| Description| | Package| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>- &nbsp;**source**: attributes of the **distributedObject** set.<br>- &nbsp;**DistributedObject**: returns the distributed object created.| | ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>-&nbsp;**source**: attributes of the **distributedObject** set.<br>-&nbsp;**DistributedObject**: returns the distributed object created.|
### Generating a Session ID ### Generating a Session ID
...@@ -28,12 +28,12 @@ Call **genSessionId()** to generate a session ID randomly. The generated session ...@@ -28,12 +28,12 @@ Call **genSessionId()** to generate a session ID randomly. The generated session
### Setting a SessionID for Distributed Data Objects ### Setting a SessionID for Distributed Data Objects
Call setSessionId() to set the 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. 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 **Table 3** API for setting a session ID
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for distributed data objects.<br>&nbsp;**sessionId**: ID of a distributed 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 distributed data objects.<br>&nbsp;**sessionId**: session ID of a distributed object in a trusted network. To remove a distributed data object from the network, set this parameter to "" or leave it empty.|
### Observing Data Changes ### Observing Data Changes
...@@ -43,7 +43,7 @@ Call **on()** to subscribe to data changes of a distributed data object. When th ...@@ -43,7 +43,7 @@ Call **on()** to subscribe to data changes of a distributed data object. When th
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Subscribes to data changes.| | DistributedDataObject| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Subscribes to data changes.|
| DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Unsubscribes from data changes. Callback used to return changes of the distributed object. If this parameter is not specified, all callbacks related to data changes will be unregistered.| | DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Unsubscribes from data changes. <br>**Callback**: specifies callback used to return changes of the distributed data object. If this parameter is not specified, all callbacks related to data changes will be unregistered.|
### Observing Online or Offline Status ### Observing Online or Offline Status
...@@ -90,10 +90,10 @@ The following example shows how to implement a distributed data object synchroni ...@@ -90,10 +90,10 @@ The following example shows how to implement a distributed data object synchroni
var remote_object = distributedObject.createDistributedObject({name:undefined, age:undefined, isVis:true, var remote_object = distributedObject.createDistributedObject({name:undefined, age:undefined, isVis:true,
parent:undefined, list:undefined}); parent:undefined, list:undefined});
remote_object.setSessionId(sessionId); remote_object.setSessionId(sessionId);
// After obtaining that the device status goes online, the remote object synchronizes data. That is, name changes to jack and age to 18. // After learning that the device goes online, the remote object synchronizes data. That is, name changes to jack and age to 18.
``` ```
4. Observe the data changes of the distributed data object. Subscribe to data changes of the remote end. When the data is the peer end changes, a callback will be called to return the data changes. 4. 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: The sample code is as follows:
...@@ -107,9 +107,9 @@ The following example shows how to implement a distributed data object synchroni ...@@ -107,9 +107,9 @@ The following example shows how to implement a distributed data object synchroni
}); });
} }
} }
// To refresh the page in changeCallback, correctly set this.changeCallback.bind(this) in // To refresh the page in changeCallback, correctly bind (this) to the changeCallback.
changeCallback. local_object.on("change", this.changeCallback.bind(this));
``` ```
5. Modify object attributes. The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types). 5. Modify object attributes. The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types).
...@@ -123,7 +123,7 @@ The following example shows how to implement a distributed data object synchroni ...@@ -123,7 +123,7 @@ The following example shows how to implement a distributed data object synchroni
local_object.list = [{mother:"jack mom"}, {father:"jack Dad"}]; local_object.list = [{mother:"jack mom"}, {father:"jack Dad"}];
``` ```
> ![icon-note.gif](../public_sys-resources/icon-note.gif) **NOTE**<br/> > ![icon-note.gif](public_sys-resources/icon-note.gif) **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. Example:
```js ```js
// Supported modification. // Supported modification.
...@@ -142,7 +142,7 @@ The following example shows how to implement a distributed data object synchroni ...@@ -142,7 +142,7 @@ The following example shows how to implement a distributed data object synchroni
The sample code is as follows: The sample code is as follows:
```js ```js
// Unsubscribe from changeCallback. // Unsubscribe from the specified data change callback.
local_object.off("change", changeCallback); local_object.off("change", changeCallback);
// Unsubscribe from all data change callbacks. // Unsubscribe from all data change callbacks.
local_object.off("change"); local_object.off("change");
...@@ -156,27 +156,27 @@ The following example shows how to implement a distributed data object synchroni ...@@ -156,27 +156,27 @@ The following example shows how to implement a distributed data object synchroni
local_object.on("status", this.statusCallback); local_object.on("status", this.statusCallback);
``` ```
9. Unsubscribe from the status changes of the distributed data object. You can specify the callback to unsubscribe from. If you do not specify the callback, all status change callbacks will be unsubscribe from. 9. Unsubscribe from the status changes of the distributed data object. You can specify the callback to unsubscribe from. If you do not specify the callback, this API unsubscribes from all callbacks of this distributed data object.
The sample code is as follows: The sample code is as follows:
```js ```js
// Unsubscribe from the online status change callback. // Unsubscribe from the specified status change callback.
local_object.off("status", statusCallback); local_object.off("status", statusCallback);
// Unsubscribe from all online status change callbacks. // Unsubscribe from all status change callbacks.
local_object.off("status"); local_object.off("status");
``` ```
10. Remove a distributed data object from the synchronization network. After the distributed data object is removed from the network, the data changes on the local end will not be synchronized to the remote end. 10. 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: The sample code is as follows:
```js ```js
local_object.setSessionId(""); local_object.setSessionId("");
``` ```
## Development Example ## Samples
The following example is provided for you to better understand the development of distributed data object: The following example is provided for you to better understand the development of distributed data objects:
- [Distributed Notepad](https://gitee.com/openharmony/distributeddatamgr_objectstore/tree/master/samples/distributedNotepad) - [Distributed Notepad](https://gitee.com/openharmony/distributeddatamgr_objectstore/tree/master/samples/distributedNotepad)
When an event occurs on a device, such as a note is added, the tile or content of a note is changed, and the event list is cleared, the change will be synchronized to other devices in the trusted network by the Notepad app. When an event of the Notepad app occurs on a device, such as a note is added, the tile or content of a note is changed, or the event list is cleared, the change will be synchronized to other devices in the trusted network.
...@@ -177,5 +177,5 @@ The following uses a single KV store as an example to describe the development p ...@@ -177,5 +177,5 @@ The following uses a single KV store as an example to describe the development p
``` ```
## Samples ## Samples
The following samples are provided to help you better understand the distributed data development: The following samples are provided to help you better understand the distributed data development:
- [`KvStore`: distributed database (eTS) (API8)](https://gitee.com/openharmony/app_samples/tree/master/data/Kvstore) - [`KvStore`: Distributed Data Management (eTS) (API8)](https://gitee.com/openharmony/app_samples/tree/master/data/Kvstore)
- [Distributed Database](https://gitee.com/openharmony/codelabs/tree/master/Data/JsDistributedData) - [Distributed Data Service](https://gitee.com/openharmony/codelabs/tree/master/Data/JsDistributedData)
# Lightweight Data Store Development # Preferences Development
## When to Use ## When to Use
The lightweight data store is ideal for storing lightweight and frequently used data, but not for storing a large amount of data or data with frequent changes. The application data is persistently stored on a device in the form of files. Note that the instance accessed by an application contains all data of the file. The data is always loaded to the memory of the device until the application removes it from the memory. The application can perform data operations using the **Storage** APIs. Preferences are ideal for storing data frequently used by applications, but not for storing a large amount of data or data with frequent changes. The application data is persistently stored on a device in the form of files. Note that the instance accessed by an application contains all data of the file. The data is always loaded to the memory of the device until the application removes it from the memory. The application can perform data operations using the **Preferences** APIs.
## Available APIs ## Available APIs
The lightweight data store provides applications with data processing capability and allows applications to perform lightweight data storage and query. Data is stored in key-value (KV) pairs. Keys are of the string type, and values can be of the number, string, or Boolean type. Preferences provide capabilities for processing data in the form of key-value (KV) pairs and support data persistence, modification, and query. In KV pairs, keys are of the string type, and values can be of the number, string, or Boolean type.
**Creating a Storage Instance** ### Creating a Preferences Instance
Create a **Storage** instance for data operations. A **Storage** instance is created after data is read from a specified file and loaded to the instance. Create a **Preferences** instance for data operations. A **Preferences** instance is created after data is read from a specified file and loaded to the instance.
**Table 1** API for creating a **Storage** instance **Table 1** API for creating a **Preferences** instance
| Package | API | Description | | Package | API | Description |
| ----------------- | ------------------------------------------- | ------------------------------------------- | | ----------------- | ------------------------------------------- | ------------------------------------------- |
| ohos.data.storage | getStorage(path: string): Promise\<Storage> | Obtains the **Storage** singleton corresponding to a file for data operations.| | ohos.data.preferences | getPreferences(context: Context, name: string): Promise\<Preferences> | Obtains a **Preferences** instance for data operations.|
**Writing Data** ### Writing Data
Call the **put()** method to add or modify data in a **Storage** instance. Call the **put()** method to add or modify data in a **Preferences** instance.
**Table 2** API for writing data **Table 2** API for writing data
| Class | API | Description | | Class | API | Description |
| ------- | -------------------------------------------------- | ----------------------------------------------- | | ------- | -------------------------------------------------- | ----------------------------------------------- |
| Storage | put(key: string, value: ValueType): Promise\<void> | Writes data of the number, string, and Boolean types.| | Preferences | put(key: string, value: ValueType): Promise\<void> | Writes data of the number, string, and Boolean types.|
**Reading Data** ### Reading Data
Call the **get()** method to read data from a **Storage** instance. Call the **get()** method to read data from a **Preferences** instance.
**Table 3** API for reading data **Table 3** API for reading data
| Class | API | Description | | Class | API | Description |
| ------- | ---------------------------------------------------------- | ----------------------------------------------- | | ------- | ---------------------------------------------------------- | ----------------------------------------------- |
| Storage | get(key: string, defValue: ValueType): Promise\<ValueType> | Reads data of the number, string, and Boolean types.| | Preferences | get(key: string, defValue: ValueType): Promise\<ValueType> | Reads data of the number, string, and Boolean types.|
**Storing Data Persistently** ### Storing Data Persistently
Call the **flush()** method to write the cached data back to its text file for persistent storage. Call the **flush()** method to write the cached data back to its text file for persistent storage.
...@@ -46,119 +46,120 @@ Call the **flush()** method to write the cached data back to its text file for p ...@@ -46,119 +46,120 @@ Call the **flush()** method to write the cached data back to its text file for p
| Class | API | Description | | Class | API | Description |
| ------- | ----------------------- | --------------------------------------- | | ------- | ----------------------- | --------------------------------------- |
| Storage | flush(): Promise\<void> | Writes data in the **Storage** instance back to its file through an asynchronous thread.| | Preferences | flush(): Promise\<void> | Writes data from the **Preferences** instance back to its file through an asynchronous thread.|
**Observing Data Changes** ### Observing Data Changes
Specify **StorageObserver** as the callback to subscribe to data changes. When the value of the subscribed key is changed and the **flush()** method is executed, **StorageObserver** will be invoked. You can subscribe to data changes. When the value of the subscribed key is changed by **flush()**, a callback will be invoked to return the new data.
**Table 5** APIs for observing data changes **Table 5** APIs for observing **Preferences** changes
| Class | API | Description | | Class | API | Description |
| ------- | ------------------------------------------------------------ | -------------- | | ------- | ------------------------------------------------------------ | -------------- |
| Storage | on(type: 'change', callback: Callback\<StorageObserver>): void | Subscribe to data changes.| | Preferences | on(type: 'change', callback: Callback<{ key : string }>): void | Subscribes to data changes.|
| Storage | off(type: 'change', callback: Callback\<StorageObserver>): void | Unsubscribes from data changes. | | Preferences | off(type: 'change', callback: Callback<{ key : string }>): void | Unsubscribes from data changes. |
**Deleting Data** ### Deleting Data
Use the following APIs to delete a **Storage** instance or data file. Use the following APIs to delete a **Preferences** instance or data file.
**Table 6** APIs for deleting data **Table 6** APIs for deleting **Preferences**
| Package | API | Description | | Package | API | Description |
| ----------------- | ---------------------------------------------------- | ------------------------------------------------------------ | | ----------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| ohos.data.storage | deleteStorage(path: string): Promise\<void> | Deletes a **Storage** instance from the cache and deletes its file from the device.| | ohos.data.preferences | deletePreferences(context: Context, name: string): Promise<void>; | Deletes a **Preferences** instance from the cache and deletes its file from the device.|
| ohos.data.storage | removeStorageFromCache(path: string): Promise\<void> | Deletes a **Storage** instance from the cache to release memory. | | ohos.data.preferences | removePreferencesFromCache(context: Context, name: string): Promise\<void>; | Removes a **Preferences** instance from the memory to release memory.
## How to Develop ## How to Develop
1. Import @ohos.data.storage and related modules to the development environment. 1. Import @ohos.data.preferences and related modules to the development environment.
```js ```js
import dataStorage from '@ohos.data.storage' import data_preferences from '@ohos.data.preferences'
import featureAbility from '@ohos.ability.featureAbility' // Used to obtain the file storage path.
``` ```
2. Create a **Storage** instance. 2. Create a **Preferences** instance.
Read the specified file and load its data to the **Storage** instance for data operations. Read the specified file and load its data to the **Preferences** instance for data operations.
```js ```js
var context = featureAbility.getContext() let promise = data_preferences.getPreferences(this.context, 'mystore')
context.getFilesDir().then(() => {
console.info("======================>getFilesDirPromsie====================>");
});
let promise = dataStorage.getStorage(path + '/mystore')
``` ```
3. Write data. 3. Write data.
Use the **put()** method of the **Storage** class to write data to the cached **Storage** instance. Use the **put()** method of the **Preferences** class to write data to the cached **Preferences** instance.
```js ```js
promise.then((storage) => { promise.then((preferences) => {
let getPromise = storage.put('startup', 'auto') // Save data to the Storage instance. let getPromise = preferences.put('startup', 'auto')
getPromise.then(() => { getPromise.then(() => {
console.info("Put the value of startup successfully.") console.info("Put the value of startup successfully.")
}).catch((err) => { }).catch((err) => {
console.info("Put the value of startup failed with err: " + err) console.info("Failed to put the value of startup with err: " + err)
}) })
}).catch((err) => { }).catch((err) => {
console.info("Get the storage failed") console.info("Failed to get the preferences")
}) })
``` ```
4. Read data. 4. Read data.
Use the **get()** method of the **Storage** class to read data. Use the **get()** method of the **Preferences** class to read data.
```js ```js
promise.then((storage) => { promise.then((preferences) => {
let getPromise = storage.get('startup', 'default') let getPromise = preferences.get('startup', 'default')
getPromise.then((value) => { getPromise.then((value) => {
console.info("The value of startup is " + value) console.info("The value of startup is " + value)
}).catch((err) => { }).catch((err) => {
console.info("Get the value of startup failed with err: " + err) console.info("Failed to get the value of startup with err: " + err)
}) })
}).catch((err) => { }).catch((err) => {
console.info("Get the storage failed")}) console.info("Failed to get the preferences")})
``` ```
5. Store data persistently. 5. Store data persistently.
Use the **flush()** or **flushSync()** method to flush data in the **Storage** instance to its file. Use the **flush()** method to flush data from the **Preferences** instance to its file.
```js ```js
storage.flush(); preferences.flush();
``` ```
6. Observe data changes. 6. Observe data changes.
Specify **StorageObserver** as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and the **flush()** method is executed, **StorageObserver** will be invoked. Unregister the **StorageObserver** when it is no longer required. Specify an observer as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and the **flush()** method is executed, the observe callback will be invoked to return the change.
```js ```js
promise.then((storage) => { var observer = function (key) {
var observer = function (key) { console.info("The key of " + key + " changed.")
console.info("The key of " + key + " changed.") }
} preferences.on('change', observer)
storage.on('change', observer) preferences.put('startup', 'auto', function (err) {
storage.putSync('startup', 'auto') // Modify data in the Storage instance. if (err) {
storage.flushSync() // Trigger the StorageObserver callback. console.info("Failed to put the value of startup with err: " + err)
return
storage.off(...change..., observer) // Unsubscribe from the data changes. }
}).catch((err) => { console.info("Put the value of startup successfully.")
console.info("Get the storage failed") preferences.flush(function (err) {
}) if (err) {
console.info("Failed to flush data to file with err: " + err)
return
}
console.info("Flushed to file successfully.") // Observer will be called.
})
})
``` ```
7. Delete the specified file. 7. Delete the specified file.
Use the **deleteStorage** method to delete the **Storage** singleton of the specified file from the memory, and delete the specified file, its backup file, and damaged files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will occur. The deleted data and files cannot be restored. Use the **deletePreferences** method to delete the **Preferences** singleton of the specified file from the memory, and delete the specified file, its backup file, and corrupted files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will occur. The deleted data and files cannot be restored.
```js ```js
let promise = dataStorage.deleteStorage(path + '/mystore') let proDelete = data_preferences.deletePreferences(context, 'mystore')
promise.then(() => { proDelete.then(() => {
console.info("Deleted successfully.") console.info("Data deleted successfully.")
}).catch((err) => { }).catch((err) => {
console.info("Deleted failed with err: " + err)}) console.info("Failed to delete data with err: " + err)
})
``` ```
# Lightweight Data Store Overview<a name="EN-US_TOPIC_0000001230752103"></a> # Preferences Overview
Lightweight data store is applicable to access and persistence operations on the data in key-value pairs. When an application accesses a lightweight **Storage** instance, data in the **Storage** instance will be cached in the memory for faster access. The cached data can also be written back to the text file for persistent storage. Since file read and write consume system resources, you are advised to minimize the frequency of reading and writing persistent files. Preferences are used for access and persistence operations on the data in the key-value structure. When an application accesses a **Preferences** instance, the data in the instance will be cached in the memory for faster access. The cached data can also be written back to the text file for persistent storage. Since file read and write consume system resources, you are advised to minimize the frequency of reading and writing persistent files.
## Basic Concepts<a name="section1055404171115"></a> ## Basic Concepts
- **Key-Value data structure** - **Key-value data structure**
A type of data structure. The key is the unique identifier for a piece of data, and the value is the specific data being identified. A type of data structure. The key is the unique identifier for a piece of data, and the value is the specific data being identified.
- **Non-relational database** - **Non-relational database**
A database not in compliance with the atomicity, consistency, isolation, and durability \(ACID\) database management properties of relational data transactions. The data in a non-relational database is independent. A database not in compliance with the atomicity, consistency, isolation, and durability (ACID) database management properties of relational data transactions. The data in a non-relational database is independent.
## Working Principles
## Working Principles<a name="section682631371115"></a> When an application loads data from a **Preferences** file to a **Preferences** instance, the system stores the instance in the memory through a static container. Each file of an application or process has only one **Preferences** instance in the memory, till the application removes the instance from the memory or deletes the **Preferences** file.
1. When an application loads data from a specified **Storage** file to a **Storage** instance, the system stores the instance in the memory through a static container. Each file of an application or process has only one **Storage** instance in the memory, till the application removes the instance from the memory or deletes the **Storage** file. When obtaining a **Preferences** instance, the application can read data from or write data to the instance. The data in the instance can be flushed to its **Preferences** file by calling the **flush()** method.
2. When obtaining a **Storage** instance, the application can read data from or write data to the instance. The data in the **Storage** instance can be flushed to its **Storage** file by calling the **flush** or **flushSync** method.
**Figure 1** How lightweight data store works<a name="fig1657785713509"></a> **Figure 1** How **Preferences** work
![](figures/preferences.png)
![](figures/en-us_image_0000001199139454.png) ## Constraints
## Constraints<a name="section17243172883219"></a>
- **Storage** instances are loaded to the memory. To minimize non-memory overhead, the number of data records stored in a **Storage** instance cannot exceed 10,000. Delete the instances that are no longer used in a timely manner.
- The key in the key-value pairs is of the string type. It cannot be empty or exceed 80 characters.
- If the value in the key-value pairs is of the string type, it can be empty or contain a maximum of 8192 characters.
- **Preferences** instances are loaded to the memory. To minimize non-memory overhead, the number of data records stored in a **Preferences** instance cannot exceed 10,000. Delete the instances that are no longer used in a timely manner.
- The key in key-value pairs is of the string type. It cannot be empty or exceed 80 bytes.
- The value of the string type in key-value pairs can be empty, but cannot exceed 8192 bytes if not empty.
...@@ -116,8 +116,8 @@ The RDB provides **RdbPredicates** for you to set database operation conditions. ...@@ -116,8 +116,8 @@ The RDB provides **RdbPredicates** for you to set database operation conditions.
A result set can be regarded as a row of data in the queried results. It allows you to traverse and access the data you have queried. The following table describes the external APIs of **ResultSet**. A result set can be regarded as a row of data in the queried results. It allows you to traverse and access the data you have queried. The following table describes the external APIs of **ResultSet**.
> ![icon-notice.gif](../public_sys-resources/icon-notice.gif) **NOTICE**<br/> > ![icon-notice.gif](public_sys-resources/icon-notice.gif) **NOTICE**<br>
> After a result set is used, you must call the **close()** method to close it explicitly.** > After a result set is used, you must call the **close()** method to close it explicitly.
**Table 7** APIs for using the result set **Table 7** APIs for using the result set
...@@ -306,3 +306,8 @@ You can obtain the distributed table name for a remote device based on the local ...@@ -306,3 +306,8 @@ You can obtain the distributed table name for a remote device based on the local
let tableName = rdbStore.obtainDistributedTableName(deviceId, "test"); let tableName = rdbStore.obtainDistributedTableName(deviceId, "test");
let resultSet = rdbStore.querySql("SELECT * FROM " + tableName) let resultSet = rdbStore.querySql("SELECT * FROM " + tableName)
``` ```
## Samples
The following samples are provided for you to better understand the RDB development:
- [`Rdb`: eTS RDB (API8)](https://gitee.com/openharmony/app_samples/tree/master/data/Rdb)
- [`DistributedRdb`: eTS Distributed Relational Database (API8)](https://gitee.com/openharmony/app_samples/tree/master/data/DistributedRdb)
- [Relational Database](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData)
...@@ -13,3 +13,6 @@ ...@@ -13,3 +13,6 @@
- Vibrator - Vibrator
- [Vibrator Overview](vibrator-overview.md) - [Vibrator Overview](vibrator-overview.md)
- [Vibrator Development](vibrator-guidelines.md) - [Vibrator Development](vibrator-guidelines.md)
- Update Servcie
- [Sample Server Overview](sample-server-overview.md)
- [Sample Server Development](sample-server-guidelines.md)
# Sample Server Development
## When to Use
The sample server provides a package search server for checking update packages and obtaining the update package download URLs, which was previously unavailable in the real-world update service. The sample server supports update service testing and secondary development function verification, building an end-to-end environment to cater for diverse update service use cases.
## How to Develop
1. Generate an SSL certificate.
Generate the **serverKey.pem** and **serverCert.cer** files for SSL communication of the sample server.
```
openssl req -newkey rsa:2048 -nodes -keyout serverKey.pem -x509 -days 365 -out serverCert.cer -subj "/C=CN/ST=GD/L=GZ/O=abc/OU=defg/CN=hijk/emailAddress=test.com"
```
2. Modify the **bundle.json** file.
Add **sub_component** to the **build** field.
```
"sub_component": [
"//base/update/updateservice/server_sample:testserver",
...
],
```
3. Create a code directory.
Go to the **update_updateservice** directory and run the following commands to create a code directory:
```
mkdir server_sample // Create the server_sample folder.
touch server_sample/BUILD.gn // Create the BUILD.gn file.
mkdir server_sample/include // Create the include folder to store the header file of the sample server.
touch server_process.h // Create the server_process.h header file.
mkdir server_sample/src // Create the src folder to store the C/C++ files of the sample server.
touch server_sample/src/server_process.c // Create the server_process.c file.
touch server_sample/src/main.cpp // Create the main.cpp file.
```
4. Write the **BUILD.gn** file.
The **BUILD.gn** file contains two **ohos** components: **ohos_shared_library** file named **libserver_process.z.so** and **ohos_executable** file named **testserver**.
```
import("//build/ohos.gni")
ohos_shared_library("server_process") {
sources = [
"//base/update/updateservice/server_sample/src/server_process.c",
]
include_dirs = [
"//base/update/updateservice/server_sample/include",
"//third_party/openssl/include",
]
deps = [
"//base/update/updater/services/log:libupdaterlog",
"//third_party/bounds_checking_function:libsec_static",
"//third_party/openssl:crypto_source",
"//third_party/openssl:ssl_source",
"//utils/native/base:utils",
]
part_name = "update_service"
}
ohos_executable("testserver") {
sources = [
"//base/update/updateservice/server_sample/src/main.cpp",
]
include_dirs = [
"//base/update/updateservice/server_sample/include",
]
deps = [
"//base/update/updateservice/server_sample:server_process",
]
part_name = "update_service"
}
```
5. Write the **server_process.h** file.
Declare the sample server APIs in the **server_process.h** file.
```c++
#ifndef __SERVER_PROCESS_H__
#define __SERVER_PROCESS_H__
/*
Init: creates a socket environment and presets certain attributes.
*/
int Init();
/*
SetParam: sets all plug-in parameters.
*/
int SetParam(const char *key, const char *value);
/*
GetParam: obtains all plug-in parameters.
*/
int GetParam(const char *key, char *value);
/*
ReverseSetParamCallback: callback.
*/
int ReverseSetParamCallback(int(*setParam)(const char *key, const char *value));
/*
Open: starts the service.
*/
int Open();
/*
MainLoop: invoked every 100 ms.
*/
int MainLoop();
/*
Close: stops the service and releases related resources.
*/
int Close();
#endif //__SERVER_PROCESS_H__
```
6. Write the **server_process.c** and **main.cpp** files.
In the **server_process.c** file, mainly declare **respondContent**, the format of the response message returned by the server. Write the **main.cpp** file based on instructions for the common SSL protocol server. Be sure to include related header files and load the **serverKey.pem** and **serverCert.cer** files.
```c
#include "server_process.h"
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "openssl/err.h"
#include "openssl/ssl.h"
#define SERVER_PEM "/data/sdcard/serverKey.pem" // Use an absolute path.
#define SERVER_CER "/data/sdcard/serverCert.cer" // Use an absolute path.
#define LOG_PRINT(fmt, ...) printf("[ServerProcess][%s:%d] " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#define DO_CHECK(cond, log, ...) \
if (!(cond)) {\
LOG_PRINT(log);\
__VA_ARGS__;\
return -1;\
}
// Implement the function by referring to the APIs in the server_process.h file. Pay attention to the format of the response message from the server.
respondContent = "{"
"\"searchStatus\": 0,"
"\"errMsg\": \"success\","
"\"checkResults\": [{"
"\"versionName\": \"sampleVersionName\","
"\"versionCode\": \"sampleVersionCode\","
"\"verifyInfo\": \"sampleVerifyInfoSha256Value\","
"\"size\": 1234567,"
"\"packageType\": 1,"
"\"descriptPackageId\": \"abcdefg1234567ABCDEFG\","
"}],"
"\"descriptInfo\": [{"
"\"descriptPackageId\": \"abcdefg1234567ABCDEFG\","
"\"content\": \"This package message is used for sampleContent\""
"}]"
"}";
```
7. Start building.
The **testserver** and **libserver_process.z.so** files are added to the build output directory.
8. Develop an update package.
For details, see the [update_packaging_tools repository](https://gitee.com/openharmony/update_packaging_tools).
9. Start the package search server.
Create a directory that contains only English characters on the development board. Place the **testserver**, **libserver_process.z.so**, **serverCert.cer**, and **serverKey.pem** files in the directory, go to the directory, and run the following command to start the package search server:
```
./testserver ./libserver_process.z.so &
```
# Sample Server Overview
The sample server provides a simple server instance for deploying update packages. It can be used as an auxiliary test environment for the UpdateService subsystem.
## Basic Concepts
- Package search service: one of the service capabilities provided by the UpdateService. It depends on the server that supports the TCP and SSL protocols.
- Package search server: a server that provisions the package search service through the TCP connection and the SSL protocol. The sample server mentioned in this document is such a package search server.
- Download server: an HTTP server.
- update.serverip.search: a system parameter that indicates the IP address of the package search server configured on the UpdateService. The default value is **127.0.0.1**.
## Constraints
The following is an example of the JSON response returned by the server. Note that the **verifyInfo** field indicates the SHA-256 value of the update package, and the **size** field indicates the size of the update package, in bytes.
```json
{
"searchStatus": 0,
"errMsg": "success",
"checkResults": [{
"versionName": "versionNameSample",
"versionCode": "versionCodeSample",
"verifyInfo": "verifyInfoSHA256Value1234567",
"size": 1234567,
"packageType": 1,
"url": "http://serverAddressSample/packageNameSample.fileTypeSample",
"descriptPackageId": "abcdefg1234567ABCDEFG"
}],
"descriptInfo": [{
"descriptPackageId": "abcdefg1234567ABCDEFG",
"content": "This package is used for update."
}]
}
```
...@@ -20,38 +20,38 @@ You can set different vibration effects as needed, for example, customizing the ...@@ -20,38 +20,38 @@ You can set different vibration effects as needed, for example, customizing the
## How to Develop ## How to Develop
1. Declare the permissions required for controlling vibrators on the hardware device in the **config.json** file. 1. Declare the permissions required for controlling vibrators on the hardware device in the `config.json` file.
``` ```
"reqPermissions":[ "reqPermissions": [
{ {
"name":"ohos.permission.ACCELEROMETER", "name": "ohos.permission.ACCELEROMETER",
"reason"":"", "reason": "",
"usedScene":{ "usedScene": {
"ability""[ "ability": [
".MainAbility" ".MainAbility"
], ],
"when":"inuse" "when": "inuse"
} }
}, },
{ {
"name":"ohos.permission.VIBRATE", "name": "ohos.permission.VIBRATE",
"reason"":"", "reason": "",
"usedScene":{ "usedScene": {
"ability""[ "ability": [
".MainAbility" ".MainAbility"
], ],
"when":"inuse" "when": "inuse"
} }
}, },
{ {
"name":"ohos.permission.ACTIVITY_MOTION", "name": "ohos.permission.ACTIVITY_MOTION",
"reason"":"", "reason": "",
"usedScene":{ "usedScene": {
"ability""[ "ability": [
".MainAbility" ".MainAbility"
], ],
"when":"inuse" "when": "inuse"
} }
}, },
] ]
...@@ -77,7 +77,7 @@ You can set different vibration effects as needed, for example, customizing the ...@@ -77,7 +77,7 @@ You can set different vibration effects as needed, for example, customizing the
vibrator.stop(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_PRESET).then((error)=>{ vibrator.stop(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_PRESET).then((error)=>{
if(error){ // The call fails, and error.code and error.message are printed. if(error){ // The call fails, and error.code and error.message are printed.
Console.log("Promise return failed.error.code"+error.code+"error.message"+error.message); Console.log("Promise return failed.error.code"+error.code+"error.message"+error.message);
}else{ // The call is successful, and the device stops vibration. }else{ // The call is successful, and the device stops vibrating.
Console.log("Promise returned to indicate a successful stop."); Console.log("Promise returned to indicate a successful stop.");
}; };
}) })
......
...@@ -75,4 +75,4 @@ In this example, an application event is logged after the application startup ex ...@@ -75,4 +75,4 @@ In this example, an application event is logged after the application startup ex
The following sample is provided to help you better understand how to develop the application event logging feature: The following sample is provided to help you better understand how to develop the application event logging feature:
- [`JsDotTest`: Event Logging Test (JavaScript) (API 7)](https://gitee.com/openharmony/app_samples/tree/master/DFX/JsDotTest) - [`JsDotTest`: Event Logging Test (JavaScript) (API 8)](https://gitee.com/openharmony/app_samples/tree/master/DFX/JsDotTest)
...@@ -4,11 +4,10 @@ ...@@ -4,11 +4,10 @@
- [Audio Overview](audio-overview.md) - [Audio Overview](audio-overview.md)
- [Audio Playback Development](audio-playback.md) - [Audio Playback Development](audio-playback.md)
- [Audio Recording Development](audio-recorder.md) - [Audio Recording Development](audio-recorder.md)
- [Audio Rendering Development](audio-renderer.md) - [Audio Rendering Development](audio-renderer.md)
- [Audio Capture Development](audio-capturer.md)
- [Audio Capture Development](audio-capturer) - [OpenSL ES Audio Playback Development](opensles-playback.md)
- Video - Video
- [Video Playback Development](video-playback.md) - [Video Playback Development](video-playback.md)
......
...@@ -25,46 +25,49 @@ The full audio recording process includes creating an instance, setting recordin ...@@ -25,46 +25,49 @@ The full audio recording process includes creating an instance, setting recordin
```js ```js
import media from '@ohos.multimedia.media' import media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary' import mediaLibrary from '@ohos.multimedia.mediaLibrary'
export class AudioRecorderDemo {
let testFdNumber; private testFdNumber; // Used to save the FD address.
function SetCallBack(audioRecorder) { // Set the callbacks related to audio recording.
audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. setCallBack(audioRecorder) {
console.log('prepare success'); audioRecorder.on('prepare', () => { // Set the prepare event callback.
// The recording page is ready. You can click the Record button to start recording. console.log('prepare success');
audioRecorder.start(); // Call the start API to start recording and trigger the start event callback.
}); });
audioRecorder.on('start', () => { // Set the 'start' event callback. audioRecorder.on('start', () => { // Set the start event callback.
console.log('audio recorder start success'); console.log('audio recorder start success');
// The Record button is changed to the pausable state. audioRecorder.pause(); // Call the pause API to pause recording and trigger the pause event callback.
}); });
audioRecorder.on('pause', () => { // Set the 'pause' event callback. audioRecorder.on('pause', () => { // Set the pause event callback.
console.log('audio recorder pause success'); console.log('audio recorder pause success');
// The Record button is changed to the recordable state. audioRecorder.resume(); // Call the resume API to resume recording and trigger the resume event callback.
}); });
audioRecorder.on('resume', () => { // Set the 'resume' event callback. audioRecorder.on('resume', () => { // Set the resume event callback.
console.log('audio recorder resume success'); console.log('audio recorder resume success');
// The Record button is changed to the pausable state. audioRecorder.stop(); // Call the stop API to stop recording and trigger the stop event callback.
}); });
audioRecorder.on('stop', () => { // Set the 'stop' event callback. audioRecorder.on('stop', () => { // Set the stop event callback.
console.log('audio recorder stop success'); console.log('audio recorder stop success');
audioRecorder.reset(); // Call the reset API to reset the recorder and trigger the reset event callback.
}); });
audioRecorder.on('release', () => { // Set the 'release' event callback. audioRecorder.on('reset', () => { // Set the reset event callback.
console.log('audio recorder release success'); console.log('audio recorder reset success');
audioRecorder.release(); // Call the release API to release resources and trigger the release event callback.
}); });
audioRecorder.on('reset', () => { // Set the 'reset' event callback. audioRecorder.on('release', () => { // Set the release event callback.
console.log('audio recorder reset success'); console.log('audio recorder release success');
// You need to reset the recording parameters for another recording. audioRecorder = undefined;
}); });
audioRecorder.on('error', (error) => { // Set the 'error' event callback. audioRecorder.on('error', (error) => { // Set the error event callback.
console.info(`audio error called, errName is ${error.name}`); console.info(`audio error called, errName is ${error.name}`);
console.info(`audio error called, errCode is ${error.code}`); console.info(`audio error called, errCode is ${error.code}`);
console.info(`audio error called, errMessage is ${error.message}`); console.info(`audio error called, errMessage is ${error.message}`);
}); });
} }
// pathName indicates the passed recording file name, for example, 01.mp3. The generated file address is /storage/media/100/local/files/Movies/01.mp3. // pathName indicates the passed recording file name, for example, 01.mp3. The generated file address is /storage/media/100/local/files/Video/01.mp3.
// To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. // To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA.
async function getFd(pathName) { async getFd(pathName) {
let displayName = pathName; let displayName = pathName;
const mediaTest = mediaLibrary.getMediaLibrary(); const mediaTest = mediaLibrary.getMediaLibrary();
let fileKeyObj = mediaLibrary.FileKey; let fileKeyObj = mediaLibrary.FileKey;
...@@ -72,49 +75,37 @@ async function getFd(pathName) { ...@@ -72,49 +75,37 @@ async function getFd(pathName) {
let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO); let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath); let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath);
if (dataUri != undefined) { if (dataUri != undefined) {
let args = dataUri.id.toString(); let args = dataUri.id.toString();
let fetchOp = { let fetchOp = {
selections : fileKeyObj.ID + "=?", selections : fileKeyObj.ID + "=?",
selectionArgs : [args], selectionArgs : [args],
} }
let fetchFileResult = await mediaTest.getFileAssets(fetchOp); let fetchFileResult = await mediaTest.getFileAssets(fetchOp);
let fileAsset = await fetchFileResult.getAllObject(); let fileAsset = await fetchFileResult.getAllObject();
let fdNumber = await fileAsset[0].open('Rw'); let fdNumber = await fileAsset[0].open('Rw');
fdNumber = "fd://" + fdNumber.toString(); this.testFdNumber = "fd://" + fdNumber.toString();
testFdNumber = fdNumber;
} }
}
async audioRecorderDemo() {
// 1. Create an AudioRecorder instance.
let audioRecorder = media.createAudioRecorder();
// 2. Set the callbacks.
this.setCallBack(audioRecorder);
await this.getFd('01.mp3'); // Call the getFd method to obtain the FD address of the file to be recorded.
// 3. Set the recording parameters.
let audioRecorderConfig = {
audioEncodeBitRate : 22050,
audioSampleRate : 22050,
numberOfChannels : 2,
uri : this.testFdNumber, // testFdNumber is generated by getFd.
location : { latitude : 30, longitude : 130},
audioEncoderMime : media.CodecMimeType.AUDIO_AAC,
fileFormat : media.ContainerFormatType.CFT_MPEG_4A,
}
audioRecorder.prepare(audioRecorderConfig); // Call the prepare method to trigger the prepare event callback.
}
} }
await getFd('01.mp3');
// 1. Create an AudioRecorder instance.
let audioRecorder = media.createAudioRecorder();
// 2. Set the callbacks.
SetCallBack(audioRecorder);
// 3. Set the recording parameters.
let audioRecorderConfig = {
audioEncoder : media.AudioEncoder.AAC_LC ,
audioEncodeBitRate : 22050,
audioSampleRate : 22050,
numberOfChannels : 2,
format : media.AudioOutputFormat.AAC_ADTS,
uri : testFdNumber, // testFdNumber is generated by getFd.
location : { latitude : 30, longitude : 130},
}
audioRecorder.prepare(audioRecorderConfig);
// 4. Start recording.
audioRecorder.start(); // The start API can be called to trigger the 'start' event callback only after the 'prepare' event callback is complete.
// 5. Pause recording.
audioRecorder.pause(); // The pause API can be called to trigger the 'pause' event callback only after the 'start' event callback is complete.
// 6. Resume recording.
audioRecorder.resume(); // The resume API can be called to trigger the 'resume' event callback only after the 'pause' event callback is complete.
// 7. Stop recording.
audioRecorder.stop(); // The stop API can be called to trigger the 'stop' event callback only after the 'start' or 'resume' event callback is complete.
// 8. Reset recording.
audioRecorder.reset(); // The prepare API can be called for another recording only after the 'reset' event callback is complete.
// 9. Release resources.
audioRecorder.release(); // The AudioRecorder resource is destroyed.
audioRecorder = undefined;
``` ```
### Normal Recording Scenario ### Normal Recording Scenario
...@@ -124,29 +115,37 @@ Unlike the full-process scenario, the normal recording scenario does not include ...@@ -124,29 +115,37 @@ Unlike the full-process scenario, the normal recording scenario does not include
```js ```js
import media from '@ohos.multimedia.media' import media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary' import mediaLibrary from '@ohos.multimedia.mediaLibrary'
export class AudioRecorderDemo {
let testFdNumber; private testFdNumber; // Used to save the FD address.
function SetCallBack(audioRecorder) { // Set the callbacks related to audio recording.
audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. setCallBack(audioRecorder) {
console.log('prepare success'); audioRecorder.on('prepare', () => { // Set the prepare event callback.
// The recording page is ready. You can click the Record button to start recording. console.log('prepare success');
audioRecorder.start(); // Call the start API to start recording and trigger the start event callback.
}); });
audioRecorder.on('start', () => { // Set the 'start' event callback. audioRecorder.on('start', () => { // Set the start event callback.
console.log('audio recorder start success'); console.log('audio recorder start success');
// The Record button is changed to the pausable state. audioRecorder.stop(); // Call the stop API to stop recording and trigger the stop event callback.
}); });
audioRecorder.on('stop', () => { // Set the 'stop' event callback. audioRecorder.on('stop', () => { // Set the stop event callback.
console.log('audio recorder stop success'); console.log('audio recorder stop success');
}); audioRecorder.release(); // Call the release API to release resources and trigger the release event callback.
audioRecorder.on('release', () => { // Set the 'release' event callback. });
console.log('audio recorder release success'); audioRecorder.on('release', () => { // Set the release event callback.
}); console.log('audio recorder release success');
} audioRecorder = undefined;
});
audioRecorder.on('error', (error) => { // Set the error event callback.
console.info(`audio error called, errName is ${error.name}`);
console.info(`audio error called, errCode is ${error.code}`);
console.info(`audio error called, errMessage is ${error.message}`);
});
}
// pathName indicates the passed recording file name, for example, 01.mp3. The generated file address is /storage/media/100/local/files/Movies/01.mp3. // pathName indicates the passed recording file name, for example, 01.mp3. The generated file address is /storage/media/100/local/files/Video/01.mp3.
// To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. // To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA.
async function getFd(pathName) { async getFd(pathName) {
let displayName = pathName; let displayName = pathName;
const mediaTest = mediaLibrary.getMediaLibrary(); const mediaTest = mediaLibrary.getMediaLibrary();
let fileKeyObj = mediaLibrary.FileKey; let fileKeyObj = mediaLibrary.FileKey;
...@@ -154,41 +153,44 @@ async function getFd(pathName) { ...@@ -154,41 +153,44 @@ async function getFd(pathName) {
let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO); let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath); let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath);
if (dataUri != undefined) { if (dataUri != undefined) {
let args = dataUri.id.toString(); let args = dataUri.id.toString();
let fetchOp = { let fetchOp = {
selections : fileKeyObj.ID + "=?", selections : fileKeyObj.ID + "=?",
selectionArgs : [args], selectionArgs : [args],
} }
let fetchFileResult = await mediaTest.getFileAssets(fetchOp); let fetchFileResult = await mediaTest.getFileAssets(fetchOp);
let fileAsset = await fetchFileResult.getAllObject(); let fileAsset = await fetchFileResult.getAllObject();
let fdNumber = await fileAsset[0].open('Rw'); let fdNumber = await fileAsset[0].open('Rw');
fdNumber = "fd://" + fdNumber.toString(); this.testFdNumber = "fd://" + fdNumber.toString();
testFdNumber = fdNumber;
} }
}
async audioRecorderDemo() {
// 1. Create an AudioRecorder instance.
let audioRecorder = media.createAudioRecorder();
// 2. Set the callbacks.
this.setCallBack(audioRecorder);
await this.getFd('01.mp3'); // Call the getFd method to obtain the FD address of the file to be recorded.
// 3. Set the recording parameters.
let audioRecorderConfig = {
audioEncodeBitRate : 22050,
audioSampleRate : 22050,
numberOfChannels : 2,
uri : this.testFdNumber, // testFdNumber is generated by getFd.
location : { latitude : 30, longitude : 130},
audioEncoderMime : media.CodecMimeType.AUDIO_AAC,
fileFormat : media.ContainerFormatType.CFT_MPEG_4A,
}
audioRecorder.prepare(audioRecorderConfig); // Call the prepare method to trigger the prepare event callback.
}
} }
await getFd('01.mp3');
// 1. Create an AudioRecorder instance.
let audioRecorder = media.createAudioRecorder();
// 2. Set the callbacks.
SetCallBack(audioRecorder);
// 3. Set the recording parameters.
let audioRecorderConfig = {
audioEncoder : media.AudioEncoder.AAC_LC ,
audioEncodeBitRate : 22050,
audioSampleRate : 22050,
numberOfChannels : 2,
format : media.AudioOutputFormat.AAC_ADTS,
uri : testFdNumber, // testFdNumber is generated by getFd.
location : { latitude : 30, longitude : 130},
}
audioRecorder.prepare(audioRecorderConfig)
// 4. Start recording.
audioRecorder.start(); // The start API can be called to trigger the 'start' event callback only after the 'prepare' event callback is complete.
// 5. Stop recording.
audioRecorder.stop(); // The stop API can be called to trigger the 'stop' event callback only after the 'start' or 'resume' event callback is complete.
// 6. Release resources.
audioRecorder.release(); // The AudioRecorder resource is destroyed.
audioRecorder = undefined;
``` ```
## Samples
The following samples are provided to help you better understand how to develop audio recording:
- [<idp:inline class="- topic/inline " val="code" displayname="code" id="code15884933169" tempcmdid="code15884933169">Recorder</idp:inline>: Recorder (eTS, API version 8)](https://gitee.com/openharmony/app_samples/tree/master/media/Recorder)
- [<idp:inline class="- topic/inline " val="code" displayname="code" id="code563211231612" tempcmdid="code563211231612">JsRecorder</idp:inline>: Recorder (JS, API version 8)](https://gitee.com/openharmony/app_samples/tree/master/media/JSRecorder)
- [<idp:inline class="- topic/inline " val="code" displayname="code" id="code7932192919168" tempcmdid="code7932192919168">eTsAudioPlayer</idp:inline>: Audio Player (eTS)](https://gitee.com/openharmony/app_samples/blob/master/media/Recorder/entry/src/main/ets/MainAbility/pages/Play.ets)
- [Audio Player](https://gitee.com/openharmony/codelabs/tree/master/Media/Audio_OH_ETS)
# OpenSL ES Audio Playback Development
## When to Use
You can use OpenSL ES to develop the audio playback function in OpenHarmony. Currently, only some [OpenSL ES APIs](https://gitee.com/openharmony/third_party_opensles/blob/master/api/1.0.1/OpenSLES.h) are implemented. If an API that has not been implemented is called, **SL_RESULT_FEATURE_UNSUPPORTED** will be returned.
## How to Develop
To use OpenSL ES to develop the audio playback function in OpenHarmony, perform the following steps:
1. Add the header files.
```c++
#include <OpenSLES.h>
#include <OpenSLES_OpenHarmony.h>
#include <OpenSLES_Platform.h>
```
2. Use the **slCreateEngine** API to obtain an **engine** instance.
```c++
SLObjectItf engineObject = nullptr;
slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
```
3. Obtain the **engineEngine** instance of the **SL_IID_ENGINE** interface.
```c++
SLEngineItf engineEngine = nullptr;
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
```
4. Configure the player and create an **AudioPlayer** instance.
```c++
SLDataLocator_BufferQueue slBufferQueue = {
SL_DATALOCATOR_BUFFERQUEUE,
0
};
// Configure the parameters based on the audio file format.
SLDataFormat_PCM pcmFormat = {
SL_DATAFORMAT_PCM,
2,
48000,
16,
0,
0,
0
};
SLDataSource slSource = {&slBufferQueue, &pcmFormat};
SLObjectItf pcmPlayerObject = nullptr;
(*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slSource, null, 0, nullptr, nullptr);
(*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
```
5. Obtain the **bufferQueueItf** instance of the **SL_IID_OH_BUFFERQUEUE** interface.
```
SLOHBufferQueueItf bufferQueueItf;
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf);
```
6. Open an audio file and register the **BufferQueueCallback** function.
```c++
FILE *wavFile_ = nullptr;
static void BuqqerQueueCallback (SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size)
{
FILE *wavFile = (FILE *)pContext;
if (!feof(wavFile)) {
SLuint8 *buffer = nullptr;
SLuint32 pSize = 0;
(*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, pSize);
// Read data from the file.
fread(buffer, 1, size, wavFile);
(*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, size);
}
return;
}
// Set wavFile_ to the descriptor of the file to be played.
wavFile_ = fopen(path, "rb");
(*bufferQueueItf)->RegisterCallback(bufferQueueItf, BuqqerQueueCallback, wavFile_);
```
7. Obtain the **playItf** instance of the **SL_PLAYSTATE_PLAYING** interface and start playback.
```c++
SLPlayItf playItf = nullptr;
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &playItf);
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
```
8. Stop audio playback.
```c++
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
(*pcmPlayerObject)->Destroy(pcmPlayerObject);
(*engineObject)->Destroy(engineObject);
```
...@@ -16,21 +16,20 @@ During video recording, audio and video signals are captured, encoded, and saved ...@@ -16,21 +16,20 @@ During video recording, audio and video signals are captured, encoded, and saved
## How to Develop ## How to Develop
For details about the APIs used for video recording, see [VideoRecorder in the Media API](../reference/apis/js-apis-media.md). For details about the APIs, see [VideoRecorder in the Media API](../reference/apis/js-apis-media.md).
### Full-Process Scenario ### Full-Process Scenario
The full video recording process includes creating an instance, setting recording parameters, recording video, pausing, resuming, and stopping recording, and releasing resources. The full video recording process includes creating an instance, setting recording parameters, starting, pausing, resuming, and stopping recording, and releasing resources.
```js ```js
import media from '@ohos.multimedia.media' import media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary' import mediaLibrary from '@ohos.multimedia.mediaLibrary'
export class VideoRecorderDemo {
let testFdNumber; private testFdNumber; // Used to save the FD address.
// pathName indicates the passed recording file name, for example, 01.mp4. The generated file address is /storage/media/100/local/files/Video/01.mp4.
// pathName indicates the passed recording file name, for example, 01.mp4. The generated file address is /storage/media/100/local/files/Movies/01.mp4. // To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA.
// To use the media library, declare the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. async getFd(pathName) {
async function getFd(pathName) {
let displayName = pathName; let displayName = pathName;
const mediaTest = mediaLibrary.getMediaLibrary(); const mediaTest = mediaLibrary.getMediaLibrary();
let fileKeyObj = mediaLibrary.FileKey; let fileKeyObj = mediaLibrary.FileKey;
...@@ -38,110 +37,115 @@ async function getFd(pathName) { ...@@ -38,110 +37,115 @@ async function getFd(pathName) {
let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO); let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath); let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath);
if (dataUri != undefined) { if (dataUri != undefined) {
let args = dataUri.id.toString(); let args = dataUri.id.toString();
let fetchOp = { let fetchOp = {
selections : fileKeyObj.ID + "=?", selections : fileKeyObj.ID + "=?",
selectionArgs : [args], selectionArgs : [args],
} }
let fetchFileResult = await mediaTest.getFileAssets(fetchOp); let fetchFileResult = await mediaTest.getFileAssets(fetchOp);
let fileAsset = await fetchFileResult.getAllObject(); let fileAsset = await fetchFileResult.getAllObject();
let fdNumber = await fileAsset[0].open('Rw'); let fdNumber = await fileAsset[0].open('Rw');
fdNumber = "fd://" + fdNumber.toString(); this.testFdNumber = "fd://" + fdNumber.toString();
testFdNumber = fdNumber; }
}
// Error callback triggered in the case of an error
failureCallback(error) {
console.info('error happened, error name is ' + error.name);
console.info('error happened, error code is ' + error.code);
console.info('error happened, error message is ' + error.message);
}
// Error callback triggered in the case of an exception
catchCallback(error) {
console.info('catch error happened, error name is ' + error.name);
console.info('catch error happened, error code is ' + error.code);
console.info('catch error happened, error message is ' + error.message);
}
async videoRecorderDemo() {
let videoRecorder = null; // videoRecorder is an empty object and assigned with a value after createVideoRecorder is successfully called.
let surfaceID = null; // Used to save the surface ID returned by getInputSurface.
// Obtain the FD address of the video to be recorded.
await this.getFd('01.mp4');
// Recording-related parameter settings
let videoProfile = {
audioBitrate : 48000,
audioChannels : 2,
audioCodec : 'audio/mp4a-latm',
audioSampleRate : 48000,
fileFormat : 'mp4',
videoBitrate : 48000,
videoCodec : 'video/mp4v-es',
videoFrameWidth : 640,
videoFrameHeight : 480,
videoFrameRate : 30
} }
}
await getFd('01.mp4');
let videoProfile = {
audioBitrate : 48000,
audioChannels : 2,
audioCodec : 'audio/mp4a-latm',
audioSampleRate : 48000,
fileFormat : 'mp4',
videoBitrate : 48000,
videoCodec : 'video/mp4v-es',
videoFrameWidth : 640,
videoFrameHeight : 480,
videoFrameRate : 30
}
let videoConfig = { let videoConfig = {
audioSourceType : 1, audioSourceType : 1,
videoSourceType : 0, videoSourceType : 0,
profile : videoProfile, profile : videoProfile,
url: testFdNumber, // testFdNumber is generated by getFd. url : this.testFdNumber, // testFdNumber is generated by getFd.
orientationHint : 0, orientationHint : 0,
location : { latitude : 30, longitude : 130 }, location : { latitude : 30, longitude : 130 },
} }
// Create a VideoRecorder object.
// Error callback triggered in the case of an error await media.createVideoRecorder().then((recorder) => {
function failureCallback(error) { console.info('case createVideoRecorder called');
console.info('error happened, error name is ' + error.name); if (typeof (recorder) != 'undefined') {
console.info('error happened, error code is ' + error.code);
console.info('error happened, error message is ' + error.message);
}
// Error callback triggered in the case of an exception
function catchCallback(error) {
console.info('catch error happened, error name is ' + error.name);
console.info('catch error happened, error code is ' + error.code);
console.info('catch error happened, error message is ' + error.message);
}
let videoRecorder = null; // videoRecorder is an empty object and assigned with a value after createVideoRecorder is successfully called.
let surfaceID = null; // Used to save the surface ID returned by getInputSurface.
// Create a VideoRecorder object.
await media.createVideoRecorder().then((recorder) => {
console.info('case createVideoRecorder called');
if (typeof (recorder) != 'undefined') {
videoRecorder = recorder; videoRecorder = recorder;
console.info('createVideoRecorder success'); console.info('createVideoRecorder success');
} else { } else {
console.info('createVideoRecorder failed'); console.info('createVideoRecorder failed');
} }
}, failureCallback).catch(catchCallback); }, this.failureCallback).catch(this.catchCallback);
// Obtain the surface ID, save it, and pass it to camera-related interfaces. // Call the prepare API to prepare for video recording.
await videoRecorder.getInputSurface().then((surface) => { await videoRecorder.prepare(videoConfig).then(() => {
console.info('getInputSurface success'); console.info('prepare success');
surfaceID = surface; }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Obtain the surface ID, save it, and pass it to camera-related APIs.
// Video recording depends on camera-related interfaces. The following operations can be performed only after the video output start interface is invoked. await videoRecorder.getInputSurface().then((surface) => {
console.info('getInputSurface success');
// Start video recording. surfaceID = surface;
await videoRecorder.start().then(() => { }, this.failureCallback).catch(this.catchCallback);
console.info('start success');
}, failureCallback).catch(catchCallback); // Video recording depends on camera-related APIs. The following operations can be performed only after the video output start API is invoked. For details about how to call the camera APIs, see the samples.
// Start video recording.
// Pause video playback before the video output stop interface is invoked. await videoRecorder.start().then(() => {
await videoRecorder.pause().then(() => { console.info('start success');
console.info('pause success'); }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Pause video recording before the video output stop API of the camera is invoked.
// Resume video playback after the video output start interface is invoked. await videoRecorder.pause().then(() => {
await videoRecorder.resume().then(() => { console.info('pause success');
console.info('resume success'); }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Resume video recording after the video output start API of the camera is invoked.
// Stop video recording after the video output stop interface is invoked. await videoRecorder.resume().then(() => {
await videoRecorder.stop().then(() => { console.info('resume success');
console.info('stop success'); }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Stop video recording after the video output stop API of the camera is invoked.
// Reset the recording configuration. await videoRecorder.stop().then(() => {
await videoRecorder.reset().then(() => { console.info('stop success');
console.info('reset success'); }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Reset the recording configuration.
// Release the video recording resources and camera object resources. await videoRecorder.reset().then(() => {
await videoRecorder.release().then(() => { console.info('reset success');
console.info('release success'); }, this.failureCallback).catch(this.catchCallback);
}, failureCallback).catch(catchCallback);
// Release the video recording resources and camera object resources.
// Set the related object to null. await videoRecorder.release().then(() => {
videoRecorder = null; console.info('release success');
surfaceID = null; }, this.failureCallback).catch(this.catchCallback);
// Set the related object to null.
videoRecorder = undefined;
surfaceID = undefined;
}
}
``` ```
# Using Native APIs in Application Projects # Using Native APIs in Application Projects
OpenHarmony applications need to use JavaScript (JS) when calling native APIs. The napi interfaces provided by the **arkui_napi** repository are used to implement the interaction with JS. Currently, the **arkui_napi** repository supports some third-party **Node.js** interfaces. The names of the napi interfaces are the same as those in the third-party **Node.js**. For details about the interfaces supported, see `libnapi.ndk.json` in this repository. OpenHarmony applications use JavaScript (JS) when calling native APIs. The native APIs (NAPIs) provided by the **arkui_napi** repository are used to implement the interaction with JS. Currently, the **arkui_napi** repository supports some third-party **Node.js** interfaces. The names of the NAPIs are the same as those in the third-party **Node.js**. For details about the interfaces supported, see `libnapi.ndk.json` in this repository.
## How to Develop ## How to Develop
The IDE has a default project that uses native APIs. You can choose `File` > `New` > `Create Project` to create a `Native C++` project. The cpp directory is generated in the main directory. You can use the napi interfaces provided by the **arkui_napi** repository for development. The IDE has a default project that uses NAPIs. You can choose `File` > `New` > `Create Project` to create a `Native C++` project. The **cpp** directory is generated in the **main** directory. You can use the NAPIs provided by the **arkui_napi** repository for development.
You can `import` the native .so that contains the JS processing logic. For example, `import hello from 'libhello.so'` to use the **libhello.so** capability. Then, the JS object created using the NAPI interface can be passed to the `hello` object of the application to call the native capability. You can `import` the native .so that contains the JS processing logic. For example, `import hello from 'libhello.so'` to use the **libhello.so** capability. Then, the JS object created using the NAPI can be passed to the `hello` object of the application to call the native capability.
## Development Guidelines ## Development Guidelines
### Registration ### Registration
* Add **static** to the **nm_register_func** function to prevent symbol conflicts with other .so files. * Add **static** to the **nm_register_func** function to prevent symbol conflicts with other .so files.
* The name of the module registration entry, that is, the function modified by **\_\_attribute\_\_((constructor))**, must be unique. * The name of the module registration entry, that is, the function decorated by **\_\_attribute\_\_((constructor))**, must be unique.
### .so Naming Rules ### .so Naming Rules
Each module has a .so file. For example, if the module name is `hello`, name the .so file **libhello.so**. The `nm_modname` field in `napi_module` must be `hello`, which is the same as the module name. The sample code for importing the .so file is `import hello from 'libhello.so'`. Each module has a .so file. For example, if the module name is `hello`, name the .so file **libhello.so**. The `nm_modname` field in `napi_module` must be `hello`, which is the same as the module name. The sample code for importing the .so file is `import hello from 'libhello.so'`.
### JS Objects and Threads ### JS Objects and Threads
The Ark engine prevents napi interfaces from being called to operate JS objects in non-JS threads. Otherwise, the application will crash. The Ark engine prevents NAPIs from being called to operate JS objects in non-JS threads. Otherwise, the application will crash.
* The napi interfaces can be used only in JS threads. * The NAPIs can be used only in JS threads.
* **env** is bound to a thread and cannot be used across threads. The JS object created by a native API can be used only in the thread, in which the object is created, that is, the JS object is bound to the **env** of the thread. * **env** is bound to a thread and cannot be used across threads. The JS object created by a NAPI can be used only in the thread, in which the object is created, that is, the JS object is bound to the **env** of the thread.
### napi_create_async_work ### napi_create_async_work
**napi_create_async_work** has two callbacks: **napi_create_async_work** has two callbacks:
* **execute**: processes service logic asynchronously. This callback is not executed by a JS thread, therefore, it cannot call any NAPI interface. The return value of **execute** is processed by the **complete** callback. * **execute**: processes service logic asynchronously. This callback is not executed by a JS thread; therefore, it cannot call any NAPI. The return value of **execute** is processed by the **complete** callback.
* **complete**: calls the napi interface to encapsulate the return value of **execute** into a JS object and return it for processing. This callback is executed by a JS thread. * **complete**: calls the NAPI to encapsulate the return value of **execute** into a JS object and return it for processing. This callback is executed by a JS thread.
```c++ ```c++
napi_status napi_create_async_work(napi_env env, napi_status napi_create_async_work(napi_env env,
...@@ -45,7 +45,7 @@ napi_status napi_create_async_work(napi_env env, ...@@ -45,7 +45,7 @@ napi_status napi_create_async_work(napi_env env,
## Example 1 Encapsulating Synchronous and Asynchronous APIs for the Storage Module ## Example 1: Encapsulating Synchronous and Asynchronous APIs for the Storage Module
### Overview ### Overview
...@@ -131,7 +131,7 @@ static napi_value JSStorageGetSync(napi_env env, napi_callback_info info) ...@@ -131,7 +131,7 @@ static napi_value JSStorageGetSync(napi_env env, napi_callback_info info)
char value[128] = {0}; char value[128] = {0};
size_t valueLen = 0; size_t valueLen = 0;
// parse parameters // Parse parameters.
for (size_t i = 0; i < argc; i++) { for (size_t i = 0; i < argc; i++) {
napi_valuetype valueType; napi_valuetype valueType;
napi_typeof(env, argv[i], &valueType); napi_typeof(env, argv[i], &valueType);
...@@ -212,7 +212,7 @@ static napi_value JSStorageGet(napi_env env, napi_callback_info info) ...@@ -212,7 +212,7 @@ static napi_value JSStorageGet(napi_env env, napi_callback_info info)
napi_create_async_work( napi_create_async_work(
env, nullptr, resource, env, nullptr, resource,
// Callback 1: This callback contains the service logic to be asynchronously executed and is asynchronously executed by the napi interface. Do not operate JS objects using the napi interface because the execution is asynchronous. // Callback 1: This callback contains the service logic to be asynchronously executed and is asynchronously executed by the NAPI. Do not operate JS objects using theNAPI because the execution is asynchronous.
[](napi_env env, void* data) { [](napi_env env, void* data) {
StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
auto itr = gKeyValueStorage.find(asyncContext->key); auto itr = gKeyValueStorage.find(asyncContext->key);
...@@ -239,10 +239,10 @@ static napi_value JSStorageGet(napi_env env, napi_callback_info info) ...@@ -239,10 +239,10 @@ static napi_value JSStorageGet(napi_env env, napi_callback_info info)
if (asyncContext->deferred) { if (asyncContext->deferred) {
// If a promise is used, check the result of callback 1. // If a promise is used, check the result of callback 1.
if (!asyncContext->status) { if (!asyncContext->status) {
// Triggered when callback 1 is successful (status is 1), that is, invoke the callback passed in then in the promise. // Triggered when callback 1 is successful (status is 1), that is, to invoke the callback passed in then in the promise.
napi_resolve_deferred(env, asyncContext->deferred, result[1]); napi_resolve_deferred(env, asyncContext->deferred, result[1]);
} else { } else {
// Triggered when callback 1 fails (status is 0), that is, invoke the callback passed in catch in the promise. // Triggered when callback 1 fails (status is 0), that is, to invoke the callback passed in catch in the promise.
napi_reject_deferred(env, asyncContext->deferred, result[0]); napi_reject_deferred(env, asyncContext->deferred, result[0]);
} }
} else { } else {
...@@ -287,11 +287,11 @@ export default { ...@@ -287,11 +287,11 @@ export default {
## Example 2 Binding Native and JS Objects for the NetServer Module ## Example 2: Binding Native and JS Objects for the NetServer Module
### Overview ### Overview
This example shows how to implement the `on/off/once` method and bind C++ and JS objects using the **wrap** API. The NetServer module implements a network service. This example shows how to implement the `on/off/once` method and bind C++ and JS objects using the **wrap** API. The NetServer module implements the network service.
### API Declaration ### API Declaration
...@@ -486,11 +486,11 @@ export default { ...@@ -486,11 +486,11 @@ export default {
## Example 3 Calling Back a JS API in a Non-JS Thread ## Example 3: Calling Back a JS API in a Non-JS Thread
### Overview ### Overview
This example describes how to invoke a JS callback in a non-JS thread. For example, a sensor listener is registered for a JS application. The sensor data is reported by an SA. When the SA invokes the client through Inter-Process Communication (IPC), the execution thread is an IPC thread, which is different from the JS thread of the application. In this case, the JS callback must be thrown to the JS thread to execute. Otherwise, the application will crash. This example describes how to invoke a JS callback in a non-JS thread. For example, a sensor listener is registered for a JS application. The sensor data is reported by an SA. When the SA invokes the client through Inter-Process Communication (IPC), the execution thread is an IPC thread, which is different from the JS thread of the SA. In this case, the JS callback must be thrown to the JS thread to execute. Otherwise, the application will crash.
### Implementation ### Implementation
...@@ -513,7 +513,7 @@ static napi_value CallbackExport(napi_env env, napi_value exports) ...@@ -513,7 +513,7 @@ static napi_value CallbackExport(napi_env env, napi_value exports)
return exports; return exports;
} }
// Define the callback // Define the callback.
static napi_module callbackModule = { static napi_module callbackModule = {
.nm_version = 1, .nm_version = 1,
.nm_flags = 0, .nm_flags = 0,
...@@ -524,7 +524,7 @@ static napi_module callbackModule = { ...@@ -524,7 +524,7 @@ static napi_module callbackModule = {
.reserved = { 0 }, .reserved = { 0 },
}; };
// Register the callback // Register the callback.
extern "C" __attribute__((constructor)) void CallbackTestRegister() extern "C" __attribute__((constructor)) void CallbackTestRegister()
{ {
napi_module_register(&callbackModule); napi_module_register(&callbackModule);
...@@ -574,7 +574,7 @@ void callbackTest(CallbackContext* context) ...@@ -574,7 +574,7 @@ void callbackTest(CallbackContext* context)
return; return;
} }
// Call napi interfaces. // Call the NAPIs.
napi_value callback = nullptr; napi_value callback = nullptr;
napi_get_reference_value(context->env, context->callbackRef, &callback); napi_get_reference_value(context->env, context->callbackRef, &callback);
napi_value retArg; napi_value retArg;
......
# Common Event and Notification # Common Event and Notification
[Common Event and Notification Overview](notification-brief.md) - [Common Event and Notification Overview](notification-brief.md)
- Common Event
### Common Event - [Common Event Development](common-event.md)
- Notification
* [Common Event Development](common-event.md) - [Notification Development](notification.md)
- Debugging Tools
### Notification - [Debugging Assistant Usage](assistant-guidelines.md)
* [Notification Development](notification.md)
### Debugging Tools
* [Debugging Assistant Usage](assistant-guidelines.md)
...@@ -174,4 +174,4 @@ if (this.subscriber != null) { ...@@ -174,4 +174,4 @@ if (this.subscriber != null) {
The following sample is provided to help you better understand how to use the common event functionality: The following sample is provided to help you better understand how to use the common event functionality:
- [`CommonEvent`: eTS Common Event (API 7)](https://gitee.com/openharmony/app_samples/tree/master/Notification/CommonEvent) - [`CommonEvent`: eTS Common Event (API 8)](https://gitee.com/openharmony/app_samples/tree/master/Notification/CommonEvent)
...@@ -133,7 +133,7 @@ var subscriber = { ...@@ -133,7 +133,7 @@ var subscriber = {
##### Enabling Notification ##### Enabling Notification
Before publishing a notification, check whether the notification feature is enabled for your application. By default, the feature is disabled. The application can use **Notification.requestEnableNotification** to prompt the user to enable the feature. Before publishing a notification, check whether the notification feature is enabled for your application. By default, the feature is disabled. The application calls **Notification.requestEnableNotification** to prompt the user to enable the feature.
```js ```js
Notification.requestEnableNotification() .then((data) => { Notification.requestEnableNotification() .then((data) => {
...@@ -262,4 +262,4 @@ Notification.cancel(1, "label", cancelCallback) ...@@ -262,4 +262,4 @@ Notification.cancel(1, "label", cancelCallback)
The following sample is provided to help you better understand how to develop notification functions: The following sample is provided to help you better understand how to develop notification functions:
[`Notification`: EtsNotification (API 7)](https://gitee.com/openharmony/app_samples/tree/master/common/Notification) [`Notification`: EtsNotification (API 8)](https://gitee.com/openharmony/app_samples/tree/master/common/Notification)
\ No newline at end of file \ No newline at end of file
# Quick Start # Quick Start
- Getting Started - Getting Started
- [Preparations](start-overview.md) - [Preparations](start-overview.md)
- [Getting Started with eTS in the Traditional Coding Approach](start-with-ets.md) - [Getting Started with eTS in the Traditional Coding Approach](start-with-ets.md)
- [Getting Started with eTS in the Low-Code Approach](start-with-ets-low-code.md) - [Getting Started with eTS in the Low-Code Approach](start-with-ets-low-code.md)
- [Getting Started with JavaScript in the Traditional Coding Approach](start-with-js.md) - [Getting Started with JavaScript in the Traditional Coding Approach](start-with-js.md)
- [Getting Started with JavaScript in the Low-Code Approach](start-with-js-low-code.md) - [Getting Started with JavaScript in the Low-Code Approach](start-with-js-low-code.md)
- Development Fundamentals
- Development Fundamentals - [Application Package Structure Configuration File (FA Model)](package-structure.md)
- [Application Development Package Structure (FA Model)](package-structure.md) - [Application Package Structure Configuration File (Stage Model)](stage-structure.md)
- [Application Development Package Structure (Stage Model)](module-structure.md) - [Resource File Categories](basic-resource-file-categories.md)
- [Resource File Categories](basic-resource-file-categories.md) - [SysCap](syscap.md)
- [SysCap](syscap.md)
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
All the application resource files, such as strings, images, and audio files, are stored in the **resources** directory, allowing you to easily access, use, and maintain them. The **resources** directory consists of two types of sub-directories: the **base** sub-directory and qualifiers sub-directories, and the **rawfile** sub-directory. For details, see Categories of the **resources** directory. All the application resource files, such as strings, images, and audio files, are stored in the **resources** directory, allowing you to easily access, use, and maintain them. The **resources** directory consists of two types of sub-directories: the **base** sub-directory and qualifiers sub-directories, and the **rawfile** sub-directory. For details, see Categories of the **resources** directory.
Example of the **resources** directory: Example of the **resources** directory:
``` ```
resources resources
...@@ -22,13 +22,13 @@ resources ...@@ -22,13 +22,13 @@ resources
|---rawfile // Default directory |---rawfile // Default directory
``` ```
**Table 1** Categories of the **resources** directory **Table 1** Categories of the **resources** directory
| Category | base&nbsp;and&nbsp;Qualifiers&nbsp;Sub-directories | rawfile&nbsp;Sub-directory | | Category | base and Qualifiers Sub-directories | rawfile Sub-directory |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| Structure | Sub-directories&nbsp;are&nbsp;structured&nbsp;in&nbsp;two&nbsp;levels.&nbsp;The&nbsp;directory&nbsp;name&nbsp;must&nbsp;comply&nbsp;with&nbsp;specified&nbsp;naming&nbsp;conventions&nbsp;so&nbsp;that&nbsp;its&nbsp;target&nbsp;resource&nbsp;file&nbsp;in&nbsp;the&nbsp;correct&nbsp;directory&nbsp;can&nbsp;be&nbsp;matched&nbsp;based&nbsp;on&nbsp;the&nbsp;device&nbsp;status.<br/>&nbsp;&nbsp;The&nbsp;**base**&nbsp;sub-directory&nbsp;and&nbsp;qualifiers&nbsp;sub-directories&nbsp;are&nbsp;the&nbsp;first&nbsp;level&nbsp;of&nbsp;sub-directories&nbsp;under&nbsp;**resources**.<br/>-&nbsp;The&nbsp;**base**&nbsp;sub-directory&nbsp;is&nbsp;generated&nbsp;by&nbsp;default.&nbsp;If&nbsp;no&nbsp;qualifiers&nbsp;sub-directories&nbsp;in&nbsp;the&nbsp;**resources**&nbsp;directory&nbsp;of&nbsp;the&nbsp;application&nbsp;match&nbsp;the&nbsp;device&nbsp;status,&nbsp;the&nbsp;resource&nbsp;file&nbsp;in&nbsp;the&nbsp;**base**&nbsp;sub-directory&nbsp;will&nbsp;be&nbsp;automatically&nbsp;referenced.<br/>-&nbsp;You&nbsp;need&nbsp;to&nbsp;create&nbsp;qualifiers&nbsp;sub-directories&nbsp;on&nbsp;your&nbsp;own.&nbsp;Each&nbsp;directory&nbsp;name&nbsp;consists&nbsp;of&nbsp;one&nbsp;or&nbsp;more&nbsp;qualifiers&nbsp;that&nbsp;represent&nbsp;the&nbsp;application&nbsp;scenarios&nbsp;or&nbsp;device&nbsp;characteristics.&nbsp;For&nbsp;details,&nbsp;see&nbsp;[Qualifiers&nbsp;Sub-directories](#qualifiers-sub-directories).<br/>Resource&nbsp;group&nbsp;sub-directories&nbsp;are&nbsp;located&nbsp;at&nbsp;the&nbsp;second&nbsp;level&nbsp;of&nbsp;sub-directories&nbsp;to&nbsp;store&nbsp;basic&nbsp;elements&nbsp;such&nbsp;as&nbsp;strings,&nbsp;colors,&nbsp;and&nbsp;boolean&nbsp;values,&nbsp;as&nbsp;well&nbsp;as&nbsp;resource&nbsp;files&nbsp;such&nbsp;as&nbsp;media,&nbsp;animations,&nbsp;and&nbsp;layouts.&nbsp;For&nbsp;details,&nbsp;see&nbsp;[Resource&nbsp;Group&nbsp;Sub-directories](#resource-group-sub-directories). | You&nbsp;can&nbsp;create&nbsp;multiple&nbsp;levels&nbsp;of&nbsp;sub-directories&nbsp;with&nbsp;custom&nbsp;directory&nbsp;names.&nbsp;They&nbsp;can&nbsp;be&nbsp;used&nbsp;to&nbsp;store&nbsp;various&nbsp;resource&nbsp;files.<br/>However,&nbsp;resource&nbsp;files&nbsp;in&nbsp;the&nbsp;**rawfile**&nbsp;sub-directory&nbsp;will&nbsp;not&nbsp;be&nbsp;matched&nbsp;based&nbsp;on&nbsp;the&nbsp;device&nbsp;status. | | Structure | Sub-directories are structured in two levels. The directory name must comply with specified naming conventions so that its target resource file in the correct directory can be matched based on the device status.<br/> The **base** sub-directory and qualifiers sub-directories are the first level of sub-directories under **resources**.<br/>- The **base** sub-directory is generated by default. If no qualifiers sub-directories in the **resources** directory of the application match the device status, the resource file in the **base** sub-directory will be automatically referenced.<br/>- You need to create qualifiers sub-directories on your own. Each directory name consists of one or more qualifiers that represent the application scenarios or device characteristics. For details, see [Qualifiers Sub-directories](#qualifiers-sub-directories).<br/>Resource group sub-directories are located at the second level of sub-directories to store basic elements such as strings, colors, and boolean values, as well as resource files such as media, animations, and layouts. For details, see [Resource Group Sub-directories](#resource-group-sub-directories). | You can create multiple levels of sub-directories with custom directory names. They can be used to store various resource files.<br/>However, resource files in the **rawfile** sub-directory will not be matched based on the device status. |
| Compilation | Resource&nbsp;files&nbsp;in&nbsp;the&nbsp;sub-directories&nbsp;are&nbsp;compiled&nbsp;into&nbsp;binary&nbsp;files,&nbsp;and&nbsp;each&nbsp;resource&nbsp;file&nbsp;is&nbsp;assigned&nbsp;an&nbsp;ID. | Resource&nbsp;files&nbsp;in&nbsp;the&nbsp;sub-directory&nbsp;are&nbsp;directly&nbsp;packed&nbsp;into&nbsp;the&nbsp;application&nbsp;without&nbsp;being&nbsp;compiled,&nbsp;and&nbsp;no&nbsp;IDs&nbsp;will&nbsp;be&nbsp;assigned&nbsp;to&nbsp;the&nbsp;resource&nbsp;files. | | Compilation | Resource files in the sub-directories are compiled into binary files, and each resource file is assigned an ID. | Resource files in the sub-directory are directly packed into the application without being compiled, and no IDs will be assigned to the resource files. |
| Reference | Resource&nbsp;files&nbsp;in&nbsp;the&nbsp;sub-directories&nbsp;are&nbsp;referenced&nbsp;based&nbsp;on&nbsp;the&nbsp;resource&nbsp;type&nbsp;and&nbsp;resource&nbsp;name. | Resource&nbsp;files&nbsp;in&nbsp;the&nbsp;sub-directories&nbsp;are&nbsp;referenced&nbsp;based&nbsp;on&nbsp;the&nbsp;specified&nbsp;file&nbsp;path&nbsp;and&nbsp;file&nbsp;name. | | Reference | Resource files in the sub-directories are referenced based on the resource type and resource name. | Resource files in the sub-directories are referenced based on the specified file path and file name. |
## Qualifiers Sub-directories ## Qualifiers Sub-directories
...@@ -39,21 +39,22 @@ The name of a qualifiers sub-directory consists of one or more qualifiers that r ...@@ -39,21 +39,22 @@ The name of a qualifiers sub-directory consists of one or more qualifiers that r
- Qualifiers are ordered in the following sequence: _MCC_MNC-language_script_country/region-screen orientation-device type-color mode-screen density_. You can select one or multiple qualifiers to name your sub-directory based on your application scenarios and device characteristics. - Qualifiers are ordered in the following sequence: _MCC_MNC-language_script_country/region-screen orientation-device type-color mode-screen density_. You can select one or multiple qualifiers to name your sub-directory based on your application scenarios and device characteristics.
- Separation between qualifiers: The language, script, and country/region qualifiers are separated using underscores (_); the MNC and MCC qualifiers are also separated using underscores (_); other qualifiers are separated using hyphens (-). For example, **zh_Hant_CN** and **zh_CN-car-ldpi**. - Separation between qualifiers: The language, script, and country/region qualifiers are separated using underscores (\_); the MNC and MCC qualifiers are also separated using underscores (\_); other qualifiers are separated using hyphens (-). For example, **zh_Hant_CN** and **zh_CN-car-ldpi**.
- Value range of qualifiers: The value of each qualifier must meet the requirements. Otherwise, the resource files in the sub-directory cannot be matched. - Value range of qualifiers: The value of each qualifier must meet the requirements. Otherwise, the resource files in the sub-directory cannot be matched.
**Table 2** Requirements for qualifier values
**Table 2** Requirements for qualifier values
| Qualifier&nbsp;Type | Description&nbsp;and&nbsp;Value&nbsp;Range | | Qualifier Type | Description and Value Range |
| -------- | -------- | | -------- | -------- |
| MCC&amp;MNC | Indicates&nbsp;the&nbsp;MCC&nbsp;and&nbsp;MNC,&nbsp;which&nbsp;are&nbsp;obtained&nbsp;from&nbsp;the&nbsp;network&nbsp;where&nbsp;the&nbsp;device&nbsp;is&nbsp;registered.&nbsp;The&nbsp;MCC&nbsp;can&nbsp;be&nbsp;either&nbsp;followed&nbsp;by&nbsp;the&nbsp;MNC&nbsp;with&nbsp;an&nbsp;underscore&nbsp;(_)&nbsp;in&nbsp;between&nbsp;or&nbsp;be&nbsp;used&nbsp;independently.&nbsp;For&nbsp;example,&nbsp;**mcc460**&nbsp;represents&nbsp;China,&nbsp;and&nbsp;**mcc460_mnc00**&nbsp;represents&nbsp;China&nbsp;Mobile.<br/>For&nbsp;details&nbsp;about&nbsp;the&nbsp;value&nbsp;range,&nbsp;refer&nbsp;to&nbsp;**ITU-T&nbsp;E.212**&nbsp;(the&nbsp;international&nbsp;identification&nbsp;plan&nbsp;for&nbsp;public&nbsp;networks&nbsp;and&nbsp;subscriptions). | | MCC&amp;MNC | Indicates the MCC and MNC, which are obtained from the network where the device is registered. The MCC can be either followed by the MNC with an underscore (_) in between or be used independently. For example, **mcc460** represents China, and **mcc460_mnc00** represents China Mobile.<br/>For details about the value range, refer to **ITU-T E.212** (the international identification plan for public networks and subscriptions). |
| Language | Indicates&nbsp;the&nbsp;language&nbsp;used&nbsp;by&nbsp;the&nbsp;device.&nbsp;The&nbsp;value&nbsp;consists&nbsp;of&nbsp;two&nbsp;or&nbsp;three&nbsp;lowercase&nbsp;letters,&nbsp;for&nbsp;example,&nbsp;**zh**&nbsp;indicates&nbsp;Chinese,&nbsp;**en**&nbsp;indicates&nbsp;English,&nbsp;and&nbsp;**mai**&nbsp;indicates&nbsp;Maithili.<br/>For&nbsp;details&nbsp;about&nbsp;the&nbsp;value&nbsp;range,&nbsp;refer&nbsp;to&nbsp;**ISO&nbsp;639**&nbsp;(codes&nbsp;for&nbsp;the&nbsp;representation&nbsp;of&nbsp;names&nbsp;of&nbsp;languages). | | Language | Indicates the language used by the device. The value consists of two or three lowercase letters, for example, **zh** indicates Chinese, **en** indicates English, and **mai** indicates Maithili.<br/>For details about the value range, refer to **ISO 639** (codes for the representation of names of languages). |
| Script | Indicates&nbsp;the&nbsp;script&nbsp;type&nbsp;used&nbsp;by&nbsp;the&nbsp;device.&nbsp;The&nbsp;value&nbsp;starts&nbsp;with&nbsp;one&nbsp;uppercase&nbsp;letter&nbsp;followed&nbsp;by&nbsp;three&nbsp;lowercase&nbsp;letters,&nbsp;for&nbsp;example,&nbsp;**Hans**&nbsp;indicates&nbsp;simplified&nbsp;Chinese&nbsp;and&nbsp;**Hant**&nbsp;indicates&nbsp;traditional&nbsp;Chinese.<br/>For&nbsp;details&nbsp;about&nbsp;the&nbsp;value&nbsp;range,&nbsp;refer&nbsp;to&nbsp;**ISO&nbsp;15924**&nbsp;(codes&nbsp;for&nbsp;the&nbsp;representation&nbsp;of&nbsp;names&nbsp;of&nbsp;scripts). | | Script | Indicates the script type used by the device. The value starts with one uppercase letter followed by three lowercase letters, for example, **Hans** indicates simplified Chinese and **Hant** indicates traditional Chinese.<br/>For details about the value range, refer to **ISO 15924** (codes for the representation of names of scripts). |
| Country/Region | Indicates&nbsp;the&nbsp;country&nbsp;or&nbsp;region&nbsp;where&nbsp;a&nbsp;user&nbsp;is&nbsp;located.&nbsp;The&nbsp;value&nbsp;consists&nbsp;of&nbsp;two&nbsp;or&nbsp;three&nbsp;uppercase&nbsp;letters&nbsp;or&nbsp;three&nbsp;digits,&nbsp;for&nbsp;example,&nbsp;**CN**&nbsp;indicates&nbsp;China&nbsp;and&nbsp;**GB**&nbsp;indicates&nbsp;the&nbsp;United&nbsp;Kingdom.<br/>For&nbsp;details&nbsp;about&nbsp;the&nbsp;value&nbsp;range,&nbsp;refer&nbsp;to&nbsp;**ISO&nbsp;3166-1**&nbsp;(codes&nbsp;for&nbsp;the&nbsp;representation&nbsp;of&nbsp;names&nbsp;of&nbsp;countries&nbsp;and&nbsp;their&nbsp;subdivisions). | | Country/Region | Indicates the country or region where a user is located. The value consists of two or three uppercase letters or three digits, for example, **CN** indicates China and **GB** indicates the United Kingdom.<br/>For details about the value range, refer to **ISO 3166-1** (codes for the representation of names of countries and their subdivisions). |
| Screen&nbsp;orientation | Indicates&nbsp;the&nbsp;screen&nbsp;orientation&nbsp;of&nbsp;the&nbsp;device.&nbsp;The&nbsp;value&nbsp;can&nbsp;be:<br/>-&nbsp;**vertical**:&nbsp;portrait&nbsp;orientation<br/>-&nbsp;**horizontal**:&nbsp;landscape&nbsp;orientation | | Screen orientation | Indicates the screen orientation of the device. The value can be:<br/>- **vertical**: portrait orientation<br/>- **horizontal**: landscape orientation |
| Device&nbsp;type | Indicates&nbsp;the&nbsp;device&nbsp;type.&nbsp;The&nbsp;value&nbsp;can&nbsp;be:<br/>-&nbsp;**phone**:&nbsp;smartphones<br/>-&nbsp;**tablet**:&nbsp;tablets<br/>-&nbsp;**car**:&nbsp;head&nbsp;units<br/>-&nbsp;**tv**:&nbsp;smart&nbsp;TVs<br/>-&nbsp;**wearable**:&nbsp;wearables | | Device type | Indicates the device type. The value can be:<br/>- **phone**: smartphones<br/>- **tablet**: tablets<br/>- **car**: head units<br/>- **tv**: smart TVs<br/>- **wearable**: wearables |
| Color&nbsp;mode | Indicates&nbsp;the&nbsp;color&nbsp;mode&nbsp;of&nbsp;the&nbsp;device.&nbsp;The&nbsp;value&nbsp;can&nbsp;be:<br/>-&nbsp;**dark**:&nbsp;dark&nbsp;mode<br/>-&nbsp;**light**:&nbsp;light&nbsp;mode | | Color mode | Indicates the color mode of the device. The value can be:<br/>- **dark**: dark mode<br/>- **light**: light mode |
| Screen&nbsp;density | Indicates&nbsp;the&nbsp;screen&nbsp;density&nbsp;of&nbsp;the&nbsp;device,&nbsp;in&nbsp;dpi.&nbsp;The&nbsp;value&nbsp;can&nbsp;be:<br/>-&nbsp;**sdpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;small-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(SDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(0,&nbsp;120].<br/>-&nbsp;**mdpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;medium-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(MDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(120,&nbsp;160].<br/>-&nbsp;**ldpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;large-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(LDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(160,&nbsp;240].<br/>-&nbsp;**xldpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;extra-large-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(XLDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(240,&nbsp;320].<br/>-&nbsp;**xxldpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;extra-extra-large-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(XXLDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(320,&nbsp;480].<br/>-&nbsp;**xxxldpi**:&nbsp;screen&nbsp;density&nbsp;with&nbsp;extra-extra-extra-large-scale&nbsp;dots&nbsp;per&nbsp;inch&nbsp;(XXXLDPI).&nbsp;This&nbsp;value&nbsp;is&nbsp;applicable&nbsp;for&nbsp;devices&nbsp;with&nbsp;a&nbsp;DPI&nbsp;range&nbsp;of&nbsp;(480,&nbsp;640]. | | Screen density | Indicates the screen density of the device, in dpi. The value can be:<br/>- **sdpi**: screen density with small-scale dots per inch (SDPI). This value is applicable for devices with a DPI range of (0, 120].<br/>- **mdpi**: screen density with medium-scale dots per inch (MDPI). This value is applicable for devices with a DPI range of (120, 160].<br/>- **ldpi**: screen density with large-scale dots per inch (LDPI). This value is applicable for devices with a DPI range of (160, 240].<br/>- **xldpi**: screen density with extra-large-scale dots per inch (XLDPI). This value is applicable for devices with a DPI range of (240, 320].<br/>- **xxldpi**: screen density with extra-extra-large-scale dots per inch (XXLDPI). This value is applicable for devices with a DPI range of (320, 480].<br/>- **xxxldpi**: screen density with extra-extra-extra-large-scale dots per inch (XXXLDPI). This value is applicable for devices with a DPI range of (480, 640]. |
**Rules for Matching Qualifiers Sub-directories and Device Resources** **Rules for Matching Qualifiers Sub-directories and Device Resources**
...@@ -66,14 +67,13 @@ The name of a qualifiers sub-directory consists of one or more qualifiers that r ...@@ -66,14 +67,13 @@ The name of a qualifiers sub-directory consists of one or more qualifiers that r
You can create resource group sub-directories (including element, media, animation, layout, graphic, and profile) in the **base** and qualifiers sub-directories to store resource files of specific types. For details, see Resource group sub-directories. You can create resource group sub-directories (including element, media, animation, layout, graphic, and profile) in the **base** and qualifiers sub-directories to store resource files of specific types. For details, see Resource group sub-directories.
**Table 3** Resource group sub-directories
**Table 3** Resource group sub-directories | Resource Group Sub-directory | Description | Resource File |
| Resource&nbsp;Group&nbsp;Sub-directory | Description | Resource&nbsp;File |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| element | Indicates&nbsp;element&nbsp;resources.&nbsp;Each&nbsp;type&nbsp;of&nbsp;data&nbsp;is&nbsp;represented&nbsp;by&nbsp;a&nbsp;JSON&nbsp;file.&nbsp;The&nbsp;options&nbsp;are&nbsp;as&nbsp;follows:<br/>-&nbsp;**boolean**:&nbsp;boolean&nbsp;data<br/>-&nbsp;**color**:&nbsp;color&nbsp;data<br/>-&nbsp;**float**:&nbsp;floating-point&nbsp;data<br/>-&nbsp;**intarray**:&nbsp;array&nbsp;of&nbsp;integer<br/>-&nbsp;**integer**:&nbsp;integer&nbsp;data<br/>-&nbsp;**pattern**:&nbsp;pattern&nbsp;data<br/>-&nbsp;**plural**:&nbsp;plural&nbsp;form&nbsp;data<br/>-&nbsp;**strarray**:&nbsp;array&nbsp;of&nbsp;strings<br/>-&nbsp;**string**:&nbsp;string&nbsp;data | It&nbsp;is&nbsp;recommended&nbsp;that&nbsp;files&nbsp;in&nbsp;the&nbsp;**element**&nbsp;sub-directory&nbsp;be&nbsp;named&nbsp;the&nbsp;same&nbsp;as&nbsp;the&nbsp;following&nbsp;files,&nbsp;each&nbsp;of&nbsp;which&nbsp;can&nbsp;contain&nbsp;only&nbsp;data&nbsp;of&nbsp;the&nbsp;same&nbsp;type:<br/>-&nbsp;boolean.json<br/>-&nbsp;color.json<br/>-&nbsp;float.json<br/>-&nbsp;intarray.json<br/>-&nbsp;integer.json<br/>-&nbsp;pattern.json<br/>-&nbsp;plural.json<br/>-&nbsp;strarray.json<br/>-&nbsp;string.json | | element | Indicates element resources. Each type of data is represented by a JSON file. The options are as follows:<br/>- **boolean**: boolean data<br/>- **color**: color data<br/>- **float**: floating-point data<br/>- **intarray**: array of integer<br/>- **integer**: integer data<br/>- **pattern**: pattern data<br/>- **plural**: plural form data<br/>- **strarray**: array of strings<br/>- **string**: string data | It is recommended that files in the **element** sub-directory be named the same as the following files, each of which can contain only data of the same type:<br/>- boolean.json<br/>- color.json<br/>- float.json<br/>- intarray.json<br/>- integer.json<br/>- pattern.json<br/>- plural.json<br/>- strarray.json<br/>- string.json |
| media | Indicates&nbsp;media&nbsp;resources,&nbsp;including&nbsp;non-text&nbsp;files&nbsp;such&nbsp;as&nbsp;images,&nbsp;audios,&nbsp;and&nbsp;videos. | The&nbsp;file&nbsp;name&nbsp;can&nbsp;be&nbsp;customized,&nbsp;for&nbsp;example,&nbsp;**icon.png**. | | media | Indicates media resources, including non-text files such as images, audios, and videos. | The file name can be customized, for example, **icon.png**. |
| animation | Indicates&nbsp;animation&nbsp;resources,&nbsp;in&nbsp;XML&nbsp;format. | The&nbsp;file&nbsp;name&nbsp;can&nbsp;be&nbsp;customized,&nbsp;for&nbsp;example,&nbsp;**zoom_in.xml**. | | animation | Indicates animation resources, in XML format. | The file name can be customized, for example, **zoom_in.xml**. |
| layout | Indicates&nbsp;layout&nbsp;resources,&nbsp;in&nbsp;XML&nbsp;format. | The&nbsp;file&nbsp;name&nbsp;can&nbsp;be&nbsp;customized,&nbsp;for&nbsp;example,&nbsp;**home_layout.xml**. | | layout | Indicates layout resources, in XML format. | The file name can be customized, for example, **home_layout.xml**. |
| graphic | Indicates&nbsp;graphic&nbsp;resources,&nbsp;in&nbsp;XML&nbsp;format. | The&nbsp;file&nbsp;name&nbsp;can&nbsp;be&nbsp;customized,&nbsp;for&nbsp;example,&nbsp;**notifications_dark.xml**. | | graphic | Indicates graphic resources, in XML format. | The file name can be customized, for example, **notifications_dark.xml**. |
| profile | Indicates&nbsp;other&nbsp;types&nbsp;of&nbsp;files,&nbsp;which&nbsp;are&nbsp;stored&nbsp;in&nbsp;their&nbsp;raw&nbsp;formats. | The&nbsp;file&nbsp;name&nbsp;can&nbsp;be&nbsp;customized. | | profile | Indicates other types of files, which are stored in their raw formats. | The file name can be customized. |
...@@ -18,10 +18,10 @@ OpenHarmony provides a UI development framework, known as ArkUI. ArkUI provides ...@@ -18,10 +18,10 @@ OpenHarmony provides a UI development framework, known as ArkUI. ArkUI provides
ArkUI comes with two development paradigms: JavaScript-based web-like development paradigm (web-like development paradigm for short) and TypeScript-based declarative development paradigm (declarative development paradigm for short). You can choose whichever development paradigm that aligns with your practice. ArkUI comes with two development paradigms: JavaScript-based web-like development paradigm (web-like development paradigm for short) and TypeScript-based declarative development paradigm (declarative development paradigm for short). You can choose whichever development paradigm that aligns with your practice.
| **Development&nbsp;Paradigm** | **Language** | **UI&nbsp;Update&nbsp;Mode** | **Applicable&nbsp;To** | **Intended&nbsp;Audience** | | **Development Paradigm** | **Language** | **UI Update Mode** | **Applicable To** | **Intended Audience** |
| -------- | -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- | -------- |
| Web-like&nbsp;development&nbsp;paradigm | JavaScript | Data-driven | Applications&nbsp;and&nbsp;service&nbsp;widgets&nbsp;with&nbsp;simple&nbsp;UIs | Frontend&nbsp;web&nbsp;developers | | Web-like development paradigm | JavaScript | Data-driven | Applications and service widgets with simple UIs | Frontend web developers |
| Declarative&nbsp;development&nbsp;paradigm | Extended&nbsp;TypeScript&nbsp;(eTS) | Data-driven | Applications&nbsp;involving&nbsp;technological&nbsp;sophistication&nbsp;and&nbsp;teamwork | Mobile&nbsp;application&nbsp;and&nbsp;system&nbsp;application&nbsp;developers | | Declarative development paradigm | Extended TypeScript (eTS) | Data-driven | Applications involving technological sophistication and teamwork | Mobile application and system application developers |
For DevEco Studio V2.2 Beta1 and later versions, both the traditional coding mode and the low-code mode are supported when the JS language is used for development. For DevEco Studio V2.2 Beta1 and later versions, both the traditional coding mode and the low-code mode are supported when the JS language is used for development.
......
# Getting Started with eTS in the Low-Code Approach # Getting Started with eTS in the Low-Code Approach
> ![icon-note.gif](public_sys-resources/icon-note.gif) **Note:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/>This feature is supported in DevEco Studio V3.0 Beta3 and later versions.
> This feature is supported in DevEco Studio V3.0 Beta3 and later versions. >
>
> The component lineup that supports low-code development in eTS is now at its preliminary stage and will be expanding in coming versions. > The component lineup that supports low-code development in eTS is now at its preliminary stage and will be expanding in coming versions.
> >
> For best possible results, use [DevEco Studio V3.0.0.900 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony) for your development. > For best possible results, use [DevEco Studio V3.0.0.900 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony) for your development.
...@@ -21,7 +20,7 @@ You can develop applications or services in the low-code approach using either o ...@@ -21,7 +20,7 @@ You can develop applications or services in the low-code approach using either o
## Creating a Project That Supports Low-Code Development ## Creating a Project That Supports Low-Code Development
1. Open DevEco Studio, choose **File** &gt; **New** &gt; **Create Project**, select **Empty Ability**, and click **Next**. 1. In DevEco Studio, if no project is open, click **Create Project**; if a project is already open, choose **File** &gt; **New** &gt; **Create Project**. Then, select **Empty Ability** and click **Next**.
![en-us_image_0000001233528152](figures/en-us_image_0000001233528152.png) ![en-us_image_0000001233528152](figures/en-us_image_0000001233528152.png)
...@@ -50,26 +49,32 @@ After the project synchronization is complete, the default first page contains t ...@@ -50,26 +49,32 @@ After the project synchronization is complete, the default first page contains t
Add **Column**, **Text**, and **Button** components to the first page. A column is a container component whose child components are vertically arranged. For details, see [Column](../reference/arkui-ts/ts-container-column.md). Add **Column**, **Text**, and **Button** components to the first page. A column is a container component whose child components are vertically arranged. For details, see [Column](../reference/arkui-ts/ts-container-column.md).
1. Delete the existing template components from the canvas.<a name="delete_origin_content"></a> 1. Delete the existing template components from the canvas.<a name="delete_origin_content"></a>
Open the index.visual file, right-click the existing template components on the canvas, and choose **Delete** from the shortcut menu to delete them. Below is an illustration of the operations.
Open the **index.visual** file, right-click the existing template components on the canvas, and choose **Delete** from the shortcut menu to delete them. Below is an illustration of the operations.
![en-us_image_0000001233208980](figures/en-us_image_0000001233208980.gif) ![en-us_image_0000001233208980](figures/en-us_image_0000001233208980.gif)
2. Add a **Column** component and set its styles and attributes.<a name="add_container"></a> 2. Add a **Column** component and set its styles and attributes.<a name="add_container"></a>
Drag the **Column** component from the **UI Control** area to the canvas. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001233048996](figures/en-us_image_0000001233048996.png)**General** and set **Height** to **100%** so that the component fills the entire screen. Click ![en-us_image_0000001233368860](figures/en-us_image_0000001233368860.png)**Feature** and set **AlignItems** to **center** so that the child components of the **Column** component are centered along the horizontal axis. Below is an illustration of the operations. Drag the **Column** component from the **UI Control** area to the canvas. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001233048996](figures/en-us_image_0000001233048996.png)**General** and set **Height** to **100%** so that the component fills the entire screen. Click ![en-us_image_0000001233368860](figures/en-us_image_0000001233368860.png)**Feature** and set **AlignItems** to **center** so that the child components of the **Column** component are centered along the horizontal axis. Below is an illustration of the operations.
![en-us_image_0000001277488977](figures/en-us_image_0000001277488977.gif) ![en-us_image_0000001277488977](figures/en-us_image_0000001277488977.gif)
3. Add a **Text** component. 3. Add a **Text** component.
Drag the **Text** component from the **UI Control** area to the canvas and then to the center area of the **Column** component. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001277608813](figures/en-us_image_0000001277608813.png)**Feature**, set **Content** of the **Text** component to **this.message** (that is, **Hello World**), set **FontSize** to **30fp**, and set **TextAlign** to **center**. Then, select the **Text** component on the canvas and drag its corners to fully display the text. Below is an illustration of the operations. Drag the **Text** component from the **UI Control** area to the canvas and then to the center area of the **Column** component. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001277608813](figures/en-us_image_0000001277608813.png)**Feature**, set **Content** of the **Text** component to **this.message** (that is, **Hello World**), set **FontSize** to **30fp**, and set **TextAlign** to **center**. Then, select the **Text** component on the canvas and drag its corners to fully display the text. Below is an illustration of the operations.
![en-us_image_0000001235731706](figures/en-us_image_0000001235731706.gif) ![en-us_image_0000001235731706](figures/en-us_image_0000001235731706.gif)
4. Add a **Button** component. 4. Add a **Button** component.
Drag the **Button** component from the **UI Control** area to the canvas and then to a position under the **Text** component. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001277728577](figures/en-us_image_0000001277728577.png)**General** and set **Height** of the **Button** component to **40vp**. Click ![en-us_image_0000001277809337](figures/en-us_image_0000001277809337.png)**Feature** and set **Label** to **Next** and **FontSize** to **25fp**. Below is an illustration of the operations. Drag the **Button** component from the **UI Control** area to the canvas and then to a position under the **Text** component. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001277728577](figures/en-us_image_0000001277728577.png)**General** and set **Height** of the **Button** component to **40vp**. Click ![en-us_image_0000001277809337](figures/en-us_image_0000001277809337.png)**Feature** and set **Label** to **Next** and **FontSize** to **25fp**. Below is an illustration of the operations.
![en-us_image_0000001235732402](figures/en-us_image_0000001235732402.gif) ![en-us_image_0000001235732402](figures/en-us_image_0000001235732402.gif)
5. On the toolbar in the upper right corner of the editing window, click **Previewer** to open the Previewer.
5. On the toolbar in the upper right corner of the editing window, click **Previewer** to open the Previewer. Below is how the first page looks in the Previewer. Below is how the first page looks in the Previewer.
![en-us_image_0000001235892798](figures/en-us_image_0000001235892798.png) ![en-us_image_0000001235892798](figures/en-us_image_0000001235892798.png)
...@@ -77,9 +82,10 @@ Add **Column**, **Text**, and **Button** components to the first page. A column ...@@ -77,9 +82,10 @@ Add **Column**, **Text**, and **Button** components to the first page. A column
## Building the Second Page ## Building the Second Page
1. Create the second page. 1. Create the second page.
In the **Project** window, choose **entry** &gt; **src** &gt; **main** &gt; **ets** &gt; **MainAbility**, right-click the **pages** folder, choose **New** &gt; **Visual**, name the page **second**, and click **Finish**. Below is the structure of the **pages** folder.
In the **Project** window, choose **entry** &gt; **src** &gt; **main** &gt; **ets** &gt; **MainAbility**, right-click the **pages** folder, choose **New** &gt; **Visual**, name the page **second**, and click **Finish**. Below, you can see the structure of the **pages** folder.
![en-us_image_0000001233368868](figures/en-us_image_0000001233368868.png) ![en-us_image_0000001233368868](figures/en-us_image_0000001233368868.png)
2. [Delete the existing template components from the canvas.](#delete_origin_content) 2. [Delete the existing template components from the canvas.](#delete_origin_content)
...@@ -108,6 +114,7 @@ Add **Column**, **Text**, and **Button** components to the first page. A column ...@@ -108,6 +114,7 @@ Add **Column**, **Text**, and **Button** components to the first page. A column
![en-us_image_0000001280255513](figures/en-us_image_0000001280255513.gif) ![en-us_image_0000001280255513](figures/en-us_image_0000001280255513.gif)
5. Add a **Button** component. 5. Add a **Button** component.
Drag the **Button** component from the **UI Control** area to the canvas and then to a position under the **Text** component. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001233528160](figures/en-us_image_0000001233528160.png)**General** and set **Height** of the **Button** component to **40vp**. Click ![en-us_image_0000001277728597](figures/en-us_image_0000001277728597.png)**Feature** and set **Value** to **Back** and **FontSize** to **25fp**. Below is an illustration of the operations. Drag the **Button** component from the **UI Control** area to the canvas and then to a position under the **Text** component. In the **Attributes &amp; Styles** area on the right, click ![en-us_image_0000001233528160](figures/en-us_image_0000001233528160.png)**General** and set **Height** of the **Button** component to **40vp**. Click ![en-us_image_0000001277728597](figures/en-us_image_0000001277728597.png)**Feature** and set **Value** to **Back** and **FontSize** to **25fp**. Below is an illustration of the operations.
![en-us_image_0000001280383937](figures/en-us_image_0000001280383937.gif) ![en-us_image_0000001280383937](figures/en-us_image_0000001280383937.gif)
...@@ -118,7 +125,9 @@ Add **Column**, **Text**, and **Button** components to the first page. A column ...@@ -118,7 +125,9 @@ Add **Column**, **Text**, and **Button** components to the first page. A column
You can implement page redirection through the page router, which finds the target page based on the page URI. Import the **router** module and then perform the steps below: You can implement page redirection through the page router, which finds the target page based on the page URI. Import the **router** module and then perform the steps below:
1. Implement redirection from the first page to the second page. 1. Implement redirection from the first page to the second page.
In the files of the first page, bind the **onclick** method to the button so that clicking the button redirects the user to the second page. This operation needs to be completed in both .ets and .visual files.
In the files of the first page, bind the **onclick** method to the button so that clicking the button redirects the user to the second page. This operation needs to be completed in both .ets and .visual files.
- In the **index.ets** file: - In the **index.ets** file:
``` ```
...@@ -143,12 +152,13 @@ You can implement page redirection through the page router, which finds the targ ...@@ -143,12 +152,13 @@ You can implement page redirection through the page router, which finds the targ
} }
} }
``` ```
- In the index.visual file, select the **Button** component on the canvas. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001233209020](figures/en-us_image_0000001233209020.png)**Events** and set **OnClick** to **this.onclick**.
![en-us_image_0000001235745716](figures/en-us_image_0000001235745716.png) - In the **index.visual** file, select the **Button** component on the canvas. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001233209020](figures/en-us_image_0000001233209020.png)**Events** and set **OnClick** to **this.onclick**.
![en-us_image_0000001235745716](figures/en-us_image_0000001235745716.png)
2. Implement redirection from the second page to the first page. 2. Implement redirection from the second page to the first page.
In the files of the second page, bind the **back** method to the **Back** button so that clicking the button redirects the user back to the first page. This operation needs to be completed in both .ets and .visual files. In the files of the second page, bind the **back** method to the **Back** button so that clicking the button redirects the user back to the first page. This operation needs to be completed in both .ets and .visual files.
- In the **second.ets** file: - In the **second.ets** file:
...@@ -174,7 +184,7 @@ You can implement page redirection through the page router, which finds the targ ...@@ -174,7 +184,7 @@ You can implement page redirection through the page router, which finds the targ
} }
} }
``` ```
- In the second.visual file, select the **Button** component on the canvas. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001233368900](figures/en-us_image_0000001233368900.png)**Events** and set **OnClick** to **this.back**. - In the **second.visual** file, select the **Button** component on the canvas. In the **Attributes &amp; Styles** area, click ![en-us_image_0000001233368900](figures/en-us_image_0000001233368900.png)**Events** and set **OnClick** to **this.back**.
![en-us_image_0000001280385809](figures/en-us_image_0000001280385809.png) ![en-us_image_0000001280385809](figures/en-us_image_0000001280385809.png)
......
# SysCap Usage Guidelines # SysCap
## Overview ## Overview
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
- [TypeScript-based Declarative Development Paradigm](arkui-ts/Readme-EN.md) - [TypeScript-based Declarative Development Paradigm](arkui-ts/Readme-EN.md)
- [APIs](apis/Readme-EN.md) - [APIs](apis/Readme-EN.md)
- [JS (eTS Included) APIs](reference/apis/Readme-EN.md) - [JS (eTS Included) APIs](apis/Readme-EN.md)
- Native APIs - Native APIs
- [Standard Library](reference/native-lib/third_party_libc/musl.md) - [Standard Library](native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md) - [Node_API](native-lib/third_party_napi/napi.md)
\ No newline at end of file
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
- [@ohos.application.appManager](js-apis-appmanager.md) - [@ohos.application.appManager](js-apis-appmanager.md)
- [@ohos.application.Configuration](js-apis-configuration.md) - [@ohos.application.Configuration](js-apis-configuration.md)
- [@ohos.application.ConfigurationConstant](js-apis-configurationconstant.md) - [@ohos.application.ConfigurationConstant](js-apis-configurationconstant.md)
- [@ohos.application.DataShareExtensionAbility](js-apis-application-DataShareExtensionAbility.md)
- [@ohos.ability.featureAbility](js-apis-featureAbility.md) - [@ohos.ability.featureAbility](js-apis-featureAbility.md)
- [@ohos.application.formBindingData](js-apis-formbindingdata.md) - [@ohos.application.formBindingData](js-apis-formbindingdata.md)
- [@ohos.application.FormExtension](js-apis-formextension.md) - [@ohos.application.FormExtension](js-apis-formextension.md)
...@@ -57,6 +56,7 @@ ...@@ -57,6 +56,7 @@
- Bundle Management - Bundle Management
- [@ohos.bundle](js-apis-Bundle.md) - [@ohos.bundle](js-apis-Bundle.md)
- [@ohos.bundleState](js-apis-deviceUsageStatistics.md)
- [@ohos.zlib](js-apis-zlib.md) - [@ohos.zlib](js-apis-zlib.md)
- UI Page - UI Page
...@@ -93,8 +93,6 @@ ...@@ -93,8 +93,6 @@
- [@ohos.workScheduler ](js-apis-workScheduler.md) - [@ohos.workScheduler ](js-apis-workScheduler.md)
- [@ohos.WorkSchedulerExtensionAbility](js-apis-WorkSchedulerExtensionAbility.md) - [@ohos.WorkSchedulerExtensionAbility](js-apis-WorkSchedulerExtensionAbility.md)
- [@ohos.bundleState ](js-apis-deviceUsageStatistics.md)
- Custom Management - Custom Management
- [@ohos.configPolicy](js-apis-config-policy.md) - [@ohos.configPolicy](js-apis-config-policy.md)
...@@ -230,6 +228,7 @@ ...@@ -230,6 +228,7 @@
- [@ohos.data.storage](js-apis-data-storage.md) - [@ohos.data.storage](js-apis-data-storage.md)
- [@system.app](js-apis-system-app.md) - [@system.app](js-apis-system-app.md)
- [@system.battery](js-apis-system-battery.md) - [@system.battery](js-apis-system-battery.md)
- [@system.bluetooth](js-apis-system-bluetooth.md)
- [@system.brightness](js-apis-system-brightness.md) - [@system.brightness](js-apis-system-brightness.md)
- [@system.configuration](js-apis-system-configuration.md) - [@system.configuration](js-apis-system-configuration.md)
- [@system.device](js-apis-system-device.md) - [@system.device](js-apis-system-device.md)
...@@ -238,6 +237,7 @@ ...@@ -238,6 +237,7 @@
- [@system.geolocation](js-apis-system-location.md) - [@system.geolocation](js-apis-system-location.md)
- [@system.mediaquery](js-apis-system-mediaquery.md) - [@system.mediaquery](js-apis-system-mediaquery.md)
- [@system.network](js-apis-system-network.md) - [@system.network](js-apis-system-network.md)
- [@system.notification](js-apis-system-notification.md)
- [@system.package](js-apis-system-package.md) - [@system.package](js-apis-system-package.md)
- [@system.prompt](js-apis-system-prompt.md) - [@system.prompt](js-apis-system-prompt.md)
- [@system.request](js-apis-system-request.md) - [@system.request](js-apis-system-request.md)
......
# ErrorCode # ErrorCode
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE** > **NOTE**<br>
> The initial APIs of this module are supported since API version 6. Newly added APIs will be marked with a superscript to indicate their earliest API version. > The initial APIs of this module are supported since API version 6. Newly added APIs will be marked with a superscript to indicate their earliest API version.
...@@ -17,9 +17,9 @@ Defines the error code used when the ability is started. ...@@ -17,9 +17,9 @@ Defines the error code used when the ability is started.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core **System capability**: SystemCapability.Ability.AbilityRuntime.Core
| Name | Value | Description | | Name | Value | Description |
| ------------------------------ | ---- | ---------------------------------------- | | ------------------------------ | ---- | ---------------------------------------- |
| NO_ERROR | 0 | No error occurs. | | NO_ERROR | 0 | No error occurs. |
| INVALID_PARAMETER | -1 | Invalid parameter.| | INVALID_PARAMETER | -1 | Invalid parameter. |
| ABILITY_NOT_FOUND | -2 | The ability is not found.| | ABILITY_NOT_FOUND | -2 | The ability is not found. |
| PERMISSION_DENY | -3 | Permission denied. | | PERMISSION_DENY | -3 | Permission denied. |
# Animation<a name="EN-US_TOPIC_0000001127125026"></a> # Animation<a name="EN-US_TOPIC_0000001127125026"></a>
>![](../../public_sys-resources/icon-note.gif) **NOTE:** > **NOTE:**<br>
>The initial APIs of this module are supported since API version 6. Newly added APIs will be marked with a superscript to indicate their earliest API version. > The initial APIs of this module are supported since API version 6. Newly added APIs will be marked with a superscript to indicate their earliest API version.
## Modules to Import<a name="s0e7b1e85a4274f58a8206e0b065bd80c"></a> ## Modules to Import<a name="s0e7b1e85a4274f58a8206e0b065bd80c"></a>
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册