提交 efade4bb 编写于 作者: Z Zhao-PengFei35

Merge remote-tracking branch 'upstream/master'

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
...@@ -210,6 +210,7 @@ zh-cn/application-dev/reference/apis/js-apis-router.md @HelloCrease ...@@ -210,6 +210,7 @@ zh-cn/application-dev/reference/apis/js-apis-router.md @HelloCrease
zh-cn/application-dev/reference/apis/js-apis-display.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-display.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-screenshot.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-screenshot.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-window.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-window.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-effectKit.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-application-WindowExtensionAbility.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-application-WindowExtensionAbility.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-screen.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-screen.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-windowAnimationManager.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-windowAnimationManager.md @ge-yafang
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
- Quick Start - Quick Start
- Getting Started - Getting Started
- [Preparations](quick-start/start-overview.md) - [Preparations](quick-start/start-overview.md)
- [Getting Started with eTS in the Traditional Coding Approach](quick-start/start-with-ets.md) - [Getting Started with eTS in Stage Model](quick-start/start-with-ets-stage.md)
- [Getting Started with eTS in the Low-Code Approach](quick-start/start-with-ets-low-code.md) - [Getting Started with eTS in FA Model](quick-start/start-with-ets-fa.md)
- [Getting Started with JavaScript in the Traditional Coding Approach](quick-start/start-with-js.md) - [Getting Started with JavaScript in FA Model](quick-start/start-with-js-fa.md)
- [Getting Started with JavaScript in the Low-Code Approach](quick-start/start-with-js-low-code.md)
- Development Fundamentals - Development Fundamentals
- [Application Package Structure Configuration File (FA Model)](quick-start/package-structure.md) - [Application Package Structure Configuration File (FA Model)](quick-start/package-structure.md)
- [Application Package Structure Configuration File (Stage Model)](quick-start/stage-structure.md) - [Application Package Structure Configuration File (Stage Model)](quick-start/stage-structure.md)
- [SysCap](quick-start/syscap.md) - [SysCap](quick-start/syscap.md)
- [HarmonyAppProvision Configuration File](quick-start/app-provision-structure.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)
...@@ -44,5 +44,9 @@ ...@@ -44,5 +44,9 @@
- [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)
- APIs - APIs
- [JS and TS APIs](reference/apis/Readme-EN.md) - [JS and TS APIs](reference/apis/Readme-EN.md)
- Native APIs
- [Standard Libraries](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md)
- [FAQs](faqs/Readme-EN.md)
- Contribution - Contribution
- [How to Contribute](../contribute/documentation-contribution.md) - [How to Contribute](../contribute/documentation-contribution.md)
...@@ -17,5 +17,7 @@ ...@@ -17,5 +17,7 @@
- Other - Other
- [WantAgent Development](wantagent.md) - [WantAgent Development](wantagent.md)
- [Ability Assistant Usage](ability-assistant-guidelines.md) - [Ability Assistant Usage](ability-assistant-guidelines.md)
- [ContinuationManager Development](continuationmanager.md)
- [Test Framework Usage](ability-delegator.md) - [Test Framework Usage](ability-delegator.md)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
An ability is the abstraction of a functionality that an application can provide. It is the minimum unit for the system to schedule applications. An application can contain one or more `Ability` instances. An ability is the abstraction of a functionality that an application can provide. It is the minimum unit for the system to schedule applications. An application can contain one or more `Ability` instances.
The ability framework model has two forms. The ability framework model has two forms:
- FA model, which applies to application development using API version 8 and earlier versions. In the FA model, there is Feature Ability (FA) and Particle Ability (PA). The FA supports Page abilities, and the PA supports Service, Data, and Form abilities. - FA model, which applies to application development using API version 8 and earlier versions. In the FA model, there is Feature Ability (FA) and Particle Ability (PA). The FA supports Page abilities, and the PA supports Service, Data, and Form abilities.
- Stage model, which is introduced since API version 9. In the stage model, there is `Ability` and `ExtensionAbility`. `ExtensionAbility` is further extended to `ServiceExtensionAbility`, `FormExtensionAbility`, `DataShareExtensionAbility`, and more. - Stage model, which is introduced since API version 9. In the stage model, there is `Ability` and `ExtensionAbility`. `ExtensionAbility` is further extended to `ServiceExtensionAbility`, `FormExtensionAbility`, `DataShareExtensionAbility`, and more.
...@@ -11,10 +11,10 @@ The stage model is designed to make it easier to develop complex applications in ...@@ -11,10 +11,10 @@ The stage model is designed to make it easier to develop complex applications in
| Item | FA Model | Stage Model | | Item | FA Model | Stage Model |
| -------------- | ------------------------------------------------------------ | -------------------------------------------------------- | | -------------- | ------------------------------------------------------------ | -------------------------------------------------------- |
| Development mode | Web-like APIs are provided. The UI development is the same as that of the stage model. | Object-oriented development mode is provided. The UI development is the same as that of the FA model. | | Development mode | Web-like APIs are provided. The UI development is the same as that of the stage model. | Object-oriented development mode is provided. The UI development is the same as that of the FA model. |
| Engine instance | Each ability in a process exclusively uses a JS VM engine instance. | Multiple abilities in a process share one JS VM engine instance. | | Engine instance | Each ability in a process exclusively uses a JS VM engine instance. | Multiple abilities in a process share one JS VM engine instance. |
| Intra-process object sharing| Not supported. | Supported. | | Intra-process object sharing| Not supported. | Supported. |
| Bundle description file | The `config.json` file is used to describe the HAP and component information. Each component must use a fixed file name.| The `module.json` file is used to describe the HAP and component information. The entry file name can be specified.| | Bundle description file | The `config.json` file is used to describe the HAP and component information. Each component must use a fixed file name.| The `module.json5` file is used to describe the HAP and component information. The entry file name can be specified.|
| Component | Four types of components are provided: Page ability (used for UI page display), Service ability (used to provide services), Data ability (used for data sharing), and Form ability (used to provide widgets).| Two types of components are provided: Ability (used for UI page display) and Extension (scenario-based service extension). | | Component | Four types of components are provided: Page ability (used for UI page display), Service ability (used to provide services), Data ability (used for data sharing), and Form ability (used to provide widgets).| Two types of components are provided: Ability (used for UI page display) and Extension (scenario-based service extension). |
In addition, the following differences exist in the development process: In addition, the following differences exist in the development process:
...@@ -27,5 +27,4 @@ In addition, the following differences exist in the development process: ...@@ -27,5 +27,4 @@ In addition, the following differences exist in the development process:
![lifecycle](figures/lifecycle.png) ![lifecycle](figures/lifecycle.png)
For details about the two models, see [FA Model Overview](fa-brief.md) and [Stage Model Overview](stage-brief.md). For details about the two models, see [FA Model Overview](fa-brief.md) and [Stage Model Overview](stage-brief.md).
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model. The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model.
- FA model - FA model
Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance. Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance.
- Stage model - Stage model
The stage model has the following types of contexts: **application/Context**, **application/ApplicationContext**, **application/AbilityStageContext**, **application/ExtensionContext**, **application/AbilityContext**, and **application/FormExtensionContext**. For details about these contexts and how to use them, see [Context in the Stage Model](#context-in-the-stage-model). The stage model has the following types of contexts: **application/Context**, **application/ApplicationContext**, **application/AbilityStageContext**, **application/ExtensionContext**, **application/AbilityContext**, and **application/FormExtensionContext**. 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) ![contextIntroduction](figures/contextIntroduction.png)
......
# ContinuationManager Development
> **NOTE**
>
> Currently, the **ContinuationManager** module is not available for application development. Its APIs are mainly used to start the device selection module.
## When to Use
Users are using two or more devices to experience an all-scenario, multi-device lifestyle. Each type of device has its unique advantages and disadvantages specific to scenarios. The ability continuation capability breaks boundaries of devices and enables multi-device collaboration, achieving precise control, universal coordination, and seamless hops of user applications.
As the entry of the ability continuation capability, **continuationManager** is used to start the device selection module for the user to select the target device. After a device is selected, information about the selected device is returned to the user. The user can then initiate cross-device continuation or collaboration based on the device information.
![continuationManager](figures/continuationManager.png)
## Available APIs
| API | Description|
| ---------------------------------------------------------------------------------------------- | ----------- |
| register(callback: AsyncCallback\<number>): void | Registers the continuation management service and obtains a token. This API does not involve any filter parameters and uses an asynchronous callback to return the result.|
| register(options: ContinuationExtraParams, callback: AsyncCallback\<number>): void | Registers the continuation management service and obtains a token. This API uses an asynchronous callback to return the result.|
| register(options?: ContinuationExtraParams): Promise\<number> | Registers the continuation management service and obtains a token. This API uses a promise to return the result.|
| on(type: "deviceConnect", token: number, callback: Callback\<Array\<ContinuationResult>>): void | Subscribes to device connection events. This API uses an asynchronous callback to return the result.|
| on(type: "deviceDisconnect", token: number, callback: Callback\<Array\<string>>): void | Subscribes to device disconnection events. This API uses an asynchronous callback to return the result.|
| off(type: "deviceConnect", token: number): void | Unsubscribes from device connection events.|
| off(type: "deviceDisconnect", token: number): void | Unsubscribes from device disconnection events.|
| startDeviceManager(token: number, callback: AsyncCallback\<void>): void | Starts the device selection module to show the list of available devices. This API does not involve any filter parameters and uses an asynchronous callback to return the result.|
| startDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\<void>): void | Starts the device selection module to show the list of available devices. This API uses an asynchronous callback to return the result.|
| startDeviceManager(token: number, options?: ContinuationExtraParams): Promise\<void> | Starts the device selection module to show the list of available devices. This API uses a promise to return the result.|
| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\<void>): void | Instructs the device selection module to update the device connection state. This API uses an asynchronous callback to return the result.|
| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState): Promise\<void> | Instructs the device selection module to update the device connection state. This API uses a promise to return the result.|
| unregister(token: number, callback: AsyncCallback\<void>): void | Deregisters the continuation management service. This API uses an asynchronous callback to return the result.|
| unregister(token: number): Promise\<void> | Deregisters the continuation management service. This API uses a promise to return the result.|
## How to Develop
1. Import the **continuationManager** module.
```ts
import continuationManager from '@ohos.continuation.continuationManager';
```
2. Apply for permissions required for cross-device continuation or collaboration operations.
The permission application operation varies according to the ability model in use. In the FA mode, add the required permission in the `config.json` file, as follows:
```json
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
}
}
```
This permission must also be granted by the user through a dialog box when the application is started for the first time. The sample code is as follows:
```ts
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import bundle from '@ohos.bundle';
async function requestPermission() {
let permissions: Array<string> = [
"ohos.permission.DISTRIBUTED_DATASYNC"
];
let needGrantPermission: boolean = false;
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let applicationInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', 0, 100);
for (let i = 0; i < permissions.length; i++) {
let result = await atManager.verifyAccessToken(applicationInfo.accessTokenId, permissions[i]);
// Check whether the permission is granted.
if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
needGrantPermission = true;
break;
}
}
// If the permission is not granted, call requestPermissionsFromUser to apply for the permission.
if (needGrantPermission) {
await featureAbility.getContext().requestPermissionsFromUser(permissions, 1);
} else {
console.info('app permission already granted');
}
}
```
In the stage model, add the required permission in the `module.json5` file. The sample code is as follows:
```json
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
}
}
```
```ts
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import bundle from '@ohos.bundle';
async function requestPermission() {
let permissions: Array<string> = [
"ohos.permission.DISTRIBUTED_DATASYNC"
];
let needGrantPermission: boolean = false;
let atManger: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let applicationInfo = await bundle.getApplicationInfo('ohos.samples.continuationmanager', 0, 100);
for (const permission of permissions) {
try {
let grantStatus = await atManger.verifyAccessToken(applicationInfo.accessTokenId, permission);
// Check whether the permission is granted.
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
needGrantPermission = true;
break;
}
} catch (err) {
console.error('app permission query grant status error' + JSON.stringify(err));
needGrantPermission = true;
break;
}
}
// If the permission is not granted, call requestPermissionsFromUser to apply for the permission.
if (needGrantPermission) {
try {
await globalThis.abilityContext.requestPermissionsFromUser(permissions);
} catch (err) {
console.error('app permission request permissions error' + JSON.stringify(err));
}
} else {
console.info('app permission already granted');
}
}
```
3. Register the continuation management service and obtain a token.
The sample code is as follows:
```ts
let token: number = -1; // Used to save the token returned after the registration. The token will be used when listening for device connection/disconnection events, starting the device selection module, and updating the device connection state.
continuationManager.register().then((data) => {
console.info('register finished, ' + JSON.stringify(data));
token = data; // Obtain a token and assign a value to the token variable.
}).catch((err) => {
console.error('register failed, cause: ' + JSON.stringify(err));
});
```
4. Listen for the device connection/disconnection state.
The sample code is as follows:
```ts
let remoteDeviceId: string = ""; // Used to save the information about the remote device selected by the user, which will be used for cross-device continuation or collaboration.
// The token parameter is the token obtained during the registration.
continuationManager.on("deviceConnect", token, (continuationResults) => {
console.info('registerDeviceConnectCallback len: ' + continuationResults.length);
if (continuationResults.length <= 0) {
console.info('no selected device');
return;
}
remoteDeviceId = continuationResults[0].id; // Assign the deviceId of the first selected remote device to the remoteDeviceId variable.
// Pass the remoteDeviceId parameter to want.
let want = {
deviceId: remoteDeviceId,
bundleName: 'ohos.samples.continuationmanager',
abilityName: 'MainAbility'
};
// To initiate multi-device collaboration, you must obtain the ohos.permission.DISTRIBUTED_DATASYNC permission.
globalThis.abilityContext.startAbility(want).then((data) => {
console.info('StartRemoteAbility finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('StartRemoteAbility failed, cause: ' + JSON.stringify(err));
});
});
```
The preceding multi-device collaboration operation is performed across devices in the stage model. For details about this operation in the FA model, see [Page Ability Development](https://gitee.com/openharmony/docs/blob/master/en/application-dev/ability/fa-pageability.md).
You can also instruct the device selection module to update the device connection state. The sample code is as follows:
```ts
// Set the device connection state.
let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.CONNECTED;
// The token parameter is the token obtained during the registration, and the remoteDeviceId parameter is the remoteDeviceId obtained.
continuationManager.updateConnectStatus(token, remoteDeviceId, deviceConnectStatus).then((data) => {
console.info('updateConnectStatus finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err));
});
```
Listen for the device disconnection state so that the user can stop cross-device continuation or collaboration in time. The sample code is as follows:
```ts
// The token parameter is the token obtained during the registration.
continuationManager.on("deviceDisconnect", token, (deviceIds) => {
console.info('onDeviceDisconnect len: ' + deviceIds.length);
if (deviceIds.length <= 0) {
console.info('no unselected device');
return;
}
// Update the device connection state.
let unselectedDeviceId: string = deviceIds[0]; // Assign the deviceId of the first deselected remote device to the unselectedDeviceId variable.
let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.DISCONNECTING; // Device disconnected.
// The token parameter is the token obtained during the registration, and the unselectedDeviceId parameter is the unselectedDeviceId obtained.
continuationManager.updateConnectStatus(token, unselectedDeviceId, deviceConnectStatus).then((data) => {
console.info('updateConnectStatus finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err));
});
});
```
5. Start the device selection module to show the list of available devices on the network.
The sample code is as follows:
```ts
// Filter parameters.
let continuationExtraParams = {
deviceType: ["00E"], // Device type.
continuationMode: continuationManager.ContinuationMode.COLLABORATION_SINGLE // Single-choice mode of the device selection module.
};
// The token parameter is the token obtained during the registration.
continuationManager.startDeviceManager(token, continuationExtraParams).then((data) => {
console.info('startDeviceManager finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('startDeviceManager failed, cause: ' + JSON.stringify(err));
});
```
6. If you do not need to perform cross-device migration or collaboration operations, you can deregister the continuation management service, by passing the token obtained during the registration.
The sample code is as follows:
```ts
// The token parameter is the token obtained during the registration.
continuationManager.unregister(token).then((data) => {
console.info('unregister finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('unregister failed, cause: ' + JSON.stringify(err));
});
```
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## Widget Overview ## Widget Overview
A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application. A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application.
A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message. A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message.
Basic concepts: Basic concepts:
- Widget provider: an atomic service that controls what and how content is displayed in a widget and interacts with users. - Widget provider: an atomic service that controls what and how content is displayed in a widget and interacts with users.
...@@ -157,8 +157,8 @@ Configure the **config.json** file for the widget. ...@@ -157,8 +157,8 @@ Configure the **config.json** file for the widget.
| supportDimensions | Grid styles supported by the widget. Available values are as follows:<br>**1 * 2**: indicates a grid with one row and two columns.<br>**2 * 2**: indicates a grid with two rows and two columns.<br>**2 * 4**: indicates a grid with two rows and four columns.<br>**4 * 4**: indicates a grid with four rows and four columns.| String array| No | | supportDimensions | Grid styles supported by the widget. Available values are as follows:<br>**1 * 2**: indicates a grid with one row and two columns.<br>**2 * 2**: indicates a grid with two rows and two columns.<br>**2 * 4**: indicates a grid with two rows and four columns.<br>**4 * 4**: indicates a grid with four rows and four columns.| String array| No |
| defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No |
| updateEnabled | Whether the widget can be updated periodically. Available values are as follows:<br>**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is preferentially recommended.<br>**false**: The widget cannot be updated periodically.| Boolean | No | | updateEnabled | Whether the widget can be updated periodically. Available values are as follows:<br>**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is preferentially recommended.<br>**false**: The widget cannot be updated periodically.| Boolean | No |
| scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute. | String | Yes (initial value: **0:0**) | | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.<br>This parameter has a lower priority than **updateDuration**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) |
| updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.| Number | Yes (initial value: **0**) | | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.<br>This parameter has a higher priority than **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) |
| formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) |
| formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) |
| jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes. | String | No | | jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes. | String | No |
...@@ -189,7 +189,6 @@ Configure the **config.json** file for the widget. ...@@ -189,7 +189,6 @@ Configure the **config.json** file for the widget.
"scheduledUpdateTime": "10:30", "scheduledUpdateTime": "10:30",
"supportDimensions": ["2*2"], "supportDimensions": ["2*2"],
"type": "JS", "type": "JS",
"updateDuration": 1,
"updateEnabled": true "updateEnabled": true
}] }]
}] }]
...@@ -208,7 +207,7 @@ Mostly, the widget provider is started only when it needs to obtain information ...@@ -208,7 +207,7 @@ Mostly, the widget provider is started only when it needs to obtain information
let formName = want.parameters["ohos.extra.param.key.form_name"]; let formName = want.parameters["ohos.extra.param.key.form_name"];
let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];
// Persistently store widget information for subsequent use, such as widget instance retrieval or update. // Persistently store widget information for subsequent use, such as widget instance retrieval or update.
// The storeFormInfo API is not implemented here. For details about the implementation, see "FA Model Widget" provided in "Samples". // The storeFormInfo API is not implemented here.
storeFormInfo(formId, formName, tempFlag, want); storeFormInfo(formId, formName, tempFlag, want);
let obj = { let obj = {
...@@ -227,7 +226,7 @@ You should override **onDestroy** to delete widget data. ...@@ -227,7 +226,7 @@ You should override **onDestroy** to delete widget data.
console.log('FormAbility onDestroy'); console.log('FormAbility onDestroy');
// You need to implement the code for deleting the persistent widget instance. // You need to implement the code for deleting the persistent widget instance.
// The deleteFormInfo API is not implemented here. For details, see "Widget Host" provided in "Samples". // The deleteFormInfo API is not implemented here.
deleteFormInfo(formId); deleteFormInfo(formId);
} }
``` ```
...@@ -336,7 +335,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme ...@@ -336,7 +335,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
"actions": { "actions": {
"routerEvent": { "routerEvent": {
"action": "router", "action": "router",
"abilityName": "com.example.MyApplication.hmservice.FormAbility", "abilityName": "com.example.entry.MainAbility",
"params": { "params": {
"message": "add detail" "message": "add detail"
} }
...@@ -349,3 +348,57 @@ Now you've got a widget shown below. ...@@ -349,3 +348,57 @@ Now you've got a widget shown below.
![fa-form-example](figures/fa-form-example.png) ![fa-form-example](figures/fa-form-example.png)
### Developing Widget Events
You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows:
1. Set **onclick** in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file.
2. For the router event, set the following attributes:
- **action**: **"router"**.
- **abilityName**: target ability name, for example, **com.example.entry.MainAbility**, which is the default main ability name in DevEco Studio for the FA model.
- **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field.
3. For the message event, set the following attributes:
- **action**: **"message"**.
- **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**.
The code snippet is as follows:
- In the HML file:
```html
<div class="container">
<stack>
<div class="container-img">
<image src="/common/widget.png" class="bg-img"></image>
</div>
<div class="container-inner">
<text class="title" onclick="routerEvent">{{title}}</text>
<text class="detail_text" onclick="messageEvent">{{detail}}</text>
</div>
</stack>
</div>
```
- In the JSON file:
```json
{
"data": {
"title": "TitleDefault",
"detail": "TextDefault"
},
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "com.example.entry.MainAbility",
"params": {
"message": "add detail"
}
},
"messageEvent": {
"action": "message",
"params": {
"message": "add detail"
}
}
}
}
```
\ No newline at end of file
# Ability Development # Ability Development
## When to Use ## When to Use
Ability development in the [stage model](stage-brief.md) is significantly different from that in the FA model. The stage model requires you to declare the application package structure in the `module.json` and `app.json` files during application development. For details about the configuration file, see [Application Package Structure Configuration File](../quick-start/stage-structure.md). To develop an ability based on the stage model, implement the following logic: Ability development in the [stage model](stage-brief.md) is significantly different from that in the FA model. The stage model requires you to declare the application package structure in the `module.json5` and `app.json5` files during application development. For details about the configuration file, see [Application Package Structure Configuration File](../quick-start/stage-structure.md). To develop an ability based on the stage model, implement the following logic:
- Create an ability that supports screen viewing and human-machine interaction. You must implement the following scenarios: ability lifecycle callbacks, obtaining ability configuration, requesting permissions, and notifying environment changes. - Create an ability that supports screen viewing and human-machine interaction. You must implement the following scenarios: ability lifecycle callbacks, obtaining ability configuration, requesting permissions, and notifying environment changes.
- Start an ability. You need to implement ability startup on the same device, on a remote device, or with a specified UI page. - Start an ability. You need to implement ability startup on the same device, on a remote device, or with a specified UI page.
- Call abilities. For details, see [Call Development](stage-call.md). - Call abilities. For details, see [Call Development](stage-call.md).
...@@ -8,7 +8,7 @@ Ability development in the [stage model](stage-brief.md) is significantly differ ...@@ -8,7 +8,7 @@ Ability development in the [stage model](stage-brief.md) is significantly differ
- Continue the ability on another device. For details, see [Ability Continuation Development](stage-ability-continuation.md). - Continue the ability on another device. For details, see [Ability Continuation Development](stage-ability-continuation.md).
### Launch Type ### Launch Type
An ability can be launched in the **standard**, **singleton**, or **specified** mode, as configured by `launchType` in the `module.json` file. Depending on the launch type, the action performed when the ability is started differs, as described below. An ability can be launched in the **standard**, **singleton**, or **specified** mode, as configured by `launchType` in the `module.json5` file. Depending on the launch type, the action performed when the ability is started differs, as described below.
| Launch Type | Description |Action | | Launch Type | Description |Action |
| ----------- | ------- |---------------- | | ----------- | ------- |---------------- |
...@@ -16,7 +16,7 @@ An ability can be launched in the **standard**, **singleton**, or **specified** ...@@ -16,7 +16,7 @@ An ability can be launched in the **standard**, **singleton**, or **specified**
| singleton | Singleton | The ability has only one instance in the system. If an instance already exists when an ability is started, that instance is reused.| | singleton | Singleton | The ability has only one instance in the system. If an instance already exists when an ability is started, that instance is reused.|
| specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.| | specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.|
By default, the singleton mode is used. The following is an example of the `module.json` file: By default, the singleton mode is used. The following is an example of the `module.json5` file:
```json ```json
{ {
"module": { "module": {
...@@ -87,7 +87,7 @@ To create Page abilities for an application in the stage model, you must impleme ...@@ -87,7 +87,7 @@ To create Page abilities for an application in the stage model, you must impleme
onWindowStageCreate(windowStage) { onWindowStageCreate(windowStage) {
console.log("MainAbility onWindowStageCreate") console.log("MainAbility onWindowStageCreate")
windowStage.loadContent("pages/index").then((data) => { windowStage.loadContent("pages/index").then(() => {
console.log("MainAbility load content succeed") console.log("MainAbility load content succeed")
}).catch((error) => { }).catch((error) => {
console.error("MainAbility load content failed with error: " + JSON.stringify(error)) console.error("MainAbility load content failed with error: " + JSON.stringify(error))
...@@ -149,9 +149,9 @@ export default class MainAbility extends Ability { ...@@ -149,9 +149,9 @@ export default class MainAbility extends Ability {
} }
``` ```
### Requesting Permissions ### Requesting Permissions
If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from consumers. During application development, you need to specify the involved sensitive permissions, declare the required permissions in `module.json`, and use the `requestPermissionsFromUser` API to request the permission from consumers in the form of a dialog box. The following uses the permission for calendar access as an example. If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from consumers. During application development, you need to specify the involved sensitive permissions, declare the required permissions in `module.json5`, and use the `requestPermissionsFromUser` API to request the permission from consumers in the form of a dialog box. The following uses the permission for calendar access as an example.
Declare the required permission in the `module.json` file. Declare the required permission in the `module.json5` file.
```json ```json
"requestPermissions": [ "requestPermissions": [
{ {
...@@ -231,8 +231,8 @@ var want = { ...@@ -231,8 +231,8 @@ var want = {
"bundleName": "com.example.MyApplication", "bundleName": "com.example.MyApplication",
"abilityName": "MainAbility" "abilityName": "MainAbility"
}; };
context.startAbility(want).then((data) => { context.startAbility(want).then(() => {
console.log("Succeed to start ability with data: " + JSON.stringify(data)) console.log("Succeed to start ability")
}).catch((error) => { }).catch((error) => {
console.error("Failed to start ability with error: "+ JSON.stringify(error)) console.error("Failed to start ability with error: "+ JSON.stringify(error))
}) })
...@@ -248,8 +248,8 @@ var want = { ...@@ -248,8 +248,8 @@ var want = {
"bundleName": "com.example.MyApplication", "bundleName": "com.example.MyApplication",
"abilityName": "MainAbility" "abilityName": "MainAbility"
}; };
context.startAbility(want).then((data) => { context.startAbility(want).then(() => {
console.log("Succeed to start remote ability with data: " + JSON.stringify(data)) console.log("Succeed to start remote ability")
}).catch((error) => { }).catch((error) => {
console.error("Failed to start remote ability with error: " + JSON.stringify(error)) console.error("Failed to start remote ability with error: " + JSON.stringify(error))
}) })
......
# Ability Call Development # Ability Call Development
## When to Use ## When to Use
Ability call is an extension of the ability capabilities. It enables an ability to be invoked by external systems. In this way, the ability can be displayed as a UI page on the foreground and created and run on the background. You can use the **Call** APIs to implement data sharing between different abilities through inter-process communication (IPC). There are two roles in the ability call: caller and callee. The following scenarios are involved in the ability call development: Ability call is an extension of the ability capability. It enables an ability to be invoked by and communicate with external systems. The ability invoked can be either started in the foreground or created and run in the background. You can use the ability call to implement data sharing between two abilities (caller ability and callee ability) through inter-process communication (IPC).
- Creating a callee
- Accessing the callee
The following figure shows the ability call process. The core API used for the ability call is `startAbilityByCall`, which differs from `startAbility` in the following ways:
- `startAbilityByCall` supports ability startup in the foreground and background, whereas `startAbility` supports ability startup in the foreground only.
- The caller ability can use the `Caller` object returned by `startAbilityByCall` to communicate with the callee ability, but `startAbility` does not provide the communication capability.
Ability call is usually used in the following scenarios:
- Communicating with the callee ability
- Starting the callee ability in the background
**Table 1** Terms used in the ability call
|Term|Description|
|:------|:------|
|Caller ability|Ability that triggers the ability call.|
|Callee ability|Ability invoked by the ability call.|
|Caller |Object returned by `startAbilityByCall` and used by the caller ability to communicate with the callee ability.|
|Callee |Object held by the callee ability to communicate with the caller ability.|
|IPC |Inter-process communication.|
The ability call process is as follows:
- The caller ability uses `startAbilityByCall` to obtain a `Caller` object and uses `call()` of the `Caller` object to send data to the callee ability.
- The callee ability, which holds a `Callee` object, uses `on()` of the `Callee` object to register a callback. This callback is invoked when the callee ability receives data from the caller ability.
![stage-call](figures/stage-call.png) ![stage-call](figures/stage-call.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/> > **NOTE**<br/>
> The startup mode of the callee must be **singleton**. > The launch type of the callee ability must be `singleton`.
> Currently, only system applications and Service Extension abilities can use the **Call** APIs to access the callee. > Currently, only system applications can use the ability call.
## 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 2** Ability call APIs
|API|Description| |API|Description|
|:------|:------| |:------|:------|
|startAbilityByCall(want: Want): Promise\<Caller>|Obtains the caller interface of the specified ability and, if the specified ability is not running, starts the ability in the background.| |startAbilityByCall(want: Want): Promise\<Caller>|Starts an ability in the foreground (through the `want` configuration) or background (default) and obtains the `Caller` object for communication with the ability. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextstartabilitybycall) or [ServiceExtensionContext](../reference/apis/js-apis-service-extension-context.md#serviceextensioncontextstartabilitybycall).|
|on(method: string, callback: CalleeCallBack): void|Callback invoked when the callee registers a method.| |on(method: string, callback: CalleeCallBack): void|Callback invoked when the callee ability registers a method.|
|off(method: string): void|Callback invoked when the callee deregisters a method.| |off(method: string): void|Callback invoked when the callee ability deregisters a method.|
|call(method: string, data: rpc.Sequenceable): Promise\<void>|Sends agreed sequenceable data to the callee.| |call(method: string, data: rpc.Sequenceable): Promise\<void>|Sends agreed sequenceable data to the callee ability.|
|callWithResult(method: string, data: rpc.Sequenceable): Promise\<rpc.MessageParcel>|Sends agreed sequenceable data to the callee and returns the agreed sequenceable data.| |callWithResult(method: string, data: rpc.Sequenceable): Promise\<rpc.MessageParcel>|Sends agreed sequenceable data to the callee ability and obtains the agreed sequenceable data returned by the callee ability.|
|release(): void|Releases the caller interface.| |release(): void|Releases the `Caller` object.|
|onRelease(callback: OnReleaseCallBack): void|Registers a callback that is invoked when the caller is disconnected.| |onRelease(callback: OnReleaseCallBack): void|Callback invoked when the `Caller` object is released.|
## How to Develop ## How to Develop
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/> The procedure for developing the ability call is as follows:
> The sample code snippets provided in the **How to Develop** section are used to show specific development steps. They may not be able to run independently. 1. Create a callee ability.
### Creating a Callee 2. Access the callee ability.
For the callee, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use the **on** API to register a listener. When data does not need to be received, use the **off** API to deregister the listener. > **NOTE**
1. Configure the ability startup mode. >
> The code snippets provided in the **How to Develop** section are used to show specific development steps. They may not be able to run independently.
### Creating a Callee Ability
For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use `on()` to register a listener. When data does not need to be received, use `off()` to deregister the listener.
**1. Configure the ability launch type.**
Set the ability of the callee to **singleton** in the **module.json5** file. Set `launchType` of the callee ability to `singleton` in the `module.json5` file.
|JSON Field|Description| |JSON Field|Description|
|:------|:------| |:------|:------|
|"launchType"|Ability startup mode. Set this parameter to **singleton**.| |"launchType"|Ability launch type. Set this parameter to `singleton`.|
An example of the ability configuration is as follows: An example of the ability configuration is as follows:
```json ```json
...@@ -51,13 +71,13 @@ An example of the ability configuration is as follows: ...@@ -51,13 +71,13 @@ An example of the ability configuration is as follows:
"visible": true "visible": true
}] }]
``` ```
2. Import the **Ability** module. **2. Import the Ability module.**
``` ```ts
import Ability from '@ohos.application.Ability' import Ability from '@ohos.application.Ability'
``` ```
3. Define the agreed sequenceable data. **3. Define the agreed sequenceable data.**
The data formats sent and received by the caller and callee must be consistent. In the following example, the data consists of numbers and strings. The sample code snippet is as follows: The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string. The code snippet is as follows:
```ts ```ts
export default class MySequenceable { export default class MySequenceable {
num: number = 0 num: number = 0
...@@ -81,23 +101,23 @@ export default class MySequenceable { ...@@ -81,23 +101,23 @@ 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 **MSG_SEND_METHOD** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The sample code snippet is as follows: The time to register a listener for the callee ability 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 `MSG_SEND_METHOD` listener is registered in `onCreate` of the ability and deregistered in `onDestroy`. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The code snippet 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'
function sendMsgCallback(data) { function sendMsgCallback(data) {
Logger.log(TAG, 'CalleeSortFunc called') console.log('CalleeSortFunc called')
// Obtain the sequenceable data sent by the caller. // Obtain the sequenceable data sent by the caller ability.
let receivedData = new MySequenceable(0, '') let receivedData = new MySequenceable(0, '')
data.readSequenceable(receivedData) data.readSequenceable(receivedData)
Logger.log(TAG, `receiveData[${receivedData.num}, ${receivedData.str}]`) console.log(`receiveData[${receivedData.num}, ${receivedData.str}]`)
// Process the data. // Process the data.
// Return the sequenceable data result to the caller. // Return the sequenceable data result to the caller ability.
return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`) return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`)
} }
...@@ -106,7 +126,7 @@ export default class CalleeAbility extends Ability { ...@@ -106,7 +126,7 @@ export default class CalleeAbility extends Ability {
try { try {
this.callee.on(MSG_SEND_METHOD, sendMsgCallback) this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
} catch (error) { } catch (error) {
Logger.error(TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) console.log(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
} }
} }
...@@ -120,15 +140,27 @@ export default class CalleeAbility extends Ability { ...@@ -120,15 +140,27 @@ export default class CalleeAbility extends Ability {
} }
``` ```
### Accessing the Callee ### Accessing the Callee Ability
1. Import the **Ability** module. **1. Import the Ability module.**
``` ```ts
import Ability from '@ohos.application.Ability' import Ability from '@ohos.application.Ability'
``` ```
2. Obtain the caller interface. **2. Obtain the `Caller` object.**
The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller interface of the ability. The following example uses **this.context** to obtain the **context** attribute of the **Ability** instance, uses **startAbilityByCall** to start the callee, obtain the caller interface, and register the **onRelease** listener of the caller. You need to implement processing based on service requirements. The sample code snippet is as follows: The `context` attribute of the ability implements `startAbilityByCall` to obtain the `Caller` object for communication. The following example uses `this.context` to obtain the `context` attribute of the ability, uses `startAbilityByCall` to start the callee ability, obtain the `Caller` object, and register the `onRelease` listener of the caller ability. You need to implement processing based on service requirements. The code snippet is as follows:
```ts ```ts
// Register the onRelease listener of the caller ability.
private regOnRelease(caller) {
try {
caller.onRelease((msg) => {
console.log(`caller onRelease is called ${msg}`)
})
console.log('caller register OnRelease succeed')
} catch (error) {
console.log(`caller register OnRelease failed with ${error}`)
}
}
async onButtonGetCaller() { async onButtonGetCaller() {
try { try {
this.caller = await context.startAbilityByCall({ this.caller = await context.startAbilityByCall({
...@@ -136,73 +168,74 @@ async onButtonGetCaller() { ...@@ -136,73 +168,74 @@ async onButtonGetCaller() {
abilityName: 'CalleeAbility' abilityName: 'CalleeAbility'
}) })
if (this.caller === undefined) { if (this.caller === undefined) {
Logger.error(TAG, 'get caller failed') console.log('get caller failed')
return return
} }
Logger.log(TAG, 'get caller success') console.log('get caller success')
this.regOnRelease(this.caller) this.regOnRelease(this.caller)
} catch (error) { } catch (error) {
Logger.error(TAG, `get caller failed with ${error}`) console.log(`get caller failed with ${error}`)
} }
}.catch((error) => { }
console.error(TAG + 'get caller failed with ' + error)
})
``` ```
In the cross-device scenario, you need to specify the ID of the peer device. The sample code snippet is as follows: In the cross-device scenario, you need to specify the ID of the peer device. The code snippet is as follows:
```ts ```ts
let TAG = '[MainAbility] ' async onButtonGetRemoteCaller() {
var caller = undefined var caller = undefined
let context = this.context var context = this.context
context.startAbilityByCall({ context.startAbilityByCall({
deviceId: getRemoteDeviceId(), deviceId: getRemoteDeviceId(),
bundleName: 'com.samples.CallApplication', bundleName: 'com.samples.CallApplication',
abilityName: 'CalleeAbility' abilityName: 'CalleeAbility'
}).then((data) => { }).then((data) => {
if (data != null) { if (data != null) {
caller = data caller = data
console.log(TAG + 'get remote caller success') console.log('get remote caller success')
// Register the onRelease listener of the caller. // Register the onRelease listener of the caller ability.
caller.onRelease((msg) => { caller.onRelease((msg) => {
console.log(TAG + 'remote caller onRelease is called ' + msg) console.log(`remote caller onRelease is called ${msg}`)
}) })
console.log(TAG + 'remote caller register OnRelease succeed') console.log('remote caller register OnRelease succeed')
} }
}).catch((error) => { }).catch((error) => {
console.error(TAG + 'get remote caller failed with ' + error) console.error(`get remote caller failed with ${error}`)
}) })
}
``` ```
Obtain the ID of the peer device from **DeviceManager**. Note that the **getTrustedDeviceListSync** API is open only to system applications. The sample code snippet is as follows: Obtain the ID of the peer device from `DeviceManager`. Note that the `getTrustedDeviceListSync` API is open only to system applications. The code snippet is as follows:
```ts ```ts
import deviceManager from '@ohos.distributedHardware.deviceManager'; import deviceManager from '@ohos.distributedHardware.deviceManager';
var dmClass; var dmClass;
function getRemoteDeviceId() { function getRemoteDeviceId() {
if (typeof dmClass === 'object' && dmClass != null) { if (typeof dmClass === 'object' && dmClass != null) {
var list = dmClass.getTrustedDeviceListSync(); var list = dmClass.getTrustedDeviceListSync()
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null")
return; return
} }
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId)
return list[0].deviceId; return list[0].deviceId
} else { } else {
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null")
} }
} }
``` ```
In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code snippet is as follows: In the cross-device scenario, your application must also apply for the data synchronization permission from end users. The code snippet is as follows:
```ts ```ts
let context = this.context requestPermission() {
let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC'] let context = this.context
context.requestPermissionsFromUser(permissions).then((data) => { let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
console.log("Succeed to request permission from user with data: "+ JSON.stringify(data)) context.requestPermissionsFromUser(permissions).then((data) => {
}).catch((error) => { console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
console.log("Failed to request permission from user with error: "+ JSON.stringify(error)) }).catch((error) => {
}) console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
})
}
``` ```
3. Send agreed sequenceable data. **3. Send agreed sequenceable data.**
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 snippet is as follows: The sequenceable data can be sent to the callee ability with or without a return value. The method and sequenceable data must be consistent with those of the callee ability. The following example describes how to send data to the callee ability. The code snippet is as follows:
```ts ```ts
const MSG_SEND_METHOD: string = 'CallSendMsg' const MSG_SEND_METHOD: string = 'CallSendMsg'
async onButtonCall() { async onButtonCall() {
...@@ -210,12 +243,12 @@ async onButtonCall() { ...@@ -210,12 +243,12 @@ async onButtonCall() {
let msg = new MySequenceable(1, 'origin_Msg') let msg = new MySequenceable(1, 'origin_Msg')
await this.caller.call(MSG_SEND_METHOD, msg) await this.caller.call(MSG_SEND_METHOD, msg)
} catch (error) { } catch (error) {
Logger.error(TAG, `caller call failed with ${error}`) console.log(`caller call failed with ${error}`)
} }
} }
``` ```
In the following, **CallWithResult** is used to send data **originMsg** to the callee and assign the data processed by the **CallSendMsg** method to **backMsg**. The sample code snippet is as follows: In the following, `CallWithResult` is used to send data `originMsg` to the callee ability and assign the data processed by the `CallSendMsg` method to `backMsg`. The code snippet is as follows:
```ts ```ts
const MSG_SEND_METHOD: string = 'CallSendMsg' const MSG_SEND_METHOD: string = 'CallSendMsg'
originMsg: string = '' originMsg: string = ''
...@@ -224,26 +257,28 @@ async onButtonCallWithResult(originMsg, backMsg) { ...@@ -224,26 +257,28 @@ async onButtonCallWithResult(originMsg, backMsg) {
try { try {
let msg = new MySequenceable(1, originMsg) let msg = new MySequenceable(1, originMsg)
const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg) const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg)
Logger.log(TAG, 'caller callWithResult succeed') console.log('caller callWithResult succeed')
let result = new MySequenceable(0, '') let result = new MySequenceable(0, '')
data.readSequenceable(result) data.readSequenceable(result)
backMsg(result.str) backMsg(result.str)
Logger.log(TAG, `caller result is [${result.num}, ${result.str}]`) console.log(`caller result is [${result.num}, ${result.str}]`)
} catch (error) { } catch (error) {
Logger.error(TAG, `caller callWithResult failed with ${error}`) console.log(`caller callWithResult failed with ${error}`)
} }
} }
``` ```
4. Release the caller interface. **4. Release the `Caller` object.**
When the caller interface is no longer required, call the **release** API to release it. The sample code snippet is as follows: When the `Caller` object is no longer required, use `release()` to release it. The code snippet is as follows:
```ts ```ts
try { releaseCall() {
this.caller.release() try {
this.caller = undefined this.caller.release()
Logger.log(TAG, 'caller release succeed') this.caller = undefined
} catch (error) { console.log('caller release succeed')
Logger.error(TAG, `caller release failed with ${error}`) } catch (error) {
console.log(`caller release failed with ${error}`)
}
} }
``` ```
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application. A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application.
A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message. A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message.
Basic concepts: Basic concepts:
...@@ -49,10 +49,10 @@ The **FormExtension** class also has a member context, that is, the **FormExtens ...@@ -49,10 +49,10 @@ The **FormExtension** class also has a member context, that is, the **FormExtens
**Table 2** FormExtensionContext APIs **Table 2** FormExtensionContext APIs
| API | Description | | API | Description |
| :----------------------------------------------------------- | :------------------------ | | :----------------------------------------------------------- | :----------------------------------------------------------- |
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback\<void>): void | Updates a widget. This API uses an asynchronous callback to return the result. | | startAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void | Starts an ability. This API uses an asynchronous callback to return the result. (This is a system API and cannot be called by third-party applications.)|
| updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise\<void> | Updates a widget. This API uses a promise to return the result.| | startAbility(want: Want): Promise&lt;void&gt; | Starts an ability. This API uses a promise to return the result. (This is a system API and cannot be called by third-party applications.)|
For details about the **FormProvider** APIs, see [FormProvider](../reference/apis/js-apis-formprovider.md). For details about the **FormProvider** APIs, see [FormProvider](../reference/apis/js-apis-formprovider.md).
...@@ -86,7 +86,7 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ...@@ -86,7 +86,7 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo
export default class FormAbility extends FormExtension { export default class FormAbility extends FormExtension {
onCreate(want) { onCreate(want) {
console.log('FormAbility onCreate'); console.log('FormAbility onCreate');
// Persistently store widget information for subsequent use, such as during widget instance retrieval or update. // Persistently store widget information for subsequent use, such as widget instance retrieval or update.
let obj = { let obj = {
"title": "titleOnCreate", "title": "titleOnCreate",
"detail": "detailOnCreate" "detail": "detailOnCreate"
...@@ -176,8 +176,8 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ...@@ -176,8 +176,8 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo
| supportDimensions | Grid styles supported by the widget. Available values are as follows:<br>**1 * 2**: indicates a grid with one row and two columns.<br>**2 * 2**: indicates a grid with two rows and two columns.<br>**2 * 4**: indicates a grid with two rows and four columns.<br>**4 * 4**: indicates a grid with four rows and four columns.| String array| No | | supportDimensions | Grid styles supported by the widget. Available values are as follows:<br>**1 * 2**: indicates a grid with one row and two columns.<br>**2 * 2**: indicates a grid with two rows and two columns.<br>**2 * 4**: indicates a grid with two rows and four columns.<br>**4 * 4**: indicates a grid with four rows and four columns.| String array| No |
| defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No |
| updateEnabled | Whether the widget can be updated periodically. Available values are as follows:<br>**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is recommended.<br>**false**: The widget cannot be updated periodically.| Boolean | No | | updateEnabled | Whether the widget can be updated periodically. Available values are as follows:<br>**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is recommended.<br>**false**: The widget cannot be updated periodically.| Boolean | No |
| scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute. | String | Yes (initial value: **0:0**) | | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.<br>This parameter has a lower priority than **updateDuration**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) |
| updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.| Number | Yes (initial value: **0**) | | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.<br>This parameter has a higher priority than **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) |
| formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) |
| formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) |
| metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) | | metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) |
...@@ -200,7 +200,6 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ...@@ -200,7 +200,6 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo
"defaultDimension": "2*2", "defaultDimension": "2*2",
"updateEnabled": true, "updateEnabled": true,
"scheduledUpdateTime": "10:30", "scheduledUpdateTime": "10:30",
"updateDuration": 1,
"formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility" "formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility"
}] }]
} }
...@@ -218,8 +217,8 @@ Mostly, the widget provider is started only when it needs to obtain information ...@@ -218,8 +217,8 @@ Mostly, the widget provider is started only when it needs to obtain information
let formId = want.parameters["ohos.extra.param.key.form_identity"]; let formId = want.parameters["ohos.extra.param.key.form_identity"];
let formName = want.parameters["ohos.extra.param.key.form_name"]; let formName = want.parameters["ohos.extra.param.key.form_name"];
let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];
// Persistently store widget data for subsequent use, such as widget instance retrieval and update. // Persistently store widget data for subsequent use, such as widget instance retrieval or update.
// The storeFormInfo API is not implemented here. For details about the implementation, see "Samples" below. // The storeFormInfo API is not implemented here.
storeFormInfo(formId, formName, tempFlag, want); storeFormInfo(formId, formName, tempFlag, want);
let obj = { let obj = {
...@@ -238,7 +237,7 @@ You should override **onDestroy** to delete widget data. ...@@ -238,7 +237,7 @@ You should override **onDestroy** to delete widget data.
console.log('FormAbility onDestroy'); console.log('FormAbility onDestroy');
// You need to implement the code for deleting the persistent widget data. // You need to implement the code for deleting the persistent widget data.
// The deleteFormInfo API is not implemented here. For details about the implementation, see "Samples" below. // The deleteFormInfo API is not implemented here.
deleteFormInfo(formId); deleteFormInfo(formId);
} }
``` ```
...@@ -277,10 +276,11 @@ onUpdate(formId) { ...@@ -277,10 +276,11 @@ onUpdate(formId) {
You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget. You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE** > **NOTE**
>
> Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI. > Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI.
- hml: - In the HML file:
```html ```html
<div class="container"> <div class="container">
<stack> <stack>
...@@ -295,7 +295,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme ...@@ -295,7 +295,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
</div> </div>
``` ```
- css: - In the CSS file:
```css ```css
.container { .container {
...@@ -336,7 +336,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme ...@@ -336,7 +336,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
} }
``` ```
- json: - In the JSON file:
```json ```json
{ {
"data": { "data": {
...@@ -346,7 +346,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme ...@@ -346,7 +346,7 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
"actions": { "actions": {
"routerEvent": { "routerEvent": {
"action": "router", "action": "router",
"abilityName": "com.example.MyApplication.hmservice.FormAbility", "abilityName": "MainAbility",
"params": { "params": {
"message": "add detail" "message": "add detail"
} }
...@@ -358,3 +358,58 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme ...@@ -358,3 +358,58 @@ You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programme
Now you've got a widget shown below. Now you've got a widget shown below.
![fa-form-example](figures/fa-form-example.png) ![fa-form-example](figures/fa-form-example.png)
### Developing Widget Events
You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows:
1. Set **onclick** in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file.
2. For the router event, set the following attributes:
- **action**: **"router"**.
- **abilityName**: target ability name, for example, **MainAbility**, which is the default main ability name in DevEco Studio for the stage model.
- **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field.
3. For the message event, set the following attributes:
- **action**: **"message"**.
- **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**.
The following is an example:
- In the HML file:
```html
<div class="container">
<stack>
<div class="container-img">
<image src="/common/widget.png" class="bg-img"></image>
</div>
<div class="container-inner">
<text class="title" onclick="routerEvent">{{title}}</text>
<text class="detail_text" onclick="messageEvent">{{detail}}</text>
</div>
</stack>
</div>
```
- In the JSON file:
```json
{
"data": {
"title": "TitleDefault",
"detail": "TextDefault"
},
"actions": {
"routerEvent": {
"action": "router",
"abilityName": "MainAbility",
"params": {
"message": "add detail"
}
},
"messageEvent": {
"action": "message",
"params": {
"message": "add detail"
}
}
}
}
```
\ No newline at end of file
# Service Extension Ability Development # Service Extension Ability Development
## When to Use ## When to Use
**ExtensionAbility** is the base class of the new Extension component in the stage model. It is used to process missions without UIs. The lifecycle of an Extension ability is simple and does not involve foreground or background states. **ServiceExtensionAbility** is extended from **ExtensionAbility**. `ExtensionAbility` is the base class of the new Extension component in the stage model. It is used to process missions without UIs. The lifecycle of an Extension ability is simple and does not involve foreground or background states. `ServiceExtensionAbility` is extended from `ExtensionAbility`.
You can customize a class that inherits from **ServiceExtensionAbility** and override the lifecycle callbacks in the base class to perform service logic operations during the initialization, connection, and disconnection processes. You can customize a class that inherits from `ServiceExtensionAbility` and override the lifecycle callbacks in the base class to perform service logic operations during the initialization, connection, and disconnection processes.
## Available APIs ## Available APIs
**Table 1** ServiceExtensionAbility lifecycle APIs **Table 1** ServiceExtensionAbility lifecycle APIs
|API|Description| |API|Description|
|:------|:------| |:------|:------|
|onCreate(want: Want): void|Called for the initialization when **startAbility** or **connectAbility** is invoked for a given ability for the first time.| |onCreate(want: Want): void|Called for the initialization when `startAbility` or `connectAbility` is invoked for a given ability for the first time.|
|onRequest(want: Want, startId: number): void|Called each time **startAbility** is invoked for a given ability. The initial value of **startId** is **1**, and the value is incremented by one each time **startAbility** is invoked for that ability.| |onRequest(want: Want, startId: number): void|Called each time `startAbility` is invoked for a given ability. The initial value of `startId` is `1`, and the value is incremented by one each time `startAbility` is invoked for that ability.|
|onConnect(want: Want): rpc.RemoteObject|Called when **connectAbility** is invoked for a given ability. This callback is not invoked for repeated calling of **connectAbility** for a specific ability. However, it will be invoked unless **connectAbility** is called after the ability has been disconnected using **disconnectAbility**. The returned result is a **RemoteObject**.| |onConnect(want: Want): rpc.RemoteObject|Called when `connectAbility` is invoked for a given ability. This callback is not invoked for repeated calling of `connectAbility` for a specific ability. However, it will be invoked unless `connectAbility` is called after the ability has been disconnected using `disconnectAbility`. The returned result is a `RemoteObject`.|
|onDisconnect(want: Want): void|Called when **disconnectAbility** is called for a given ability. If the Extension ability is started by **connectAbility** and is not bound to other applications, the **onDestroy** callback will also be triggered to destroy the Extension ability.| |onDisconnect(want: Want): void|Called when `disconnectAbility` is called for a given ability. If the Extension ability is started by `connectAbility` and is not bound to other applications, the `onDestroy` callback will also be triggered to destroy the Extension ability.|
|onDestroy(): void|Called when **terminateSelf** is invoked to terminate the ability.| |onDestroy(): void|Called when `terminateSelf` is invoked to terminate the ability.|
## Constraints ## Constraints
...@@ -24,7 +24,7 @@ OpenHarmony does not support creation of a Service Extension ability for third-p ...@@ -24,7 +24,7 @@ OpenHarmony does not support creation of a Service Extension ability for third-p
## How to Develop ## How to Develop
1. Declare the Service Extension ability in the **module.json** file by setting its **type** attribute to **service**. The following is a configuration example of the **module.json** file: 1. Declare the Service Extension ability in the `module.json5` file by setting its `type` attribute to `service`. The following is a configuration example of the `module.json5` file:
```json ```json
...@@ -39,7 +39,7 @@ OpenHarmony does not support creation of a Service Extension ability for third-p ...@@ -39,7 +39,7 @@ OpenHarmony does not support creation of a Service Extension ability for third-p
``` ```
2. Customize a class that inherits from **ServiceExtensionAbility** in the .ts file in the directory where the Service Extension ability is defined (**entry\src\main\ets\ServiceExtAbility\ServiceExtAbility.ts** by default) and override the lifecycle callbacks of the base class. The code sample is as follows: 2. Customize a class that inherits from `ServiceExtensionAbility` in the .ts file in the directory where the Service Extension ability is defined (`entry\src\main\ets\ServiceExtAbility\ServiceExtAbility.ts` by default) and override the lifecycle callbacks of the base class. The code sample is as follows:
```js ```js
import ServiceExtensionAbility from '@ohos.application.ServiceExtensionAbility' import ServiceExtensionAbility from '@ohos.application.ServiceExtensionAbility'
......
...@@ -10,6 +10,8 @@ The HTTP request function is mainly implemented by the HTTP module. ...@@ -10,6 +10,8 @@ The HTTP request function is mainly implemented by the HTTP module.
To use related APIs, you must declare the **ohos.permission.INTERNET** permission. To use related APIs, you must declare the **ohos.permission.INTERNET** permission.
For details about how to apply for permissions, see [Access Control Development](../security/accesstoken-guidelines.md).
The following table describes the related APIs. The following table describes the related APIs.
| API | Description | | API | Description |
...@@ -65,7 +67,7 @@ httpRequest.request( ...@@ -65,7 +67,7 @@ httpRequest.request(
console.info('cookies:' + data.cookies); // 8+ console.info('cookies:' + data.cookies); // 8+
} else { } else {
console.info('error:' + JSON.stringify(err)); console.info('error:' + JSON.stringify(err));
// Call the destroy() method to release resources after the call is complete. // Call the destroy() method to destroy the request if it is no longer needed.
httpRequest.destroy(); httpRequest.destroy();
} }
} }
......
...@@ -74,7 +74,7 @@ The implementation is similar for UDPSocket and TCPSocket. The following uses th ...@@ -74,7 +74,7 @@ The implementation is similar for UDPSocket and TCPSocket. The following uses th
console.log("on close") console.log("on close")
}); });
// Bind the IP address and port number. // Bind the local IP address and port number.
let bindAddress = { let bindAddress = {
address: '192.168.xx.xx', address: '192.168.xx.xx',
port: 1234, // Bound port, for example, 1234. port: 1234, // Bound port, for example, 1234.
......
...@@ -13,7 +13,7 @@ The **DataShare** module allows an application to manage its own data and share ...@@ -13,7 +13,7 @@ The **DataShare** module allows an application to manage its own data and share
|query?(uri: string, predicates: DataSharePredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;Object&gt;): void|Queries data from the database.| |query?(uri: string, predicates: DataSharePredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;Object&gt;): void|Queries data from the database.|
|delete?(uri: string, predicates: DataSharePredicates, callback: AsyncCallback&lt;number&gt;): void|Deletes data from the database.| |delete?(uri: string, predicates: DataSharePredicates, callback: AsyncCallback&lt;number&gt;): void|Deletes data from the database.|
For more details, see [DataShareExtensionAbility](../reference/apis/js-apis-application-DataShareExtensionAbility.md). For more information, see [DataShareExtensionAbility](../reference/apis/js-apis-application-DataShareExtensionAbility.md).
**Table 2** APIs of the data consumer **Table 2** APIs of the data consumer
...@@ -25,11 +25,11 @@ For more details, see [DataShareExtensionAbility](../reference/apis/js-apis-appl ...@@ -25,11 +25,11 @@ For more details, see [DataShareExtensionAbility](../reference/apis/js-apis-appl
| query(uri: string, predicates: DataSharePredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;DataShareResultSet&gt;): void | Queries data from the database. | | query(uri: string, predicates: DataSharePredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;DataShareResultSet&gt;): void | Queries data from the database. |
| delete(uri: string, predicates: DataSharePredicates, callback: AsyncCallback&lt;number&gt;): void | Deletes one or more data records from the database.| | delete(uri: string, predicates: DataSharePredicates, callback: AsyncCallback&lt;number&gt;): void | Deletes one or more data records from the database.|
For more details, see [DataShareHelper](../reference/apis/js-apis-data-dataShare.md). For more information, see [DataShareHelper](../reference/apis/js-apis-data-dataShare.md).
## When to Use ## When to Use
There are two roles in **DataShare**. There are two roles in **DataShare**:
- Data provider: adds, deletes, modifies, and queries data, opens files, and shares data. - Data provider: adds, deletes, modifies, and queries data, opens files, and shares data.
- Data consumer: accesses the data provided by the provider using **DataShareHelper**. - Data consumer: accesses the data provided by the provider using **DataShareHelper**.
...@@ -41,10 +41,10 @@ Examples are given below. ...@@ -41,10 +41,10 @@ Examples are given below.
1. Import the dependencies. 1. Import the dependencies.
```ts ```ts
import Extension from '@ohos.application.DataShareExtensionAbility' import Extension from '@ohos.application.DataShareExtensionAbility';
import rdb from '@ohos.data.rdb'; import rdb from '@ohos.data.rdb';
import fileIo from '@ohos.fileio' import fileIo from '@ohos.fileio';
import dataSharePredicates from '@ohos.data.dataSharePredicates' import dataSharePredicates from '@ohos.data.dataSharePredicates';
``` ```
2. Override **DataShareExtensionAbility** APIs based on actual requirements. For example, if the data provider provides only data query, override only the **query()** API. 2. Override **DataShareExtensionAbility** APIs based on actual requirements. For example, if the data provider provides only data query, override only the **query()** API.
...@@ -80,7 +80,7 @@ Examples are given below. ...@@ -80,7 +80,7 @@ Examples are given below.
} }
// Override the query() API. // Override the query() API.
query(uri, predicates, columns, callback) { query(uri, predicates, columns, callback) {
if (predicates == null || predicates == undefined) { if (predicates == null || predicates == undefined) {
console.info('invalid predicates'); console.info('invalid predicates');
} }
...@@ -144,48 +144,49 @@ Examples are given below. ...@@ -144,48 +144,49 @@ Examples are given below.
let dseUri = ("datashare:///com.samples.datasharetest.DataShare"); let dseUri = ("datashare:///com.samples.datasharetest.DataShare");
``` ```
2. Create a **DataShareHelper** instance. 3. Create a **DataShareHelper** instance.
```ts ```ts
let dsHelper; let dsHelper;
let abilityContext; let abilityContext;
export default class MainAbility extends Ability { export default class MainAbility extends Ability {
onWindowStageCreate(windowStage) { onWindowStageCreate(windowStage) {
abilityContext = this.context; abilityContext = this.context;
dataShare.createDataShareHelper(abilityContext, dseUri, (err,data)=>{ dataShare.createDataShareHelper(abilityContext, dseUri, (err, data)=>{
dsHelper = data; dsHelper = data;
}); });
} }
} }
``` ```
3. Use the APIs provided by **DataShareHelper** to access the services provided by the provider, for example, adding, deleting, modifying, and querying data. 4. Use the APIs provided by **DataShareHelper** to access the services provided by the provider, for example, adding, deleting, modifying, and querying data.
```ts ```ts
// Construct a piece of data. // Construct a piece of data.
var valuesBucket = {"name": "ZhangSan", "age": 21, "isStudent": false, "Binary": new Uint8Array([1,2,3])}; var valuesBucket = { "name": "ZhangSan", "age": 21, "isStudent": false, "Binary": new Uint8Array([1, 2, 3]) };
var updateBucket = {"name": "LiSi", "age": 18, "isStudent": true, "Binary": new Uint8Array([1,2,3])}; var updateBucket = { "name": "LiSi", "age": 18, "isStudent": true, "Binary": new Uint8Array([1, 2, 3]) };
let da = new dataSharePredicates.DataSharePredicates(); let da = new dataSharePredicates.DataSharePredicates();
var valArray =new Array("*"); var valArray = new Array("*");
let people = new Array( let people = new Array(
{"name": "LiSi", "age": 41, "Binary": ar}, { "name": "LiSi", "age": 41, "Binary": ar },
{"name": "WangWu", "age": 21, "Binary": arr}, { "name": "WangWu", "age": 21, "Binary": arr },
{"name": "ZhaoLiu", "age": 61, "Binary": arr}); { "name": "ZhaoLiu", "age": 61, "Binary": arr });
// Insert a piece of data. // Insert a piece of data.
dsHelper.insert(dseUri, valuesBucket, (err,data) => { dsHelper.insert(dseUri, valuesBucket, (err, data) => {
console.log("dsHelper insert result: " + data); console.log("dsHelper insert result: " + data);
}); });
// Delete data. // Delete data.
dsHelper.delete(dseUri, da, (err,data) => { dsHelper.delete(dseUri, da, (err, data) => {
console.log("dsHelper delete result: " + data); console.log("dsHelper delete result: " + data);
}); });
// Update data. // Update data.
dsHelper.update(dseUri, da, updateBucket, (err,data) => { dsHelper.update(dseUri, da, updateBucket, (err, data) => {
console.log("dsHelper update result: " + data); console.log("dsHelper update result: " + data);
}); });
// Query data. // Query data.
dsHelper.query(dseUri, da, valArray, (err,data) => { dsHelper.query(dseUri, da, valArray, (err, data) => {
console.log("dsHelper query result: " + data); console.log("dsHelper query result: " + data);
}); });
``` ```
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
## When to Use ## When to Use
Distributed data objects allow data traversing 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 data changes and online and offline status changes of other devices. The **distributedDataObject** module provides APIs to implement data collaboration of the same application across multiple devices. In addition, the devices that form a Super Device can listen for object status and data changes with each other.
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.
For example, when the data of the a distributed data object is added, deleted, or modified for application A on device 1, application A on device 2 can obtain the updated data. In addition, device 2 can listen for data changes and online/offline of the data objects on device 1.
## Available APIs ## Available APIs
For details about the APIs related to the distributed data object, see [Distributed Data Object](../reference/apis/js-apis-data-distributedobject.md). For details about the APIs, see [Distributed Data Object](../reference/apis/js-apis-data-distributedobject.md).
### Creating a Distributed Data Object Instance ### Creating a Distributed Data Object Instance
...@@ -17,7 +16,7 @@ Call **createDistributedObject()** to create a distributed data object instance. ...@@ -17,7 +16,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>- **source**: attributes of the **distributedObject** set.<br>- **DistributedObject**: returns the distributed object created.| | ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>- **source**: attributes of the **distributedObject** set.<br>- **DistributedObject**: returns the distributed object created.|
...@@ -26,35 +25,36 @@ Call **createDistributedObject()** to create a distributed data object instance. ...@@ -26,35 +25,36 @@ Call **createDistributedObject()** to create a distributed data object instance.
Call **genSessionId()** to generate a session ID randomly. The generated session ID can be used to set the session ID of a distributed data object. Call **genSessionId()** to generate a session ID randomly. The generated session ID can be used to set the session ID of a distributed data object.
**Table 2** API for generating a session ID randomly **Table 2** API for generating a session ID randomly
| Package | API | Description | | Package| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.data.distributedDataObject| genSessionId(): string | Generates a session ID, which can be used as the session ID of a distributed data object.| | ohos.data.distributedDataObject| genSessionId(): string | Generates a session ID, which can be used as the session ID of a distributed data object.|
### Setting a SessionID for Distributed Data Objects ### Setting a SessionID for a Distributed Data Object
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. 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>**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.| | DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for a distributed data object.<br>**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
Call **on()** to subscribe to data changes of a distributed data object. In the case of data change, a callback will be invoked to return the data changes. You can use **off()** to unsubscribe from the data changes. Call **on()** to subscribe to data changes of a distributed data object. When the data changes, a callback will be invoked to return the data changes. You can use **off()** to unsubscribe from the data changes.
**Table 4** APIs for observing data changes of a distributed data object **Table 4** APIs for observing data changes of a distributed data object
| 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.<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.| | DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Unsubscribes from data changes. **Callback**: specifies the data changes to unsubscribe from. If this parameter is not specified, all data changes of this distributed data object will be unsubscribed from.|
### Observing Online or Offline Status ### Observing Online or Offline Status
Call **on()** to subscribe to status changes of a distributed data object. The status can be online or offline. When the status changes, a callback will be invoked to return the status. You can use **off()** to unsubscribe from the status changes. Call **on()** to subscribe to status changes of a distributed data object. The status can be online or offline. When the status changes, a callback will be invoked to return the status. You can use **off()** to unsubscribe from the status changes.
**Table 5** APIs for observing status changes of a distributed data object **Table 5** APIs for observing status changes of a distributed data object
| Class | API | Description | | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to the status changes of a distributed data object.| | DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to the status changes of a distributed data object.|
| DistributedDataObject| off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' \| 'offline' }>): void | Unsubscribes from status changes of a distributed data object.| | DistributedDataObject| off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' \| 'offline' }>): void | Unsubscribes from status changes of a distributed data object.|
...@@ -63,7 +63,7 @@ Call **on()** to subscribe to status changes of a distributed data object. The s ...@@ -63,7 +63,7 @@ Call **on()** to subscribe to status changes of a distributed data object. The s
Call **save()** to save a distributed data object. When the application is active, the saved data will not be released. When the application exits and restarts, the data saved on the device will be restored. Call **save()** to save a distributed data object. When the application is active, the saved data will not be released. When the application exits and restarts, the data saved on the device will be restored.
Call **revokeSave()** to revoke a distributed data object that is no longer required. If the distributed data object is saved on the local device, **revokeSave()** will delete the data from all trusted devices. If the distributed data object is not saved on the local device, **revokeSave()** will delete the data from the local device. Call **revokeSave()** to delete a distributed data object that is no longer required. If the distributed data object is saved on the local device, **revokeSave()** will delete the data from all trusted devices. If the distributed data object is not saved on the local device, **revokeSave()** will delete the data from the local device.
The saved data will be released in the following cases: The saved data will be released in the following cases:
...@@ -71,13 +71,11 @@ The saved data will be released in the following cases: ...@@ -71,13 +71,11 @@ The saved data will be released in the following cases:
- The application has been uninstalled. - The application has been uninstalled.
- Data is successfully restored. - Data is successfully restored.
**Table 6** APIs for saving a distributed data object and revoking the saving **Table 6** APIs for saving a distributed data object and revoking the saving operation
| Class | API | Description | | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject | save(deviceId: string): Promise&lt;SaveSuccessResponse&gt; | Saves a distributed data object. This API uses a promise to return the result. | | DistributedDataObject | save(deviceId: string): Promise&lt;SaveSuccessResponse&gt; | Saves a distributed data object.|
| DistributedDataObject | save(deviceId: string, callback: AsyncCallback&lt;SaveSuccessResponse&gt;): void | Saves a distributed data object. This API uses an asynchronous callback to return the result. | | DistributedDataObject| revokeSave(): Promise&lt;RevokeSaveSuccessResponse&gt; | Revokes the data saving operation.|
| DistributedDataObject | revokeSave(callback: AsyncCallback&lt;RevokeSaveSuccessResponse&gt;): void | Revokes the data saving operation. This API uses an asynchronous callback to return the result. |
| DistributedDataObject | revokeSave(): Promise&lt;RevokeSaveSuccessResponse&gt; | Revokes the data saving operation. This API uses a promise to return the result. |
## How to Develop ## How to Develop
...@@ -89,12 +87,14 @@ The following example shows how to implement distributed data object synchroniza ...@@ -89,12 +87,14 @@ The following example shows how to implement distributed data object synchroniza
import distributedObject from '@ohos.data.distributedDataObject'; import distributedObject from '@ohos.data.distributedDataObject';
``` ```
2. Request the permission. 2. Apply for the permission.
Add the required permission (FA model) in the **config.json** file.
The sample code is as follows:
Add the required permission in the **config.json** file. The sample code is as follows: ```json
{
```
{
"module": { "module": {
"reqPermissions": [ "reqPermissions": [
{ {
...@@ -103,106 +103,125 @@ The following example shows how to implement distributed data object synchroniza ...@@ -103,106 +103,125 @@ The following example shows how to implement distributed data object synchroniza
] ]
} }
} }
``` ```
This permission must also be authorized by the user through a dialog box when the application is started for the first time. The sample code is as follows:
For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model).
```
This permission must also be granted by the user when the application is started for the first time. The sample code is as follows:
```json
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility';
function grantPermission() { function grantPermission() {
console.info('grantPermission'); console.info('grantPermission');
let context = featureAbility.getContext(); let context = featureAbility.getContext();
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) {
console.info(`result.requestCode=${result.requestCode}`) console.info(`result.requestCode=${result.requestCode}`)
}) })
console.info('end grantPermission'); console.info('end grantPermission');
} }
grantPermission();
``` grantPermission();
```
3. Obtain a distributed data object instance. 3. Obtain a distributed data object instance.
The sample code is as follows: The sample code is as follows:
```js ```js
var local_object = distributedObject.createDistributedObject({name:undefined, age:undefined, isVis:true, var local_object = distributedObject.createDistributedObject({
parent:undefined, list:undefined}); name: undefined,
age: undefined,
isVis: true,
parent: undefined,
list: undefined
});
var sessionId = distributedObject.genSessionId(); var sessionId = distributedObject.genSessionId();
``` ```
4. Add the distributed data object instance to the synchronization network.
4. Add the synchronization network. The data objects in the synchronization network include the local and remote objects.
The sample code is as follows: The data objects in the synchronization network include the local and remote objects.
The sample code is as follows:
```js ```js
// Local object // Local object
var local_object = distributedObject.createDistributedObject({name:"jack", age:18, isVis:true, var local_object = distributedObject.createDistributedObject({
parent:{mother:"jack mom", father:"jack Dad"}, list:[{mother:"jack mom"}, {father:"jack Dad"}]}); name: "jack",
age: 18,
isVis: true,
parent: { mother: "jack mom", father: "jack Dad" },
list: [{ mother: "jack mom" }, { father: "jack Dad" }]
});
local_object.setSessionId(sessionId); local_object.setSessionId(sessionId);
// Remote object // Remote object
var remote_object = distributedObject.createDistributedObject({name:undefined, age:undefined, isVis:true, var remote_object = distributedObject.createDistributedObject({
parent:undefined, list:undefined}); name: undefined,
remote_object.setSessionId(sessionId); age: undefined,
isVis: true,
parent: undefined,
list: undefined
});
// After learning that the device 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.
remote_object.setSessionId(sessionId);
``` ```
5. Observe the data changes of the distributed data object. 5. Observe the data changes of the distributed data object.
You can subscribe to data changes of the peer object. When the data in the peer object changes, a callback will be called to return the data changes. 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:
```js ```js
function changeCallback(sessionId, changeData) { function changeCallback(sessionId, changeData) {
console.info("change" + sessionId); console.info("change" + sessionId);
if (changeData != null && changeData != undefined) { if (changeData != null && changeData != undefined) {
changeData.forEach(element => { changeData.forEach(element => {
console.info("changed !" + element + " " + local_object[element]); console.info("changed !" + element + " " + local_object[element]);
}); });
} }
} }
// To refresh the page in changeCallback, correctly bind (this) to the changeCallback. // To refresh the page in changeCallback, correctly bind (this) to the changeCallback.
local_object.on("change", this.changeCallback.bind(this)); local_object.on("change", this.changeCallback.bind(this));
``` ```
6. Modify object attributes. 6. Modify attributes of the distributed data object.
The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types). The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types).
The sample code is as follows: The sample code is as follows:
```js ```js
local_object.name = "jack"; local_object.name = "jack";
local_object.age = 19; local_object.age = 19;
local_object.isVis = false; local_object.isVis = false;
local_object.parent = {mother:"jack mom", father:"jack Dad"}; local_object.parent = { mother: "jack mom", father: "jack Dad" };
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** > **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.
local_object.parent = {mother:"mom", father:"dad"}; local_object.parent = { mother: "mom", father: "dad" };
// Modification not supported. // Modification not supported.
local_object.parent.mother = "mom"; local_object.parent.mother = "mom";
``` ```
7. Access the distributed data object. 7. Access the distributed data object.
Obtain the distributed data object attribute, which is the latest data on the network. Obtain the distributed data object attributes, which are the latest data on the network.
The sample code is as follows: The sample code is as follows:
```js ```js
console.info("name " + local_object["name"]); console.info("name " + local_object["name"]);
``` ```
...@@ -221,7 +240,6 @@ The following example shows how to implement distributed data object synchroniza ...@@ -221,7 +240,6 @@ The following example shows how to implement distributed data object synchroniza
``` ```
9. Subscribe to the status (online/offline) changes of the distributed data object. A callback will be invoked to report the status change when the target distributed data object goes online or offline. 9. Subscribe to the status (online/offline) changes of the distributed data object. A callback will be invoked to report the status change when the target distributed data object goes online or offline.
The sample code is as follows: The sample code is as follows:
```js ```js
...@@ -234,53 +252,29 @@ The following example shows how to implement distributed data object synchroniza ...@@ -234,53 +252,29 @@ The following example shows how to implement distributed data object synchroniza
10. Save a distributed data object and revoke the data saving operation. 10. Save a distributed data object and revoke the data saving operation.
- Callback ```js
// Save a distributed data object.
``` g_object.save("local").then((result) => {
​```js console.info("save sessionId " + result.sessionId);
// Save a distributed data object. console.info("save version " + result.version);
local_object.save("local", (result, data) => { console.info("save deviceId " + result.deviceId);
console.log("save callback"); }, (result) => {
console.info("save sessionId " + data.sessionId); console.info("save local failed.");
console.info("save version " + data.version); });
console.info("save deviceId " + data.deviceId); // Revoke the data saving operation.
}); g_object.revokeSave().then((result) => {
// Revoke the data saving operation. console.info("revokeSave success.");
local_object.revokeSave((result, data) => { }, (result) => {
console.log("revokeSave callback"); console.info("revokeSave failed.");
console.info("revokeSave sessionId " + data.sessionId); });
}); ```
​```
```
- Promise
```
​```js
// Save a distributed data object.
g_object.save("local").then((result) => {
console.info("save sessionId " + result.sessionId);
console.info("save version " + result.version);
console.info("save deviceId " + result.deviceId);
}, (result)=>{
console.info("save local failed.");
});
// Revoke the data saving operation.
g_object.revokeSave().then((result) => {
console.info("revokeSave success.");
}, (result)=>{
console.info("revokeSave failed.");
});
​```
```
11. Unsubscribe from the status changes of the distributed data object. 11. Unsubscribe from the status changes of the distributed data object.
You can specify the callback to unregister. If you do not specify the callback, this API unregisters all callbacks of this distributed data object. You can specify the callback to unregister. If you do not specify the callback, this API unregisters all status change callbacks of this distributed data object.
The sample code is as follows: The sample code is as follows:
```js ```js
// Unregister the specified status change callback. // Unregister the specified status change callback.
local_object.off("status", this.statusCallback); local_object.off("status", this.statusCallback);
...@@ -288,9 +282,12 @@ The following example shows how to implement distributed data object synchroniza ...@@ -288,9 +282,12 @@ The following example shows how to implement distributed data object synchroniza
local_object.off("status"); local_object.off("status");
``` ```
12. Remove a distributed data object from the synchronization network. Data changes on the local object will not be synchronized to the removed distributed data object. 12. Remove a distributed data object from the synchronization network.
The sample code is as follows: Data changes on the local object will not be synchronized to the removed distributed data object.
```js
local_object.setSessionId(""); The sample code is as follows:
```
```js
local_object.setSessionId("");
```
# Distributed Data Object Overview # Distributed Data Object Overview
The distributed data object management framework is an object-oriented in-memory data management framework. It provides application developers with basic data object management capabilities, such as creating, querying, deleting, modifying, and subscribing to in-memory objects. This management framework also provides distributed capabilities to implement data object collaboration for the same application between multiple devices that form a Super Device. The distributed data object management framework provides object-oriented in-memory data management. It provides basic data management capabilities, such as creating, querying, deleting, and modifying distributed data objects, and observing data and status changes of the distributed data objects. This management framework also provides distributed capabilities to implement data object collaboration for the same application between multiple devices that form a Super Device.
## Key Concepts ## Basic Concepts
- **Distributed in-memory database** - **Distributed in-memory database**
The distributed in-memory database caches data in the memory, so that applications can quickly access data. This database, however, does not store data persistently. If the database is closed, the data is not retained. The distributed in-memory database caches data in the memory so that applications can quickly access data. This database, however, does not store data persistently. If the database is closed, the data is not retained.
- **Distributed data object** - **Distributed data object**
A distributed data object is an encapsulation of the JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading or assigning values to distributed data objects is automatically mapped to the **put** or **get** operation of the corresponding database. A distributed data object is an encapsulation of the JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading data from and writing data to a distributed data object are mapped to the **put** and **get** operations in the corresponding database, respectively.
The distributed data object can be in the following states in its lifecycle: The distributed data object can be in the following states in its lifecycle:
- **Uninitialized**: The distributed data object is not instantiated or has been destroyed. - **Uninitialized**: The distributed data object is not instantiated or has been destroyed.
- **Local**: The data table is created, but the data cannot be synchronized. - **Local**: The data table is created, but the data cannot be synchronized.
- **Distributed**: The data table is created, there are at least two online with the same session ID, and data can be synchronized across devices. If the device is offline or the session ID is empty, the distributed data object changes to the local state. - **Distributed**: The data table is created, and there are at least two online devices with the same session ID. In this case, data can be synchronized across devices. If a device is offline or the session ID is empty, the distributed data object changes to the local state.
## Working Principles ## Working Principles
The distributed data objects are encapsulated into JS objects in distributed in-memory databases, which allows the distributed data objects to be operated in the same way as local variables. The system automatically implements cross-device data synchronization. The distributed data objects are encapsulated into JS objects in distributed in-memory databases. This allows the distributed data objects to be operated in the same way as local variables. The system automatically implements cross-device data synchronization.
**Figure 1** Working mechanism **Figure 1** Working mechanism
...@@ -34,7 +34,7 @@ The distributed data objects are encapsulated into JS objects in distributed in- ...@@ -34,7 +34,7 @@ The distributed data objects are encapsulated into JS objects in distributed in-
## Constraints ## Constraints
- Data synchronization can be implemented across devices only for the applications with the same bundleName. - Data synchronization can be implemented across devices only for the applications with the same **bundleName**.
- Each distributed data object occupies 100 KB to 150 KB of memory. Therefore, you are advised not to create too many distributed data objects. - Each distributed data object occupies 100 KB to 150 KB of memory. Therefore, you are advised not to create too many distributed data objects.
......
...@@ -6,113 +6,144 @@ The Distributed Data Service (DDS) implements synchronization of application dat ...@@ -6,113 +6,144 @@ The Distributed Data Service (DDS) implements synchronization of application dat
## Available APIs ## Available APIs
For details about the APIs related to distributed data, see [Distributed Data Management](../reference/apis/js-apis-distributed-data.md). For details about the APIs, see [Distributed Data Management](../reference/apis/js-apis-distributed-data.md).
**Table 1** APIs provided by the DDS **Table 1** APIs provided by the DDS
| API | Description | | API | Description |
| ------------------------------------------------------------ | ----------------------------------------------- | | ------------------------------------------------------------ | ----------------------------------------------- |
| createKVManager(config:KVManagerConfig,callback:AsyncCallback&lt;KVManager&gt;):void<br>createKVManager(config:KVManagerConfig):Promise&lt;KVManager> | Creates a **KVManager** object for database management.| | createKVManager(config: KVManagerConfig, callback: AsyncCallback&lt;KVManager&gt;): void<br>createKVManager(config: KVManagerConfig): Promise&lt;KVManager> | Creates a **KVManager** object for database management.|
| getKVStore&lt;TextendsKVStore&gt;(storeId:string,options:Options,callback:AsyncCallback&lt;T&gt;):void<br>getKVStore&lt;TextendsKVStore&gt;(storeId:string,options:Options):Promise&lt;T&gt; | Obtains a KV store with the specified **Options** and **storeId**.| | getKVStore&lt;TextendsKVStore&gt;(storeId: string, options: Options, callback: AsyncCallback&lt;T&gt;): void<br>getKVStore&lt;TextendsKVStore&gt;(storeId: string, options: Options): Promise&lt;T&gt; | Obtains a KV store with the specified **Options** and **storeId**.|
| put(key:string,value:Uint8Array\|string\|number\|boolean,callback:AsyncCallback&lt;void&gt;):void<br>put(key:string,value:Uint8Array\|string\|number\|boolean):Promise&lt;void> | Inserts and updates data. | | put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback&lt;void&gt;): void<br>put(key: string, value: Uint8Array\|string\|number\|boolean): Promise&lt;void> | Inserts and updates data. |
| delete(key:string,callback:AsyncCallback&lt;void&gt;):void<br>delete(key:string):Promise&lt;void> | Deletes data. | | delete(key: string, callback: AsyncCallback&lt;void&gt;): void<br>delete(key: string): Promise&lt;void> | Deletes data. |
| get(key:string,callback:AsyncCallback&lt;Uint8Array\|string\|boolean\|number&gt;):void<br>get(key:string):Promise&lt;Uint8Array\|string\|boolean\|number> | Queries data. | | get(key: string, callback: AsyncCallback&lt;Uint8Array\|string\|boolean\|number&gt;): void<br>get(key: string): Promise&lt;Uint8Array\|string\|boolean\|number> | Queries data. |
| on(event:'dataChange',type:SubscribeType,observer:Callback&lt;ChangeNotification&gt;):void<br>on(event:'syncComplete',syncCallback:Callback&lt;Array&lt;[string,number]&gt;&gt;):void | Subscribes to data changes in the KV store. | | on(event: 'dataChange', type: SubscribeType, observer: Callback&lt;ChangeNotification&gt;): void<br>on(event: 'syncComplete', syncCallback: Callback&lt;Array&lt;[string,number]&gt;&gt;): void | Subscribes to data changes in the KV store. |
| sync(deviceIdList:string[],mode:SyncMode,allowedDelayMs?:number):void | Triggers database synchronization in manual mode. | | sync(deviceIdList: string[], mode: SyncMode, allowedDelayMs?: number): void | Triggers database synchronization in manual mode. |
## How to Develop ## How to Develop
The following uses a single KV store as an example to describe the development procedure. The following uses a single KV store as an example to describe the development procedure.
1. Import the distributed data module. 1. Import the distributed data module.
```js ```js
import distributedData from '@ohos.data.distributedData'; import distributedData from '@ohos.data.distributedData';
``` ```
2. Apply for the required permission if data synchronization is required.
2. Create a **KvManager** instance based on the specified **KvManagerConfig** object. Add the permission required (FA model) in the **config.json** file. The sample code is as follows:
(1) Create a **KvManagerConfig** object based on the application context. ```json
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
}
}
```
For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model).
This permission must also be granted by the user when the application is started for the first time. The sample code is as follows:
```js
import featureAbility from '@ohos.ability.featureAbility';
function grantPermission() {
console.info('grantPermission');
let context = featureAbility.getContext();
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) {
console.info(`result.requestCode=${result.requestCode}`)
})
console.info('end grantPermission');
}
grantPermission();
```
3. Create a **kvManager** instance based on the specified **kvManagerConfig** object.
1. Create a **kvManagerConfig** object based on the application context.
2. Create a **kvManager** instance.
(2) Create a **KvManager** instance.
The sample code is as follows: The sample code is as follows:
``` ```js
let kvManager; let kvManager;
try { try {
const kvManagerConfig = { const kvManagerConfig = {
bundleName : 'com.example.datamanagertest', bundleName: 'com.example.datamanagertest',
userInfo : { userInfo: {
userId : '0', userId: '0',
userType : distributedData.UserType.SAME_USER_ID userType: distributedData.UserType.SAME_USER_ID
}
} }
distributedData.createKVManager(kvManagerConfig, function (err, manager) { }
if (err) { distributedData.createKVManager(kvManagerConfig, function (err, manager) {
console.log("createKVManager err: " + JSON.stringify(err)); if (err) {
return; console.log("createKVManager err: " + JSON.stringify(err));
} return;
console.log("createKVManager success"); }
kvManager = manager; console.log("createKVManager success");
}); kvManager = manager;
});
} catch (e) { } catch (e) {
console.log("An unexpected error occurred. Error:" + e); console.log("An unexpected error occurred. Error: " + e);
} }
``` ```
3. Create and obtain a single KV store.
(1) Declare the ID of the single KV store to create. 4. Create and obtain a single KV store.
(2) Create a single KV store. You are advised to disable automatic synchronization (**autoSync:false**) and call **sync** when a synchronization is required. 1. Declare the ID of the single KV store to create.
2. Create a single KV store. You are advised to disable automatic synchronization (`autoSync:false`) and call `sync` when a synchronization is required.
The sample code is as follows: The sample code is as follows:
```js ```js
let kvStore; let kvStore;
try { try {
const options = { const options = {
createIfMissing : true, createIfMissing: true,
encrypt : false, encrypt: false,
backup : false, backup: false,
autoSync : false, autoSync: false,
kvStoreType : distributedData.KVStoreType.SINGLE_VERSION, kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
securityLevel : distributedData.SecurityLevel.S0, securityLevel: distributedData.SecurityLevel.S0
}; };
kvManager.getKVStore('storeId', options, function (err, store) { kvManager.getKVStore('storeId', options, function (err, store) {
if (err) { if (err) {
console.log("getKVStore err: " + JSON.stringify(err)); console.log("getKVStore err: " + JSON.stringify(err));
return; return;
} }
console.log("getKVStore success"); console.log("getKVStore success");
kvStore = store; kvStore = store;
}); });
} catch (e) { } catch (e) {
console.log("An unexpected error occurred. Error:" + e); console.log("An unexpected error occurred. Error: " + e);
} }
``` ```
> **NOTE** > **NOTE**<br>
> >
> For data synchronization between networked devices, you are advised to open the distributed KV store during application startup to obtain the database handle. With this database handle (`kvStore` in this example), you can perform operations, such as inserting data into the KV store, without creating the KV store repeatedly during the lifecycle of the handle. > For data synchronization between networked devices, you are advised to open the distributed KV store during application startup to obtain the database handle. With this database handle (`kvStore` in this example), you can perform operations, such as inserting data into the KV store, without creating the KV store repeatedly during the lifecycle of the handle.
5. Subscribe to changes in the distributed data.
4. Subscribe to changes in the distributed data.<br/>
The following is the sample code for subscribing to the data changes of a single KV store: The following is the sample code for subscribing to the data changes of a single KV store:
```js ```js
kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, function (data) { kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, function (data) {
console.log("dataChange callback call data: " + JSON.stringify(data)); console.log("dataChange callback call data: " + JSON.stringify(data));
}); });
``` ```
5. Write data to the single KV store. 6. Write data to the single KV store.
(1) Construct the key and value to be written into the single KV store.
(2) Write key-value pairs into the single KV store. 1. Construct the `Key` and `Value` to be written into the single KV store.
2. Write key-value pairs into the single KV store.
The following is the sample code for writing key-value pairs of the string type into the single KV store: The following is the sample code for writing key-value pairs of the string type into the single KV store:
...@@ -120,52 +151,54 @@ The following uses a single KV store as an example to describe the development p ...@@ -120,52 +151,54 @@ The following uses a single KV store as an example to describe the development p
const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const KEY_TEST_STRING_ELEMENT = 'key_test_string';
const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; const VALUE_TEST_STRING_ELEMENT = 'value-test-string';
try { try {
kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err, data) {
if (err != undefined) { if (err != undefined) {
console.log("put err: " + JSON.stringify(err)); console.log("put err: " + JSON.stringify(err));
return; return;
} }
console.log("put success"); console.log("put success");
}); });
}catch (e) { } catch (e) {
console.log("An unexpected error occurred. Error:" + e); console.log("An unexpected error occurred. Error: " + e);
} }
``` ```
6. Query data in the single KV store. 7. Query data in the single KV store.
(1) Construct the key to be queried from the single KV store.
(2) Query data from the single KV store. 1. Construct the `Key` to be queried from the single KV store.
2. Query data from the single KV store.
The following is the sample code for querying data of the string type from the single KV store: The following is the sample code for querying data of the string type from the single KV store:
```js ```js
const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const KEY_TEST_STRING_ELEMENT = 'key_test_string';
const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; const VALUE_TEST_STRING_ELEMENT = 'value-test-string';
try { try {
kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err, data) {
if (err != undefined) { if (err != undefined) {
console.log("put err: " + JSON.stringify(err)); console.log("put err: " + JSON.stringify(err));
return; return;
} }
console.log("put success"); console.log("put success");
kvStore.get(KEY_TEST_STRING_ELEMENT, function (err,data) { kvStore.get(KEY_TEST_STRING_ELEMENT, function (err, data) {
console.log("get success data: " + data); console.log("get success data: " + data);
}); });
}); });
}catch (e) { } catch (e) {
console.log("An unexpected error occurred. Error:" + e); console.log("An unexpected error occurred. Error: " + e);
} }
``` ```
7. Synchronize data to other devices.<br/> 8. Synchronize data to other devices.
Select the devices in the same network and the synchronization mode to synchronize data. Select the devices in the same network and the synchronization mode to synchronize data.
> **NOTE** > **NOTE**<br>
> >
> The APIs of the `deviceManager` module are system interfaces. > The APIs of the `deviceManager` module are system interfaces.
The following is the example code for synchronizing data in a single KV store:
The following is the sample code for synchronizing data in a single KV store:
```js ```js
import deviceManager from '@ohos.distributedHardware.deviceManager'; import deviceManager from '@ohos.distributedHardware.deviceManager';
...@@ -185,8 +218,8 @@ The following uses a single KV store as an example to describe the development p ...@@ -185,8 +218,8 @@ The following uses a single KV store as an example to describe the development p
try{ try{
// 1000 indicates that the maximum delay is 1000 ms. // 1000 indicates that the maximum delay is 1000 ms.
kvStore.sync(deviceIds, distributedData.SyncMode.PUSH_ONLY, 1000); kvStore.sync(deviceIds, distributedData.SyncMode.PUSH_ONLY, 1000);
}catch (e) { } catch (e) {
console.log("An unexpected error occurred. Error:" + e); console.log("An unexpected error occurred. Error: " + e);
} }
} }
}); });
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> **NOTE** > **NOTE**
> >
> This feature is supported since API Version 9. For the versions earlier than API version 9, use [Lightweight Storage](../reference/apis/js-apis-data-storage.md) APIs. > This feature is supported since API version 9. For the versions earlier than API version 9, use [Lightweight Storage](../reference/apis/js-apis-data-storage.md) APIs.
## When to Use ## When to Use
...@@ -88,8 +88,30 @@ Use the following APIs to delete a **Preferences** instance or data file. ...@@ -88,8 +88,30 @@ Use the following APIs to delete a **Preferences** instance or data file.
2. Obtain a **Preferences** instance. 2. Obtain a **Preferences** instance.
Read the specified file and load its data to the **Preferences** instance for data operations. Read the specified file and load its data to the **Preferences** instance for data operations.
FA model:
```js ```js
let promise = data_preferences.getPreferences(this.context, 'mystore'); // Obtain the context.
import featureAbility from '@ohos.ability.featureAbility'
var context = featureAbility.getContext()
let promise = data_preferences.getPreferences(context, 'mystore');
```
Stage model:
```ts
// Obtain the context.
import Ability from '@ohos.application.Ability'
var context
class MainAbility extends Ability{
onWindowStageCreate(windowStage){
context = this.context
}
}
let promise = data_preferences.getPreferences(context, 'mystore');
``` ```
3. Write data. 3. Write data.
...@@ -115,12 +137,12 @@ Use the following APIs to delete a **Preferences** instance or data file. ...@@ -115,12 +137,12 @@ Use the following APIs to delete a **Preferences** instance or data file.
```js ```js
promise.then((preferences) => { promise.then((preferences) => {
let getPromise = preferences.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("Failed to get the value of 'startup'. Cause: " + err); console.info("Failed to get the value of 'startup'. Cause: " + err);
}) })
}).catch((err) => { }).catch((err) => {
console.info("Failed to get the preferences.") console.info("Failed to get the preferences.")
}); });
...@@ -139,24 +161,24 @@ Use the following APIs to delete a **Preferences** instance or data file. ...@@ -139,24 +161,24 @@ Use the following APIs to delete a **Preferences** instance or data file.
Specify an observer as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and saved by **flush()**, the observer callback will be invoked to return the new data. Specify an observer as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and saved by **flush()**, the observer callback will be invoked to return the new data.
```js ```js
var observer = function (key) { var observer = function (key) {
console.info("The key" + key + " changed."); console.info("The key" + key + " changed.");
} }
preferences.on('change', observer); preferences.on('change', observer);
preferences.put('startup', 'auto', function (err) { preferences.put('startup', 'auto', function (err) {
if (err) { if (err) {
console.info("Failed to put the value of 'startup'. Cause: " + err); console.info("Failed to put the value of 'startup'. Cause: " + err);
return; return;
} }
console.info("Put the value of 'startup' successfully."); console.info("Put the value of 'startup' successfully.");
preferences.flush(function (err) { preferences.flush(function (err) {
if (err) { if (err) {
console.info("Failed to flush data. Cause: " + err); console.info("Failed to flush data. Cause: " + err);
return; return;
} }
console.info("Flushed data successfully."); // The observer will be called. console.info("Flushed data successfully."); // The observer will be called.
}) })
}) })
``` ```
7. Delete the specified file. 7. Delete the specified file.
...@@ -164,10 +186,10 @@ Use the following APIs to delete a **Preferences** instance or data file. ...@@ -164,10 +186,10 @@ Use the following APIs to delete a **Preferences** instance or data file.
Use the **deletePreferences** method to delete the **Preferences** instance and its persistent file and backup and corrupted files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will be caused. The deleted data and files cannot be restored. Use the **deletePreferences** method to delete the **Preferences** instance and its persistent file and backup and corrupted files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will be caused. The deleted data and files cannot be restored.
```js ```js
let proDelete = data_preferences.deletePreferences(context, 'mystore'); let proDelete = data_preferences.deletePreferences(context, 'mystore');
proDelete.then(() => { proDelete.then(() => {
console.info("Deleted data successfully."); console.info("Deleted data successfully.");
}).catch((err) => { }).catch((err) => {
console.info("Failed to delete data. Cause: " + err); console.info("Failed to delete data. Cause: " + err);
}) })
``` ```
...@@ -30,9 +30,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th ...@@ -30,9 +30,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th
**Table 2** API for inserting data **Table 2** API for inserting data
| Class | API | Description | | Class | API | Description |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | insert(table:string,values:ValuesBucket):Promise&lt;number&gt; | Inserts a row of data into a table. This API uses a promise to return the result.<br>If the operation is successful, the row ID will be returned; otherwise, **-1** will be returned.<br>- **table**: name of the target table.<br>- **values**: data to be inserted into the table.| | RdbStore | insert(table: string, values: ValuesBucket): Promise&lt;number&gt; | Inserts a row of data into a table. This API uses a promise to return the result.<br>If the operation is successful, the row ID will be returned; otherwise, **-1** will be returned.<br>- **table**: name of the target table.<br>- **values**: data to be inserted into the table.|
- **Updating Data** - **Updating Data**
...@@ -40,9 +41,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th ...@@ -40,9 +41,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th
**Table 3** API for updating data **Table 3** API for updating data
| Class | API | Description |
| Class | API | Description |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | update(values:ValuesBucket,predicates:RdbPredicates):Promise&lt;number&gt; | Updates data based on the specified **RdbPredicates** object. This API uses a promise to return the result.<br/>- **values**: data to update, which is stored in **ValuesBucket**.<br>- **predicates**: conditions for updating data.<br/>Return value: number of rows updated. | | RdbStore | update(values: ValuesBucket, predicates: RdbPredicates): Promise&lt;number&gt; | Updates data based on the specified **RdbPredicates** object. This API uses a promise to return the result.<br>the number of rows updated.<br>- **values**: data to update, which is stored in **ValuesBucket**.<br>- **predicates**: conditions for updating data.|
- **Deleting Data** - **Deleting Data**
...@@ -50,11 +52,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th ...@@ -50,11 +52,10 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th
**Table 4** API for deleting data **Table 4** API for deleting data
| Class | API | Description |
| -------- | ------------------------------------------------------ | ------------------------------------------------------------ | | Class | API | Description |
| RdbStore | delete(predicates:RdbPredicates):Promise&lt;number&gt; | Deletes data from the RDB store based on the specified **RdbPredicates** object. This API uses a promise to return the result.<br>- **predicates**: conditions for deleting data.<br/>Return value: number of rows updated. | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | delete(predicates: RdbPredicates): Promise&lt;number&gt; | Deletes data from the RDB store based on the specified **RdbPredicates** object. This API uses a promise to return<br>the number of rows updated.<br>- **predicates**: conditions for deleting data.|
- **Querying Data** - **Querying Data**
...@@ -65,10 +66,11 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th ...@@ -65,10 +66,11 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th
**Table 5** APIs for querying data **Table 5** APIs for querying data
| Class | API | Description | | Class | API | Description |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | query(predicates:RdbPredicates,columns?:Array&lt;string&gt;):Promise&lt;ResultSet&gt; | Queries data from the RDB store based on specified conditions. This API uses a promise to return the result.<br>- **predicates**: conditions for querying data.<br>- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| | RdbStore | query(predicates: RdbPredicates, columns?: Array&lt;string&gt;): Promise&lt;ResultSet&gt; | Queries data from the RDB store based on specified conditions. This API uses a promise to return the result.<br>- **predicates**: conditions for querying data.<br>- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.|
| RdbStore | querySql(sql:string,bindArgs?:Array&lt;ValueType&gt;):Promise&lt;ResultSet&gt; | Queries data using the specified SQL statement. This API uses a promise to return the result.<br>- **sql**: SQL statement.<br>- **bindArgs**: arguments in the SQL statement.| | RdbStore | querySql(sql: string, bindArgs?: Array&lt;ValueType&gt;): Promise&lt;ResultSet&gt; | Queries data using the specified SQL statement. This API uses a promise to return the result.<br>- **sql**: SQL statement.<br>- **bindArgs**: arguments in the SQL statement.|
| RdbStore | remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array&lt;string&gt;): Promise&lt;ResultSet&gt; | Queries data from the database of a remote device based on specified conditions. This API uses a promise to return the result.<br>- **device**: network ID of the remote device.<br>- **table**: name of the table to be queried.<br>- **predicates**: **RdbPredicates** that specifies the query condition.<br>- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| | RdbStore | remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array&lt;string&gt;): Promise&lt;ResultSet&gt; | Queries data from the database of a remote device based on specified conditions. This API uses a promise to return the result.<br>- **device**: network ID of the remote device.<br>- **table**: name of the table to be queried.<br>- **predicates**: **RdbPredicates** that specifies the query condition.<br>- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.|
### Using Predicates ### Using Predicates
...@@ -81,11 +83,11 @@ The following lists common predicates. For more information about predicates, se ...@@ -81,11 +83,11 @@ The following lists common predicates. For more information about predicates, se
| Class | API | Description | | Class | API | Description |
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbPredicates | equalTo(field:string,value:ValueType):RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value equal to the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| | RdbPredicates | equalTo(field: string, value: ValueType): RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value equal to the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.|
| RdbPredicates | notEqualTo(field:string,value:ValueType):RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value not equal to the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| | RdbPredicates | notEqualTo(field: string, value: ValueType): RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value not equal to the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.|
| RdbPredicates | or():RdbPredicates | Adds the OR condition to the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** with the OR condition.| | RdbPredicates | or(): RdbPredicates | Adds the OR condition to the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** with the OR condition.|
| RdbPredicates | and():RdbPredicates | Adds the AND condition to the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** with the AND condition.| | RdbPredicates | and(): RdbPredicates | Adds the AND condition to the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** with the AND condition.|
| RdbPredicates | contains(field:string,value:string):RdbPredicates | Sets an **RdbPredicates** to match a string containing the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| | RdbPredicates | contains(field: string, value: string): RdbPredicates | Sets an **RdbPredicates** to match a string containing the specified value.<br>- **field**: column name in the database table.<br>- **value**: value to match the **RdbPredicates**.<br>- **RdbPredicates**: **RdbPredicates** object that matches the specified field.|
### Using the Result Set ### Using the Result Set
...@@ -101,12 +103,12 @@ For details about how to use result set APIs, see [Result Set](../reference/apis ...@@ -101,12 +103,12 @@ For details about how to use result set APIs, see [Result Set](../reference/apis
| Class | API | Description | | Class | API | Description |
| --------- | ---------------------------------------------------- | ------------------------------------------ | | --------- | ---------------------------------------------------- | ------------------------------------------ |
| ResultSet | goToFirstRow():boolean | Moves to the first row of the result set. | | ResultSet | goToFirstRow(): boolean | Moves to the first row of the result set. |
| ResultSet | getString(columnIndex:number):string | Obtains the value in the form of a string based on the specified column and current row. | | ResultSet | getString(columnIndex: number): string | Obtains the value in the form of a string based on the specified column and current row. |
| ResultSet | getBlob(columnIndex:number):Uint8Array | Obtains the value in the form of a byte array based on the specified column and the current row.| | ResultSet | getBlob(columnIndex: number): Uint8Array | Obtains the value in the form of a byte array based on the specified column and the current row.|
| ResultSet | getDouble(columnIndex:number):number | Obtains the value in the form of double based on the specified column and current row. | | ResultSet | getDouble(columnIndex: number): number | Obtains the value in the form of double based on the specified column and current row. |
| ResultSet | getLong(columnIndex:number):number | Obtains the value in the form of a long integer based on the specified column and current row. | | ResultSet | getLong(columnIndex: number): number | Obtains the value in the form of a long integer based on the specified column and current row. |
| ResultSet | close():void | Closes the result set. | | ResultSet | close(): void | Closes the result set. |
...@@ -164,7 +166,7 @@ You can obtain the distributed table name for a remote device based on the local ...@@ -164,7 +166,7 @@ You can obtain the distributed table name for a remote device based on the local
| Class | API | Description | | Class | API | Description |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | backup(destName:string): Promise&lt;void&gt; | Backs up an RDB store. This API uses a promise to return the result.<br>- **destName**: name of the RDB backup file.| | RdbStore | backup(destName: string): Promise&lt;void&gt; | Backs up an RDB store. This API uses a promise to return the result.<br>- **destName**: name of the RDB backup file.|
**Restoring an RDB Store** **Restoring an RDB Store**
...@@ -172,7 +174,7 @@ You can obtain the distributed table name for a remote device based on the local ...@@ -172,7 +174,7 @@ You can obtain the distributed table name for a remote device based on the local
| Class | API | Description | | Class | API | Description |
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| RdbStore | restore(srcName:string): Promise&lt;void&gt; | Restores an RDB store from a backup file. This API uses a promise to return the result.<br>- **srcName**: name of the backup file used to restore the RDB store.| | RdbStore | restore(srcName: string): Promise&lt;void&gt; | Restores an RDB store from a backup file. This API uses a promise to return the result.<br>- **srcName**: name of the backup file used to restore the RDB store.|
**Transaction** **Transaction**
...@@ -180,9 +182,9 @@ Table 15 Transaction APIs ...@@ -180,9 +182,9 @@ Table 15 Transaction APIs
| Class | API | Description | | Class | API | Description |
| -------- | ----------------------- | --------------------------------- | | -------- | ----------------------- | --------------------------------- |
| RdbStore | beginTransaction():void | Starts the transaction before executing SQL statements.| | RdbStore | beginTransaction(): void | Starts the transaction before executing SQL statements.|
| RdbStore | commit():void | Commits the executed SQL statements. | | RdbStore | commit(): void | Commits the executed SQL statements. |
| RdbStore | rollBack():void | Rolls back the SQL statements that have been executed. | | RdbStore | rollBack(): void | Rolls back the SQL statements that have been executed. |
## How to Develop ## How to Develop
...@@ -200,10 +202,10 @@ Table 15 Transaction APIs ...@@ -200,10 +202,10 @@ Table 15 Transaction APIs
import data_rdb from '@ohos.data.rdb' import data_rdb from '@ohos.data.rdb'
const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)";
const STORE_CONFIG = {name: "rdbstore.db"} const STORE_CONFIG = { name: "rdbstore.db" }
data_rdb.getRdbStore(this.context, STORE_CONFIG, 1, function (err, rdbStore) { data_rdb.getRdbStore(this.context, STORE_CONFIG, 1, function (err, rdbStore) {
rdbStore.executeSql(CREATE_TABLE_TEST) rdbStore.executeSql(CREATE_TABLE_TEST)
console.info('create table done.') console.info('create table done.')
}) })
``` ```
...@@ -217,7 +219,7 @@ Table 15 Transaction APIs ...@@ -217,7 +219,7 @@ Table 15 Transaction APIs
```js ```js
var u8 = new Uint8Array([1, 2, 3]) var u8 = new Uint8Array([1, 2, 3])
const valueBucket = {"name": "Tom", "age": 18, "salary": 100.5, "blobType": u8} const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 }
let insertPromise = rdbStore.insert("test", valueBucket) let insertPromise = rdbStore.insert("test", valueBucket)
``` ```
...@@ -316,6 +318,7 @@ Table 15 Transaction APIs ...@@ -316,6 +318,7 @@ Table 15 Transaction APIs
console.log('device=' + device[i] + 'data changed') console.log('device=' + device[i] + 'data changed')
} }
} }
try { try {
rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver) rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver)
} catch (err) { } catch (err) {
...@@ -366,9 +369,7 @@ Table 15 Transaction APIs ...@@ -366,9 +369,7 @@ Table 15 Transaction APIs
(1) Back up the current RDB store. (1) Back up the current RDB store.
(2) Restore the RDB store using the backup file. The sample code is as follows:
The sample code is as follows:
```js ```js
let promiseBackup = rdbStore.backup("dbBackup.db") let promiseBackup = rdbStore.backup("dbBackup.db")
...@@ -378,6 +379,10 @@ Table 15 Transaction APIs ...@@ -378,6 +379,10 @@ Table 15 Transaction APIs
console.info('Backup failed, err: ' + err) console.info('Backup failed, err: ' + err)
}) })
``` ```
(2) Restore the RDB store using the backup file.
The sample code is as follows:
```js ```js
let promiseRestore = rdbStore.restore("dbBackup.db") let promiseRestore = rdbStore.restore("dbBackup.db")
promiseRestore.then(() => { promiseRestore.then(() => {
...@@ -386,4 +391,3 @@ Table 15 Transaction APIs ...@@ -386,4 +391,3 @@ Table 15 Transaction APIs
console.info('Restore failed, err: ' + err) console.info('Restore failed, err: ' + err)
}) })
``` ```
...@@ -4,7 +4,7 @@ With device usage statistics APIs, you can have a better understanding of the ap ...@@ -4,7 +4,7 @@ With device usage statistics APIs, you can have a better understanding of the ap
## Introduction ## Introduction
Currently you can have access to statistics on the application usage, and notification and system usage statistics feature will be available for use in later versions. Currently you can have access to statistics on the application usage, and the notification and system usage statistics feature will be available for use in later versions.
- **The application usage statistics is updated**: - **The application usage statistics is updated**:
1. Every 30 minutes 1. Every 30 minutes
...@@ -21,7 +21,7 @@ Currently you can have access to statistics on the application usage, and notifi ...@@ -21,7 +21,7 @@ Currently you can have access to statistics on the application usage, and notifi
7. Number of FA usage records specified by **maxNum**, sorted by time (most recent first). If **maxNum** is not specified, the default value **1000** will be used. 7. Number of FA usage records specified by **maxNum**, sorted by time (most recent first). If **maxNum** is not specified, the default value **1000** will be used.
8. Number of notifications from applications based on the specified start time and end time 8. Number of notifications from applications based on the specified start time and end time
9. Statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time 9. Statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time
9. Priority group of the invoker application or a specified application 10. Priority group of the invoker application or a specified application
- **The setters can be used to:** - **The setters can be used to:**
......
...@@ -20,7 +20,7 @@ The following table describes APIs available for obtaining device location infor ...@@ -20,7 +20,7 @@ The following table describes APIs available for obtaining device location infor
| off(type: 'locationChange', callback?: Callback&lt;Location&gt;) : void | Unregisters the listener for location changes with the corresponding location request deleted. | | off(type: 'locationChange', callback?: Callback&lt;Location&gt;) : void | Unregisters the listener for location changes with the corresponding location request deleted. |
| on(type: 'locationServiceState', callback: Callback&lt;boolean&gt;) : void | Registers a listener for location service status change events. | | on(type: 'locationServiceState', callback: Callback&lt;boolean&gt;) : void | Registers a listener for location service status change events. |
| off(type: 'locationServiceState', callback: Callback&lt;boolean&gt;) : void | Unregisters the listener for location service status change events. | | off(type: 'locationServiceState', callback: Callback&lt;boolean&gt;) : void | Unregisters the listener for location service status change events. |
| on(type: 'cachedGnssLocationsReporting', request: CachedGnssLoactionsRequest, callback: Callback&lt;Array&lt;Location&gt;&gt;) : void; | Registers a listener for cached GNSS location reports. | | on(type: 'cachedGnssLocationsReporting', request: CachedGnssLocationsRequest, callback: Callback&lt;Array&lt;Location&gt;&gt;) : void; | Registers a listener for cached GNSS location reports. |
| off(type: 'cachedGnssLocationsReporting', callback?: Callback&lt;Array&lt;Location&gt;&gt;) : void; | Unregisters the listener for cached GNSS location reports. | | off(type: 'cachedGnssLocationsReporting', callback?: Callback&lt;Array&lt;Location&gt;&gt;) : void; | Unregisters the listener for cached GNSS location reports. |
| on(type: 'gnssStatusChange', callback: Callback&lt;SatelliteStatusInfo&gt;) : void; | Registers a listener for satellite status change events. | | on(type: 'gnssStatusChange', callback: Callback&lt;SatelliteStatusInfo&gt;) : void; | Registers a listener for satellite status change events. |
| off(type: 'gnssStatusChange', callback?: Callback&lt;SatelliteStatusInfo&gt;) : void; | Unregisters the listener for satellite status change events. | | off(type: 'gnssStatusChange', callback?: Callback&lt;SatelliteStatusInfo&gt;) : void; | Unregisters the listener for satellite status change events. |
......
...@@ -37,3 +37,9 @@ Location awareness is offered by the system as a basic service for applications. ...@@ -37,3 +37,9 @@ Location awareness is offered by the system as a basic service for applications.
Your application can use the location function only after the user has granted the permission and turned on the function. If the location function is off, the system will not provide the location service for any application. Your application can use the location function only after the user has granted the permission and turned on the function. If the location function is off, the system will not provide the location service for any application.
Since the location information is considered sensitive, your application still needs to obtain the location access permission from the user even if the user has turned on the location function. The system will provide the location service for your application only after it has been granted the permission to access the device location information. Since the location information is considered sensitive, your application still needs to obtain the location access permission from the user even if the user has turned on the location function. The system will provide the location service for your application only after it has been granted the permission to access the device location information.
## Samples
The following sample is provided to help you better understand how to develop location services:
-[`Location`: Location (eTS) (API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/device/Location)
# USB Service Development # USB Service Development
The USB service provides the following functions: query of USB device list, bulk data transfer, control transfer, and access permission management.
## When to Use ## When to Use
In Host mode, you can obtain the list of connected devices, enable or disable the devices, manage device access permissions, and perform data transfer or control transfer. In Host mode, you can obtain the list of connected devices, enable or disable the devices, manage device access permissions, and perform data transfer or control transfer.
## APIs ## APIs
The USB service provides the following functions: query of USB device list, bulk data transfer, control transfer, and access permission management.
The following table lists the USB APIs currently available. For details, see the [API Reference](../reference/apis/js-apis-usb.md). The following table lists the USB APIs currently available. For details, see the [API Reference](../reference/apis/js-apis-usb.md).
**Table 1** Open USB APIs **Table 1** Open USB APIs
...@@ -21,7 +21,7 @@ The following table lists the USB APIs currently available. For details, see the ...@@ -21,7 +21,7 @@ The following table lists the USB APIs currently available. For details, see the
| setConfiguration(pipe: USBDevicePipe, config: USBConfig): number | Sets the USB device configuration. | | setConfiguration(pipe: USBDevicePipe, config: USBConfig): number | Sets the USB device configuration. |
| setInterface(pipe: USBDevicePipe, iface: USBInterface): number | Sets a USB interface. | | setInterface(pipe: USBDevicePipe, iface: USBInterface): number | Sets a USB interface. |
| claimInterface(pipe: USBDevicePipe, iface: USBInterface, force?: boolean): number | Claims a USB interface | | claimInterface(pipe: USBDevicePipe, iface: USBInterface, force?: boolean): number | Claims a USB interface |
| bulkTransfer(pipe: USBDevicePipe, endpoint: USBEndpoint, buffer: Uint8Array, timeout?: number): Promise\<number> | Performs bulk transfer. | | bulkTransfer(pipe: USBDevicePipe, endpoint: USBEndpoint, buffer: Uint8Array, timeout?: number): Promise\<number> | Performs bulk transfer. |
| closePipe(pipe: USBDevicePipe): number | Closes a USB device pipe. | | closePipe(pipe: USBDevicePipe): number | Closes a USB device pipe. |
| releaseInterface(pipe: USBDevicePipe, iface: USBInterface): number | Releases a USB interface. | | releaseInterface(pipe: USBDevicePipe, iface: USBInterface): number | Releases a USB interface. |
| getFileDescriptor(pipe: USBDevicePipe): number | Obtains the file descriptor. | | getFileDescriptor(pipe: USBDevicePipe): number | Obtains the file descriptor. |
......
...@@ -23,4 +23,4 @@ The vibrator is a Misc device that consists of four modules: Vibrator API, Vibra ...@@ -23,4 +23,4 @@ The vibrator is a Misc device that consists of four modules: Vibrator API, Vibra
## Constraints ## Constraints
When using a vibrator, you must declare the **ohos.permission.VIBRATE** permission before you can control the vibration effect. The sensitivity level of this permission is **system_grant**. When using a vibrator, you must declare the **ohos.permission.VIBRATE** permission before you can control the vibration effect. The authorization mode of this permission is **system_grant**.
...@@ -2,89 +2,164 @@ ...@@ -2,89 +2,164 @@
## When to Use ## When to Use
The event logging function helps applications to log various information generated during running. The event logging function helps applications log various information generated during running.
## Available APIs ## Available APIs
JS application event logging APIs are provided by the **hiAppEvent** module. JS application event logging APIs are provided by the **hiAppEvent** module.
**Table 1** APIs for event logging The following table provides only a brief description of related APIs. For details, see [HiAppEvent](../reference/apis/js-apis-hiappevent.md).
| API | Return Value | Description | **Table 1** APIs for application event logging
| ------------------------------------------------------------ | -------------- | ------------------------------------------------------------ |
| write(string eventName, EventType type, object keyValues, AsyncCallback\<void> callback): void | void | Logs application events in asynchronous mode. This method uses an asynchronous callback to return the result. |
| write(string eventName, EventType type, object keyValues): Promise\<void> | Promise\<void> | Logs application events in asynchronous mode. This method uses a promise to return the result. |
When an asynchronous callback is used, the return value can be processed directly in the callback. When a promise is used, the return value can also be processed in the promise in a similar way. For details about the result codes, see [Event Verification Result Codes](#event-verification-result-codes). | API | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| write(string eventName, EventType type, object keyValues, AsyncCallback\<void> callback): void | Logs application events in asynchronous mode. This API uses an asynchronous callback to return the result. |
| write(string eventName, EventType type, object keyValues): Promise\<void> | Logs application events in asynchronous mode. This API uses a promise to return the result. |
| write(AppEventInfo info, AsyncCallback\<void> callback): void | Logs application events by domain in asynchronous mode. This API uses an asynchronous callback to return the result.|
| write(AppEventInfo info): Promise\<void> | Logs application events by domain in asynchronous mode. This API uses a promise to return the result.|
**Table 2** APIs for event logging configuration When an asynchronous callback is used, the return value can be processed directly in the callback.
| API | Return Value | Description | If a promise is used, the return value can also be processed in the promise in a similar way.
| ------------------------------ | ------------ | ------------------------------------------------------------ |
| configure(ConfigOption config) | boolean | Sets the configuration options for application event logging.<br>The value **true** indicates that the operation is successful, and value **false** indicates the opposite. |
## Event Verification Result Codes For details about the result codes, see [Event Verification Result Codes](#event-verification-result-codes).
| Result Code | Cause | Check Rule | Processing Method | **Table 2** APIs for event logging configuration
| ----------- | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 0 | None | Event verification is successful. | Event logging is normal. No action is required. |
| -1 | Invalid event name | The event name is not empty and contains a maximum of 48 characters.<br/>The event name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore (\_).<br/>The event name does not start with a digit or underscore (_). | Ignore this event and do not perform logging. |
| -2 | Invalid event parameter type | The event name must be a string.<br/>The event type must be a number.<br/>The key value must be an object. | Ignore this event and do not perform logging. |
| -99 | Application event logging disabled | The application event logging function is disabled. | Ignore this event and do not perform logging. |
| -100 | Unknown error | None | Ignore this event and do not perform logging. |
| 1 | Invalid key name | The key name is not empty and contains a maximum of 16 characters.<br/>The key name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore (\_).<br/>The key name does not start with a digit or underscore (\_).<br/>The key name does not end with an underscore (_). | Ignore the key-value pair and continue to perform logging. |
| 2 | Invalid key type | The key must be a string. | Ignore the key-value pair and continue to perform logging. |
| 3 | Invalid value type | The supported value types vary depending on the programming language:<br/>boolean, number, string, or Array [basic element] | Ignore the key-value pair and continue to perform logging. |
| 4 | Value too long | The value can contain a maximum of 8*1024 characters. | Ignore the key-value pair and continue to perform logging. |
| 5 | Excess key-value pairs | The number of key-value pairs must be less than or equal to 32. | Ignore the excess key-value pairs and continue to perform logging. |
| 6 | Excess elements in a list value | The number of elements in a list value must be less than or equal to 100. | Truncate the list with only the first 100 elements retained, and continue to perform logging. |
| 7 | Invalid list value | A list value can only be a basic element.<br/>The elements in a list value must be of the same type. | Ignore the key-value pair and continue to perform logging. |
| API | Description |
| --------------------------------------- | ---------------------------------------------------- |
| configure(ConfigOption config): boolean | Sets the configuration options for application event logging.|
## How to Develop **Table 3** APIs for watcher management
In this example, an application event is logged after the application startup execution page is loaded. | API | Description |
| -------------------------------------------------- | -------------------- |
| addWatcher(Watcher watcher): AppEventPackageHolder | Adds an event watcher.|
| removeWatcher(Watcher watcher): void | Removes an event watcher.|
1. Create a JS application project. In the displayed Project window, choose **entry > src > main** > **js** > **default** > **pages > index**, and double-click index.js. Add the code to log the initial application event after page loading. The sample code is as follows: **Table 4** APIs for clearing logging data
```js | API | Description |
import hiAppEvent from '@ohos.hiAppEvent' | ----------------- | -------------------- |
| clearData(): void | Clears local logging data.|
### Event Verification Result Codes
| Result Code| Cause | Verification Rules | Handling Method |
| ------ | ----------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
| 0 | N/A | Event verification is successful. | Event logging is normal. No action is required. |
| -1 | Invalid event name | The name is not empty and contains a maximum of 48 characters.<br>The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).<br>The name does not start with a digit or underscore \(_).| Ignore this event and do not perform logging. |
| -2 | Invalid event parameter type | The event name must be a string.<br>The event type must be a number.<br>The event parameter must be an object.| Ignore this event and do not perform logging. |
| -4 | Invalid event domain name | The name is not empty and contains a maximum of 32 characters.<br>The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).<br>The name does not start with a digit or underscore \(_).| Ignore this event and do not perform logging. |
| -99 | Application event logging disabled | Application event logging is disabled. | Ignore this event and do not perform logging. |
| -100 | Unknown error | None. | Ignore this event and do not perform logging. |
| 1 | Invalid key name | The name is not empty and contains a maximum of 16 characters.<br>The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).<br>The name does not start with a digit or underscore \(_).<br>The name does not end with an underscore \(_).| Ignore the key-value pair and continue to perform logging. |
| 2 | Invalid key type | The key must be a string. | Ignore the key-value pair and continue to perform logging. |
| 3 | Invalid value type | The supported value types vary depending on the programming language:<br>boolean, number, string, or Array [basic element]| Ignore the key-value pair and continue to perform logging. |
| 4 | Invalid length for values of the string type| For a value of the string type, the maximum length is 8*1024 characters. | Truncate the value with the first 8*1024 characters retained, and continue to perform logging.|
| 5 | Excess key-value pairs | The number of key-value pairs must be less than or equal to 32. | Ignore the excess key-value pairs and continue to perform logging. |
| 6 | Invalid number of elements in values of the array type | For a value of the array type, the number of elements must be less than or equal to 100. | Truncate the array with the first 100 elements retained, and continue to perform logging. |
| 7 | Invalid parameters in values of the array type | For a value of the array type, all the parameters must be of the same type, which can only be boolean, number, or string.| Ignore the key-value pair and continue to perform logging. |
## Development Procedure
The following uses a one-time event watcher as an example to illustrate the development procedure.
1. Create an eTS application project. In the displayed **Project** window, choose **entry** > **src** > **main** > **ets** > **pages** > **index.ets**, and double-click **index.ets**. Then, add three buttons to simulate the process of watching for application events. Wherein, button 1 is used to invoke application event logging, button 2 to add an event watcher that automatically triggers a callback, and button 3 to remove the watcher. The complete sample code is as follows:
```ts
import hiAppEvent from '@ohos.hiAppEvent';
export default { @Entry
data: { @Component
title: "" struct Index {
}, @State message: string = 'Hello World'
onInit() {
this.title = this.$t('strings.world');
// 1. Callback mode build() {
hiAppEvent.write("start_event", hiAppEvent.EventType.BEHAVIOR, {"int_data":100, "str_data":"strValue"}, (err, value) => { Row() {
if (err) { Column() {
console.error(`failed to write event because ${err.code}`); Text(this.message)
return; .fontSize(50)
.fontWeight(FontWeight.Bold)
Button("1 writeTest").onClick(()=>{
hiAppEvent.write({
domain: "test_domain",
name: "test_event",
eventType: hiAppEvent.EventType.FAULT,
params: {
int_data: 100,
str_data: "strValue"
} }
console.log(`success to write event: ${value}`); }).then((value) => {
}); console.log(`HiAppEvent success to write event: ${value}`);
}).catch((err) => {
console.error(`HiAppEvent failed to write event because ${err.code}`);
});
})
// 2. Promise mode Button("2 addWatcherTest").onClick(()=>{
hiAppEvent.write("start_event", hiAppEvent.EventType.BEHAVIOR, {"int_data":100, "str_data":"strValue"}) hiAppEvent.addWatcher({
.then((value) => { name: "watcher1",
console.log(`success to write event: ${value}`); appEventFilters: [{ domain: "test_domain" }],
}).catch((err) => { triggerCondition: {
console.error(`failed to write event because ${err.code}`); row: 2,
}); size: 1000,
timeOut: 2
// 3. Set the application event logging switch. },
hiAppEvent.configure({ onTrigger: function (curRow, curSize, holder) {
disable: true if (holder == null) {
}); console.error("HiAppEvent holder is null");
return;
}
let eventPkg = null;
while ((eventPkg = holder.takeNext()) != null) {
console.info("HiAppEvent eventPkg.packageId=" + eventPkg.packageId);
console.info("HiAppEvent eventPkg.row=" + eventPkg.row);
console.info("HiAppEvent eventPkg.size=" + eventPkg.size);
for (const eventInfo of eventPkg.data) {
console.info("HiAppEvent eventPkg.data=" + eventInfo);
}
}
}
});
})
// 4. Set the maximum size of the event file storage directory. The default value is 10M. Button("3 removeWatcherTest").onClick(()=>{
hiAppEvent.configure({ hiAppEvent.removeWatcher({
maxStorage: '100M' name: "watcher1"
}); })
})
}
.width('100%')
} }
.height('100%')
}
} }
``` ```
2. Tap the run button on the application UI to run the project. 2. Touch the run button on the IDE to run the project.
3. Touch button 1 on the application UI to start application event logging. If the logging is successful, you'll see the following message in the **Log** window:
```
success to write event: 0
```
4. On the application UI, touch button 2 to add an event watcher, and touch button 1 for multiple times to perform application event logging. If any callback trigger condition (event count, event data size, and timeout duration) is met, the event watcher will invoke a callback and the event package obtained through the callback will be displayed in the **Log** window.
```
HiAppEvent eventPkg.packageId=0
HiAppEvent eventPkg.row=2
HiAppEvent eventPkg.size=308
HiAppEvent eventPkg.data={"domain_":"test_domain","name_":"test_event","type_":1,"time_":1502096107556,"tz_":"+0000","pid_":4204,"tid_":4223,"int_data":100,"str_data":"strValue"}
```
5. On the application UI, touch button 3 to remove the event watcher. Then, touch button 1 for multiple times to perform application event logging. In such a case, there will be no log information about the callback invoked by the event watcher.
## Samples
The following sample is provided to help you better understand how to develop the application event logging feature:
- [`JsDotTest` (JS) (API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/DFX/JsDotTest)
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
HiAppEvent provides event logging APIs for applications to log the fault, statistical, security, and user behavior events reported during running. Based on event information, you will be able to analyze the running status of your application. HiAppEvent provides event logging APIs for applications to log the fault, statistical, security, and user behavior events reported during running. Based on event information, you will be able to analyze the running status of your application.
The HiAppEvent module of OpenHarmony can be used to develop application event services and provide functions related to application events, including flushing application events to a disk and querying historical application event data. The HiAppEvent module can be used to develop application event-related functions, including flushing application events to a disk and querying historical application events.
## Basic Concepts ## Basic Concepts
- **Logging** **Logging**
Logs changes caused by user operations to provide service data for development, product, and O&M analysis. A function that logs changes caused by user operations to provide service data for development, product, and O&M analysis.
\ No newline at end of file
# FAQs
- [Ability Framework Development](faqs-ability.md)
- [Graphics and Image Development](faqs-graphics.md)
- [File Management Development](faqs-file-management.md)
- [Data Management Development](faqs-data-management.md)
- [Native API Usage](faqs-native.md)
- [Usage of Third- and Fourth-Party Libraries](faqs-third-party-library.md)
# Ability Framework Development
## Is a guide similar to the Data ability development in the FA model available for the stage model?
Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
A guide is available for the **DataShareExtensionAbility** class in the stage model, which provides APIs for sharing data with other applications and managing the data.
Reference: [DataShare Development](../database/database-datashare-guidelines.md)
## What should I do if the UI does not respond when an ability is started?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
1. If the ability is started using **startAbility**, check whether the **abilityName** field in **want** uses the bundle name as the prefix. If yes, delete the bundle name.
2. Make sure the ability's home page file configured by **onWindowStageCreate** in the **MainAbility.ts** file is defined in the **main_pages.json** file.
3. You are advised to use the SDK and OpenHarmony SDK versions released on the same day.
Reference: [Release Testing Version](https://gitee.com/openharmony-sig/oh-inner-release-management/blob/master/Release-Testing-Version.md)
## How do I prevent "this" in a method from changing to "undefined" when the method is called?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
Method 1: Add **.bind(this)** when calling the method.
Method 2: Use the arrow function.
## What should I do when the message "must have required property 'startWindowIcon'" is displayed?
Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Configure the **startWindowIcon** attribute under **abilities** in the **module.json5** file.
Reference: [Application Package Structure Configuration File](../quick-start/stage-structure.md)
Example:
```
{
"module": {
// Do something.
"abilities": [{
// Do something.
"startWindowIcon": "$media:space",
"startWindowBackground": "$color:white",
}]
}
}
```
## How do I obtain a notification when the device orientation changes?
Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Implement the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the orientation and density) change.
Reference: [Ability Development](../ability/stage-ability.md)
# Device Management Development
## How Do I Save PixelMap data to a database?
Applicable to: OpenHarmony SDK 3.2.3.5
You can convert a **PixelMap** into a **ArrayBuffer** and save the **ArrayBuffer** to your database.
Reference: [readPixelsToBuffer](../reference/apis/js-apis-image.md#readpixelstobuffer7-1)
## How Do I Obtain RDB Store Files?
Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Run the hdc_std command to copy the .db, .db-shm, and .db-wal files from **/data/app/el2/100/database/Bundle name/entry/db/**, and then use the SQLite tool to open the files.
Example:
```
hdc_std file recv /data/app/el2/100/database/com.xxxx.xxxx/entry/db/test.db ./test.db
```
# File Management Development
## What If There is No Return Value or Error Captured After getAlbums Is Called?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
The **ohos.permission.READ_MEDIA** permission is required for calling **getAlbums**, and this permission needs user authorization. For details, see OpenHarmony [Application Permission List](../security/permission-list.md).
1. Configure the required permission in the **module.json5** file.
```
"requestPermissions": [
{
"name": "ohos.permission.READ_MEDIA"
}
]
```
2. Add the code for user authorization before the **MainAbility.ts -> onWindowStageCreate** page is loaded.
```
private requestPermissions() {
let permissionList: Array<string> = [
"ohos.permission.READ_MEDIA"
];
this.context.requestPermissionsFromUser(permissionList)
.then(data => {
console.info(`request permission data result = ${data.authResults}`)
})
.catch(err => {
console.error(`fail to request permission error:${err}`)
})
}
```
# Graphics and Image Development
## Why do the isStatusBarLightIcon and isNavigationBarLightIcon attributes not take effect when window.setSystemBarProperties() is called?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
In effect, the **isStatusBarLightIcon** and **isNavigationBarLightIcon** attributes turn the font white when set to **true**. If **statusBarContentColor** is also set in **window.setSystemBarProperties()**, the **isStatusBarLightIcon** attribute does not take effect. Similarly, if **navigationBarContentColor** is set, the **isNavigationBarLightIcon** attribute does not take effect.
## How do I set the style of the system bar?
Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9
Import the **\@ohos.window** module, and call **window.setSystemBarProperties()**.
# Native API Usage
## When a native HAP is running, the error message "Obj is not a valid object" is displayed for the imported namespace. What should I do?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
Check the **abiFilters** parameter value in the **build-profile.json5** file in the root directory of the module (not the root directory of the project). If the device is 32-bit, the value must be **armeabi-v7a**. If the device is 64-bit, the value must be **arm64-v8a**.
## How do I obtain the value of version in the package.json file of a module in the C++ code developed using native APIs?
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
1. In the script file **hvigorfile.js** of Hvigor, use **subModule.getPackageJsonPath** to obtain the location of the **package.json** file in the module.
2. Use Node.js to read the **version** field in the **package.json** file and write the value to the **buildOption.cppFlags** field in the **build-profile.json5** file.
Example
```
// Module-level hvigorfile.js
const subModule = require('@ohos/hvigor')(__filename)
const fs = require("fs-extra")
const path = require("path")
const packageJsonPath = subModule.getPackageJsonPath()
const buildProfilePath = path.resolve(packageJsonPath, '../build-profile.json5')
const packageJsonData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
let buildProfileData = fs.readFileSync(buildProfilePath, 'utf8')
buildProfileData = buildProfileData.replace(/\"cppFlags\"\:(.*)\,/, `"cppFlags": "-D NWEBEX_VERSION=${packageJsonData.version}",`)
fs.writeFileSync(buildProfilePath, buildProfileData, 'utf8')
const ohosPlugin = require('@ohos/hvigor-ohos-plugin').hapTasks(subModule) // The plug-in executes the C++ build task and reads the build-profile.json5 file.
module.exports = {
ohos: ohosPlugin
}
```
```
// Read the hello.cpp file.
#define _NWEBEX_VERSION(v) #v
#define _NWEBEX_VER2STR(v) _NWEBEX_VERSION(v)
static napi_value Add(napi_env env, napi_callback_info info)
{
napi_value fixed_version_value = nullptr;
napi_create_string_utf8(env, _NWEBEX_VER2STR(NWEBEX_VERSION), NAPI_AUTO_LENGTH, &fixed_version_value);
return fixed_version_value;
}
```
# Usage of Third- and Fourth-Party Libraries
## What does the following error message mean : "Stage model module... does not support including OpenHarmony npm packages or modules in FA model. OpenHarmony build tasks will not be executed, and OpenHarmony resources will not be packed."
Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9
The third- and fourth-party libraries are not yet compatible with the stage model of API version 9 and cannot be used.
# Internationalization Development (I18N) # Internationalization Development (I18N)
This module provides system-related or enhanced I18N capabilities, such as locale management, phone number formatting, and calendar, through supplementary I18N interfaces that are not defined in ECMA 402. This module provides system-related or enhanced I18N capabilities, such as locale management, phone number formatting, and calendar, through supplementary I18N APIs that are not defined in ECMA 402. For more details about APIs and their usage, see [I18N](../reference/apis/js-apis-i18n.md).
The [Intl](intl-guidelines.md) module provides basic I18N capabilities through the standard I18N interfaces defined in ECMA 402. It works with the I18N module to provide a complete suite of I18N capabilities.
## Obtaining System Language and Region Information ## Obtaining System Language and Region Information
...@@ -90,7 +89,7 @@ You can use APIs provided in the following table to obtain the system language a ...@@ -90,7 +89,7 @@ You can use APIs provided in the following table to obtain the system language a
## Obtaining Calendar Information ## Obtaining Calendar Information
[Calendar](../reference/apis/js-apis-intl.md) APIs are used to obtain calendar information, for example, the localized display of the calendar, the first day of a week, and the minimum count of days in the first week of a year. [Calendar](../reference/apis/js-apis-i18n.md#calendar8) APIs are used to obtain calendar information, for example, the localized display of the calendar, the first day of a week, and the minimum count of days in the first week of a year.
### Available APIs ### Available APIs
...@@ -119,7 +118,7 @@ You can use APIs provided in the following table to obtain the system language a ...@@ -119,7 +118,7 @@ You can use APIs provided in the following table to obtain the system language a
```js ```js
var calendar = i18n.getCalendar("zh-CN", "gregory); var calendar = i18n.getCalendar("zh-CN", "gregory");
``` ```
2. Set the time for the **Calendar** object. 2. Set the time for the **Calendar** object.
...@@ -192,7 +191,7 @@ You can use APIs provided in the following table to obtain the system language a ...@@ -192,7 +191,7 @@ You can use APIs provided in the following table to obtain the system language a
## Formatting a Phone Number ## Formatting a Phone Number
[PhoneNumberFormat](../reference/apis/js-apis-intl.md) APIs are used to format phone numbers in different countries and check whether the phone number formats are correct. [PhoneNumberFormat](../reference/apis/js-apis-i18n.md#phonenumberformat8) APIs are used to format phone numbers in different countries and check whether the phone number formats are correct.
### Available APIs ### Available APIs
...@@ -245,7 +244,7 @@ The **unitConvert** API is provided to help you implement measurement conversion ...@@ -245,7 +244,7 @@ The **unitConvert** API is provided to help you implement measurement conversion
### How to Develop ### How to Develop
1. Convert a measurement unit. 1. Convert a measurement unit.
Call the [unitConvert](../reference/apis/js-apis-intl.md) method to convert a measurement unit and format the display result. Call the [unitConvert](../reference/apis/js-apis-i18n.md#unitconvert8) method to convert a measurement unit and format the display result.
```js ```js
...@@ -260,7 +259,7 @@ The **unitConvert** API is provided to help you implement measurement conversion ...@@ -260,7 +259,7 @@ The **unitConvert** API is provided to help you implement measurement conversion
## Alphabet Index ## Alphabet Index
[IndexUtil](../reference/apis/js-apis-intl.md) APIs are used to obtain the alphabet indexes of different locales and calculate the index to which a string belongs. [IndexUtil](../reference/apis/js-apis-i18n.md#indexutil8) APIs are used to obtain the alphabet indexes of different locales and calculate the index to which a string belongs.
### Available APIs ### Available APIs
...@@ -281,7 +280,7 @@ The **unitConvert** API is provided to help you implement measurement conversion ...@@ -281,7 +280,7 @@ The **unitConvert** API is provided to help you implement measurement conversion
```js ```js
var indexUtil = getInstance("zh-CN"); var indexUtil = i18n.getInstance("zh-CN");
``` ```
2. Obtain the index list. 2. Obtain the index list.
...@@ -312,7 +311,7 @@ The **unitConvert** API is provided to help you implement measurement conversion ...@@ -312,7 +311,7 @@ The **unitConvert** API is provided to help you implement measurement conversion
## Obtaining Line Breaks of Text ## Obtaining Line Breaks of Text
When a text is displayed in more than one line, [BreakIterator](../reference/apis/js-apis-intl.md) APIs are used to obtain the line break positions of the text. When a text is displayed in more than one line, [BreakIterator8](../reference/apis/js-apis-i18n.md#breakiterator8) APIs are used to obtain the line break positions of the text.
### Available APIs ### Available APIs
......
# Internationalization Development (Intl) # Internationalization Development (Intl)
This module provides basic I18N capabilities, such as time and date formatting, number formatting, and string sorting, through the standard I18N interfaces defined in ECMA 402. This module provides basic I18N capabilities, such as time and date formatting, number formatting, and string sorting, through the standard I18N APIs defined in ECMA 402. For more details about APIs and their usage, see [Intl](../reference/apis/js-apis-intl.md).
The [I18N](i18n-guidelines.md) module provides enhanced I18N capabilities through supplementary interfaces that are not defined in ECMA 402. It works with the Intl module to provide a complete suite of I18N capabilities.
> **NOTE** > **NOTE**
> >
...@@ -9,7 +8,7 @@ The [I18N](i18n-guidelines.md) module provides enhanced I18N capabilities throug ...@@ -9,7 +8,7 @@ The [I18N](i18n-guidelines.md) module provides enhanced I18N capabilities throug
## Setting Locale Information ## Setting Locale Information
Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize locale information. Use [Locale](../reference/apis/js-apis-intl.md#locale) APIs to maximize or minimize locale information.
### Available APIs ### Available APIs
...@@ -27,7 +26,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc ...@@ -27,7 +26,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc
1. Instantiate a **Locale** object. 1. Instantiate a **Locale** object.
Create a **Locale** object by using the **Locale** constructor. This method receives a string representing the locale and an optional [Attributes](../reference/apis/js-apis-intl.md) list. Create a **Locale** object by using the **Locale** constructor. This method receives a string representing the locale and an optional [Attributes](../reference/apis/js-apis-intl.md#localeoptions) list.
A **Locale** object consists of four parts: language, script, region, and extension, which are separated by using a hyphen (-). A **Locale** object consists of four parts: language, script, region, and extension, which are separated by using a hyphen (-).
- Language: mandatory. It is represented by a two-letter or three-letter code as defined in ISO-639. For example, **en** indicates English and **zh** indicates Chinese. - Language: mandatory. It is represented by a two-letter or three-letter code as defined in ISO-639. For example, **en** indicates English and **zh** indicates Chinese.
...@@ -46,7 +45,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc ...@@ -46,7 +45,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc
```js ```js
var locale = "zh-CN"; var locale = "zh-CN";
var options = {caseFirst: false, calendar: "chinese", collation: pinyin}; var options = {caseFirst: false, calendar: "chinese", collation: "pinyin"};
var localeObj = new intl.Locale(locale, options); var localeObj = new intl.Locale(locale, options);
``` ```
...@@ -77,7 +76,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc ...@@ -77,7 +76,7 @@ Use [Locale](../reference/apis/js-apis-intl.md) APIs to maximize or minimize loc
## Formatting the Date and Time ## Formatting the Date and Time
Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date and time for a specific locale. Use [DateTimeFormat](../reference/apis/js-apis-intl.md#datetimeformat) APIs to format the date and time for a specific locale.
### Available APIs ### Available APIs
...@@ -102,7 +101,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date ...@@ -102,7 +101,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date
var dateTimeFormat = new intl.DateTimeFormat(); var dateTimeFormat = new intl.DateTimeFormat();
``` ```
Alternatively, use your own locale and formatting parameters to create a **DateTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [DateTimeOptions](../reference/apis/js-apis-intl.md). Alternatively, use your own locale and formatting parameters to create a **DateTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [DateTimeOptions](../reference/apis/js-apis-intl.md#datetimeoptions).
```js ```js
var options = {dateStyle: "full", timeStyle: "full"}; var options = {dateStyle: "full", timeStyle: "full"};
...@@ -114,7 +113,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date ...@@ -114,7 +113,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date
Call the **format** method to format the date and time in the **DateTimeFormat** object. This method returns a string representing the formatting result. Call the **format** method to format the date and time in the **DateTimeFormat** object. This method returns a string representing the formatting result.
```js ```js
Date date = new Date(); var date = new Date();
var formatResult = dateTimeFormat.format(date); var formatResult = dateTimeFormat.format(date);
``` ```
...@@ -123,9 +122,10 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date ...@@ -123,9 +122,10 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date
Call the **formatRange** method to format the period in the **DateTimeFormat** object. This method requires input of two **Date** objects, which respectively indicate the start date and end date of a period. This method returns a string representing the formatting result. Call the **formatRange** method to format the period in the **DateTimeFormat** object. This method requires input of two **Date** objects, which respectively indicate the start date and end date of a period. This method returns a string representing the formatting result.
```js ```js
Date startDate = new Date(); var startDate = new Date(2021, 11, 17, 3, 24, 0);
Date endDate = new Date(); var endDate = new Date(2021, 11, 18, 3, 24, 0);
var formatResult = dateTimeFormat.formatRange(startDate, endDate); var datefmt = new Intl.DateTimeFormat("en-GB");
datefmt.formatRange(startDate, endDate);
``` ```
4. Obtain attributes of the **DateTimeFormat** object. 4. Obtain attributes of the **DateTimeFormat** object.
...@@ -139,7 +139,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date ...@@ -139,7 +139,7 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the date
## Formatting Numbers ## Formatting Numbers
Use [NumberFormat](../reference/apis/js-apis-intl.md) APIs to format numbers for a specific locale. Use [NumberFormat](../reference/apis/js-apis-intl.md#numberformat) APIs to format numbers for a specific locale.
### Available APIs ### Available APIs
...@@ -163,7 +163,7 @@ Use [NumberFormat](../reference/apis/js-apis-intl.md) APIs to format numbers for ...@@ -163,7 +163,7 @@ Use [NumberFormat](../reference/apis/js-apis-intl.md) APIs to format numbers for
var numberFormat = new intl.NumberFormat(); var numberFormat = new intl.NumberFormat();
``` ```
Alternatively, use your own locale and formatting parameters to create a **NumberFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [NumberOptions](../reference/apis/js-apis-intl.md). Alternatively, use your own locale and formatting parameters to create a **NumberFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [NumberOptions](../reference/apis/js-apis-intl.md#numberoptions).
```js ```js
var options = {compactDisplay: "short", notation: "compact"}; var options = {compactDisplay: "short", notation: "compact"};
...@@ -190,7 +190,7 @@ Use [NumberFormat](../reference/apis/js-apis-intl.md) APIs to format numbers for ...@@ -190,7 +190,7 @@ Use [NumberFormat](../reference/apis/js-apis-intl.md) APIs to format numbers for
## Sorting Strings ## Sorting Strings
Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on a specific locale. Users in different regions have different preferences for string sorting. Use [Collator](../reference/apis/js-apis-intl.md#collator8) APIs to sort strings based on a specific locale. Users in different regions have different preferences for string sorting.
### Available APIs ### Available APIs
...@@ -214,7 +214,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on ...@@ -214,7 +214,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on
var collator = new intl.Collator(); var collator = new intl.Collator();
``` ```
Alternatively, use your own locale and formatting parameters to create a **Collator** object. For a full list of parameters, see [CollatorOptions](../reference/apis/js-apis-intl.md). Alternatively, use your own locale and formatting parameters to create a **Collator** object. For a full list of parameters, see [CollatorOptions](../reference/apis/js-apis-intl.md#collatoroptions8).
```js ```js
var collator= new intl.Collator("zh-CN", {localeMatcher: "best fit", usage: "sort"}); var collator= new intl.Collator("zh-CN", {localeMatcher: "best fit", usage: "sort"});
...@@ -222,7 +222,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on ...@@ -222,7 +222,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on
2. Compare two strings. 2. Compare two strings.
Call the **compare** method to compare two input strings. This method returns a value as the comparison result. The return value **-1** indicates that the first string is shorter than the second string, the return value **1** indicates that the first string is longer than the second string, and the return value **0** indicates that the two strings are of equal lengths. Call the **compare** method to compare two input strings. This method returns a value as the comparison result. The return value **-1** indicates that the first string is shorter than the second string, the return value **1** indicates that the first string is longer than the second string, and the return value **0** indicates that the two strings are of equal lengths. This allows you to sort character strings based on the comparison result.
```js ```js
var str1 = "first string"; var str1 = "first string";
...@@ -241,7 +241,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on ...@@ -241,7 +241,7 @@ Use [Collator](../reference/apis/js-apis-intl.md) APIs to sort strings based on
## Determining the Singular-Plural Type ## Determining the Singular-Plural Type
Use [PluralRules](../reference/apis/js-apis-intl.md) APIs to determine the singular-plural type for a specific locale. According to the grammar of certain languages, the singular or plural form of a noun depends on its preceding number. Use [PluralRules](../reference/apis/js-apis-intl.md#pluralrules8) APIs to determine the singular-plural type for a specific locale. According to the grammar of certain languages, the singular or plural form of a noun depends on its preceding number.
### Available APIs ### Available APIs
...@@ -264,10 +264,10 @@ Use [PluralRules](../reference/apis/js-apis-intl.md) APIs to determine the singu ...@@ -264,10 +264,10 @@ Use [PluralRules](../reference/apis/js-apis-intl.md) APIs to determine the singu
var pluralRules = new intl.PluralRules(); var pluralRules = new intl.PluralRules();
``` ```
Alternatively, use your own locale and formatting parameters to create a **PluralRules** object. For a full list of parameters, see [PluralRulesOptions](../reference/apis/js-apis-intl.md). Alternatively, use your own locale and formatting parameters to create a **PluralRules** object. For a full list of parameters, see [PluralRulesOptions](../reference/apis/js-apis-intl.md#pluralrulesoptions8).
```js ```js
var plurals = new intl.PluralRules("zh-CN", {localeMatcher: "best fit", type: "cardinal"}); var pluralRules = new intl.PluralRules("zh-CN", {localeMatcher: "best fit", type: "cardinal"});
``` ```
2. Determine the singular-plural type. 2. Determine the singular-plural type.
...@@ -282,7 +282,7 @@ Use [PluralRules](../reference/apis/js-apis-intl.md) APIs to determine the singu ...@@ -282,7 +282,7 @@ Use [PluralRules](../reference/apis/js-apis-intl.md) APIs to determine the singu
## Formatting the Relative Time ## Formatting the Relative Time
Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the relative time for a specific locale. Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md#relativetimeformat8) APIs to format the relative time for a specific locale.
### Available APIs ### Available APIs
...@@ -307,7 +307,7 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the r ...@@ -307,7 +307,7 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the r
var relativeTimeFormat = new intl.RelativeTimeFormat(); var relativeTimeFormat = new intl.RelativeTimeFormat();
``` ```
Alternatively, use your own locale and formatting parameters to create a **RelativeTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [ RelativeTimeFormatInputOptions](../reference/apis/js-apis-intl.md). Alternatively, use your own locale and formatting parameters to create a **RelativeTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [RelativeTimeFormatInputOptions](../reference/apis/js-apis-intl.md#relativetimeformatinputoptions8).
```js ```js
var relativeTimeFormat = new intl.RelativeTimeFormat("zh-CN", {numeric: "always", style: "long"}); var relativeTimeFormat = new intl.RelativeTimeFormat("zh-CN", {numeric: "always", style: "long"});
...@@ -335,8 +335,16 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the r ...@@ -335,8 +335,16 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md) APIs to format the r
4. Obtain attributes of the **RelativeTimeFormat** object. 4. Obtain attributes of the **RelativeTimeFormat** object.
Call the **resolvedOptions** method to obtain attributes of the **RelativeTimeFormat** object. This method will return an array that contains all attributes and values of the object. For a full list of attributes, see [ RelativeTimeFormatResolvedOptions](../reference/apis/js-apis-intl.md). Call the **resolvedOptions** method to obtain attributes of the **RelativeTimeFormat** object. This method will return an array that contains all attributes and values of the object. For a full list of attributes, see [RelativeTimeFormatResolvedOptions](../reference/apis/js-apis-intl.md#relativetimeformatresolvedoptions8).
```js ```js
var options = numberFormat.resolvedOptions(); var options = numberFormat.resolvedOptions();
``` ```
## Samples
The following sample is provided to help you better understand how to develop internationalization capabilities:
-[`International`: Internationalization (JS) (API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/UI/International)
-[`International`: Internationalization (eTS) (API8) (Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/common/International)
...@@ -54,7 +54,7 @@ await cameraManager.getCameras((err, cameras) => { ...@@ -54,7 +54,7 @@ await cameraManager.getCameras((err, cameras) => {
cameraArray = cameras cameraArray = cameras
}) })
for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex) { for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex++) {
console.log('cameraId : ' + cameraArray[cameraIndex].cameraId) // Obtain the camera ID. console.log('cameraId : ' + cameraArray[cameraIndex].cameraId) // Obtain the camera ID.
console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition) // Obtain the camera position. console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition) // Obtain the camera position.
console.log('cameraType : ' + cameraArray[cameraIndex].cameraType) // Obtain the camera type. console.log('cameraType : ' + cameraArray[cameraIndex].cameraType) // Obtain the camera type.
......
# Distributed Camera Development
## When to Use
You can call the APIs provided by the **Camera** module to develop a distributed camera that provides the basic camera functions such as shooting and video recording.
## How to Develop
Connect your calculator to a distributed device. Your calculator will call **getCameras()** to obtain the camera list and traverse the returned camera list to check **ConnctionType** of the **Camera** objects. If **ConnctionType** of a **Camera** object is **CAMERA_CONNECTION_REMOTE**, your calculator will use this object to create a **CameraInput** object. The subsequent call process is the same as that of the local camera development. For details about the local camera development, see [Camera Development](./camera.md).
For details about the APIs, see [Camera Management](../reference/apis/js-apis-camera.md).
### Connecting to a Distributed Camera
Connect the calculator and the distributed device to the same LAN.
Open the calculator and click the arrow icon in the upper right corner. A new window is displayed. Enter the verification code as prompted, and the calculator will be connected to the distributed device.
### Creating an Instance
```js
import camera from '@ohos.multimedia.camera'
import image from '@ohos.multimedia.image'
import media from '@ohos.multimedia.media'
import featureAbility from '@ohos.ability.featureAbility'
// Create a CameraManager object.
let cameraManager
await camera.getCameraManager(globalThis.Context, (err, manager) => {
if (err) {
console.error('Failed to get the CameraManager instance ${err.message}');
return;
}
console.log('Callback returned with the CameraManager instance');
cameraManager = manager
})
// Register a callback to listen for camera status changes and obtain the updated camera status information.
cameraManager.on('cameraStatus', (cameraStatusInfo) => {
console.log('camera : ' + cameraStatusInfo.camera.cameraId);
console.log('status: ' + cameraStatusInfo.status);
})
// Obtain the camera list.
let cameraArray
let remoteCamera
await cameraManager.getCameras((err, cameras) => {
if (err) {
console.error('Failed to get the cameras. ${err.message}');
return;
}
console.log('Callback returned with an array of supported cameras: ' + cameras.length);
cameraArray = cameras
})
for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex) {
console.log('cameraId : ' + cameraArray[cameraIndex].cameraId) // Obtain the camera ID.
console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition) // Obtain the camera position.
console.log('cameraType : ' + cameraArray[cameraIndex].cameraType) // Obtain the camera type.
console.log('connectionType : ' + cameraArray[cameraIndex].connectionType) // Obtain the camera connection type.
if (cameraArray[cameraIndex].connectionType == CAMERA_CONNECTION_REMOTE) {
remoteCamera = cameraArray[cameraIndex].cameraId
}
}
// Create a camera input stream.
let cameraInput
await cameraManager.createCameraInput(remoteCamera).then((input) => {
console.log('Promise returned with the CameraInput instance');
cameraInput = input
})
```
For details about the subsequent steps, see [Camera Development](./camera.md).
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
- [Using Native APIs in Application Projects](napi-guidelines.md) - [Using Native APIs in Application Projects](napi-guidelines.md)
- [Drawing Development](drawing-guidelines.md) - [Drawing Development](drawing-guidelines.md)
- [Native Window Development](native-window-guidelines.md)
- [Raw File Development](rawfile-guidelines.md) - [Raw File Development](rawfile-guidelines.md)
- [Native Window Development](native-window-guidelines.md)
...@@ -89,7 +89,7 @@ Register four synchronous APIs (`getSync`, `setSync`, `removeSync`, and`clearSyn ...@@ -89,7 +89,7 @@ Register four synchronous APIs (`getSync`, `setSync`, `removeSync`, and`clearSyn
/*********************************************** /***********************************************
* Module export and register * Module export and register
***********************************************/ ***********************************************/
static napi_value StorgeExport(napi_env env, napi_value exports) static napi_value StorageExport(napi_env env, napi_value exports)
{ {
napi_property_descriptor desc[] = { napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("get", JSStorageGet), DECLARE_NAPI_FUNCTION("get", JSStorageGet),
...@@ -110,7 +110,7 @@ static napi_value StorgeExport(napi_env env, napi_value exports) ...@@ -110,7 +110,7 @@ static napi_value StorgeExport(napi_env env, napi_value exports)
static napi_module storage_module = {.nm_version = 1, static napi_module storage_module = {.nm_version = 1,
.nm_flags = 0, .nm_flags = 0,
.nm_filename = nullptr, .nm_filename = nullptr,
.nm_register_func = StorgeExport, .nm_register_func = StorageExport,
.nm_modname = "storage", .nm_modname = "storage",
.nm_priv = ((void*)0), .nm_priv = ((void*)0),
.reserved = {0}}; .reserved = {0}};
......
...@@ -7,139 +7,33 @@ You can set your application to call the **ReminderRequest** class to create sch ...@@ -7,139 +7,33 @@ You can set your application to call the **ReminderRequest** class to create sch
## Available APIs ## Available APIs
**reminderAgent** encapsulates the methods for publishing and canceling reminders. **reminderAgent** encapsulates the APIs for publishing and canceling reminders.
**Table 1** Major APIs in reminderAgent For details about the APIs, see [reminderAgent](../reference/apis/js-apis-reminderAgent.md).
| Name| Description|
| -------- | -------- |
| function publishReminder(reminderReq: ReminderRequest, callback: AsyncCallback&lt;number&gt;): void;<br>function publishReminder(reminderReq: ReminderRequest): Promise&lt;number&gt;; | Publishes a scheduled reminder.<br>The maximum number of valid notifications (excluding expired ones that will not pop up again) is 30 for one application and 2000 for the entire system. |
| function cancelReminder(reminderId: number, callback: AsyncCallback&lt;void&gt;): void;<br>function cancelReminder(reminderId: number): Promise&lt;void&gt;; | Cancels a specified reminder. (The value of **reminderId** is obtained from the return value of **publishReminder**.)|
| function getValidReminders(callback: AsyncCallback&lt;Array&lt;ReminderRequest&gt;&gt;): void;<br>function getValidReminders(): Promise&lt;Array&lt;ReminderRequest&gt;&gt;; | Obtains all valid reminders set by the current application.|
| function cancelAllReminders(callback: AsyncCallback&lt;void&gt;): void;<br>function cancelAllReminders(): Promise&lt;void&gt;; | Cancels all reminders set by the current application.|
| function addNotificationSlot(slot: NotificationSlot, callback: AsyncCallback&lt;void&gt;): void;<br>function addNotificationSlot(slot: NotificationSlot): Promise&lt;void&gt;; | Registers a **NotificationSlot** instance to be used by the reminder. |
| function removeNotificationSlot(slotType: notification.SlotType, callback: AsyncCallback&lt;void&gt;): void;<br>function removeNotificationSlot(slotType: notification.SlotType): Promise&lt;void&gt;; | Removes a **NotificationSlot** instance of a specified type. |
**ActionButtonType** enumerates types of buttons displayed in a reminder notification. **Table 1** Major APIs in reminderAgent
**Table 2** ActionButtonType enums
| Name| Description|
| -------- | -------- |
| ACTION_BUTTON_TYPE_CLOSE | Close button, which can stop the reminder alert tone, close the reminder notification, and cancel the reminder snoozing.|
| ACTION_BUTTON_TYPE_SNOOZE | Snooze button, which can snooze the reminder.|
**ReminderType** enumerates the reminder types.
**Table 3** ReminderType enums
| Name| Description| | Name| Description|
| -------- | -------- | | -------- | -------- |
| REMINDER_TYPE_TIMER | Countdown reminder.| | publishReminder(reminderReq: ReminderRequest, callback: AsyncCallback&lt;number&gt;): void<br>publishReminder(reminderReq: ReminderRequest): Promise&lt;number&gt; | Publishes a scheduled reminder.<br>The maximum number of valid notifications (excluding expired ones that will not pop up again) is 30 for one application and 2000 for the entire system. |
| REMINDER_TYPE_CALENDAR | Calendar reminder.| | cancelReminder(reminderId: number, callback: AsyncCallback&lt;void&gt;): void<br>cancelReminder(reminderId: number): Promise&lt;void&gt; | Cancels a specified reminder. (The value of **reminderId** is obtained from the return value of **publishReminder**.)|
| REMINDER_TYPE_ALARM | Alarm reminder.| | getValidReminders(callback: AsyncCallback&lt;Array&lt;ReminderRequest&gt;&gt;): void<br>getValidReminders(): Promise&lt;Array&lt;ReminderRequest&gt;&gt; | Obtains all valid reminders set by the current application.|
| cancelAllReminders(callback: AsyncCallback&lt;void&gt;): void<br>cancelAllReminders(): Promise&lt;void&gt; | Cancels all reminders set by the current application.|
**ActionButton** defines a button displayed in the reminder notification. | addNotificationSlot(slot: NotificationSlot, callback: AsyncCallback&lt;void&gt;): void<br>addNotificationSlot(slot: NotificationSlot): Promise&lt;void&gt; | Registers a **NotificationSlot** instance to be used by the reminder.|
| removeNotificationSlot(slotType: notification.SlotType, callback: AsyncCallback&lt;void&gt;): void<br>removeNotificationSlot(slotType: notification.SlotType): Promise&lt;void&gt; | Removes a **NotificationSlot** instance of a specified type.|
**Table 4** ActionButton
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| title | string | Yes| Text on the button.|
| type | ActionButtonType | Yes| Button type.|
**WantAgent** sets the package and ability that are redirected to when the reminder notification is clicked.
**Table 5** WantAgent
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| pkgName | string | Yes| Name of the package redirected to when the reminder notification is clicked.|
| abilityName | string | Yes| Name of the ability redirected to when the reminder notification is clicked.|
**MaxScreenWantAgent** sets the name of the target package and ability to start automatically when the reminder arrives and the device is not in use. If the device is in use, a notification will be displayed.
**Table 6** MaxScreenWantAgent
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| pkgName | string | Yes| Name of the package that is automatically started when the reminder arrives and the device is not in use.|
| abilityName | string | Yes| Name of the ability that is automatically started when the reminder arrives and the device is not in use.|
**ReminderRequest** defines the reminder to publish.
**Table 7** ReminderRequest
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| reminderType | ReminderType | Yes| Type of the reminder.|
| actionButton | [ActionButton?,ActionButton?] | No| Action button displayed in the reminder notification.|
| wantAgent | WantAgent | No| Information about the ability that is redirected to when the notification is clicked.|
| maxScreenWantAgent | MaxScreenWantAgent | No| Information about the ability that is automatically started when the reminder arrives. If the device is in use, a notification will be displayed.|
| ringDuration | number | No| Ring duration.|
| snoozeTimes | number | No| Number of reminder snooze times.|
| timeInterval | number | No| Reminder snooze interval.|
| title | string | No| Reminder title.|
| content | string | No| Reminder content.|
| expiredContent | string | No| Extended content to be displayed when the reminder expires.|
| snoozeContent | string | No| Extended content to be displayed when the reminder is snoozing.|
| notificationId | number | No| Notification ID used by the reminder. For details, see **NotificationRequest::SetNotificationId(int32_t id)**.|
| slotType | SlotType | No| Type of the slot used by the reminder. |
**ReminderRequestCalendar** extends **ReminderRequest** and defines a reminder for a calendar event.
For the application to run properly, if both **repeatMonths** and **repeatDays** are not specified, the earliest reminder time must be later than the current time.
**Table 8** ReminderRequestCalendar
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| dateTime | LocalDateTime | Yes| Reminder time, accurate to the minute.|
| repeatMonths | Array&lt;number&gt; | No| Months in which the reminder repeats. The value range is 1 to 12.|
| repeatDays | Array&lt;number&gt; | No| Date on which the reminder repeats. The value range is 1 to 31.|
**ReminderRequestAlarm** extends **ReminderRequest** and defines a reminder for the alarm clock.
**Table 9** ReminderRequestAlarm
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| hour | number | Yes| Hour portion of the reminder time. The value range is 0 to 23.|
| minute | number | Yes| Minute portion of the reminder time. The value range is 0 to 59.|
| daysOfWeek | Array&lt;number&gt; | No| Days of a week when the reminder repeats. The value range is 1 to 7.|
**ReminderRequestTimer** extends **ReminderRequest** and defines a reminder for a scheduled timer.
**Table 10** ReminderRequestTimer
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| triggerTimeInSeconds | number | Yes| Number of seconds in the countdown timer.|
**LocalDateTime** defines a **LocalDateTime** instance.
**Table 11** LocalDateTime
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| year | number | Yes| Year.|
| month | number | Yes| Month.|
| day | number | Yes| Date.|
| hour | number | Yes| Hour.|
| minute | number | Yes| Minute.|
| second | number | No| Second.|
## How to Develop ## How to Develop
> **NOTE** > **NOTE**
> >
> To publish a reminder, your application needs to apply for the **ohos.permission.PUBLISH_AGENT_REMINDER** permission. > 1. To publish a reminder through the reminder agent, your application needs to apply for the **ohos.permission.PUBLISH_AGENT_REMINDER** permission.
>
> 2. Your application must have notification enabled. For details, see [Notification.requestEnableNotification](../reference/apis/js-apis-notification.md#notificationrequestenablenotification8).
Publish a 10-second countdown reminder. 1. Define a reminder agent.
1. Define a countdown timer instance. Sample code for defining a reminder agent for a countdown timer:
``` ```js
import reminderAgent from '@ohos.reminderAgent'; import reminderAgent from '@ohos.reminderAgent';
import notification from '@ohos.notification'; import notification from '@ohos.notification';
export default { export default {
...@@ -172,8 +66,97 @@ Publish a 10-second countdown reminder. ...@@ -172,8 +66,97 @@ Publish a 10-second countdown reminder.
} }
``` ```
2. Publish the reminder. Sample code for defining a reminder agent for a calendar event:
```
```js
// For a JS project:
// calendar: {
// For an eTS project:
let calendar : reminderAgent.ReminderRequestCalendar = {
reminderType: reminderAgent.ReminderType.REMINDER_TYPE_CALENDAR,
dateTime: {
year: 2050,
month: 7,
day: 30,
hour: 11,
minute: 14,
second: 30
},
repeatMonths: [1],
repeatDays: [1],
actionButton: [
{
title: "close",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: "snooze",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
},
],
wantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
maxScreenWantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
ringDuration: 5,
snoozeTimes: 2,
timeInterval: 5,
title: "this is title",
content: "this is content",
expiredContent: "this reminder has expired",
snoozeContent: "remind later",
notificationId: 100,
slotType: notification.SlotType.SOCIAL_COMMUNICATION
}
```
Sample code for defining a reminder agent for an alarm:
```js
// For a JS project:
// alarm: {
// For an eTS project:
let alarm : reminderAgent.ReminderRequestAlarm = {
reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM,
hour: 11,
minute: 14,
daysOfWeek: [0],
actionButton: [
{
title: "close",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: "snooze",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
},
],
wantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
maxScreenWantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
ringDuration: 5,
snoozeTimes: 2,
timeInterval: 5,
title: "this is title",
content: "this is content",
expiredContent: "this reminder has expired",
snoozeContent: "remind later",
notificationId: 100,
slotType: notification.SlotType.SOCIAL_COMMUNICATION
}
```
2. Publish a countdown reminder.
```js
startTimer() { startTimer() {
reminderAgent.publishReminder(this.timer, (err, reminderId) =>{ reminderAgent.publishReminder(this.timer, (err, reminderId) =>{
this.printInfo(JSON.stringify(err)); this.printInfo(JSON.stringify(err));
...@@ -183,98 +166,9 @@ Publish a 10-second countdown reminder. ...@@ -183,98 +166,9 @@ Publish a 10-second countdown reminder.
``` ```
HML page code: HML page code:
``` ```html
<div class="container"> <div class="container">
<button type="text" value="publishReminder" onclick="startTimer"></button> <button type="text" value="publishReminder" onclick="startTimer"></button>
</div> </div>
``` ```
Sample code for defining a calendar reminder instance:
```
// For a JS project:
// calendar: {
// For an eTS project:
let calendar : reminderAgent.ReminderRequestCalendar = {
reminderType: reminderAgent.ReminderType.REMINDER_TYPE_CALENDAR,
dateTime: {
year: 2050,
month: 7,
day: 30,
hour: 11,
minute: 14,
second: 30
},
repeatMonths: [1],
repeatDays: [1],
actionButton: [
{
title: "close",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: "snooze",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
},
],
wantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
maxScreenWantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
ringDuration: 5,
snoozeTimes: 2,
timeInterval: 5,
title: "this is title",
content: "this is content",
expiredContent: "this reminder has expired",
snoozeContent: "remind later",
notificationId: 100,
slotType: notification.SlotType.SOCIAL_COMMUNICATION
}
```
Sample code for defining an alarm reminder instance:
```
// For a JS project:
// alarm: {
// For an eTS project:
let alarm : reminderAgent.ReminderRequestAlarm = {
reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM,
hour: 11,
minute: 14,
daysOfWeek: [0],
actionButton: [
{
title: "close",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: "snooze",
type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
},
],
wantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
maxScreenWantAgent: {
pkgName: "com.example.device",
abilityName: "com.example.device.MainAbility"
},
ringDuration: 5,
snoozeTimes: 2,
timeInterval: 5,
title: "this is title",
content: "this is content",
expiredContent: "this reminder has expired",
snoozeContent: "remind later",
notificationId: 100,
slotType: notification.SlotType.SOCIAL_COMMUNICATION
}
```
...@@ -28,14 +28,14 @@ System applications also support notification-related configuration options, suc ...@@ -28,14 +28,14 @@ System applications also support notification-related configuration options, suc
## Available APIs ## Available APIs
Certain APIs can be invoked only by system applications that have been granted the **SystemCapability.Notification.Notification** permission. The APIs use either a callback or promise to return the result. The tables below list the APIs that use a callback, which provide same functions as their counterparts that use a promise. For details about the APIs, see the [API document](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-notification.md). Certain APIs can be called only by system applications that have been granted the **SystemCapability.Notification.Notification** permission. The APIs use either a callback or promise to return the result. The tables below list the APIs that use a callback, which provide the same functions as their counterparts that use a promise. For details about the APIs, see the [API document](../reference/apis/js-apis-notification.md).
**Table 1** APIs for notification enabling **Table 1** APIs for notification enabling
| API | Description | | API | Description |
| ------------------------------------------------------------ | ---------------- | | ------------------------------------------------------------ | ---------------- |
| isNotificationEnabled(bundle: BundleOption, callback: AsyncCallback<boolean>): void | Checks whether notification is enabled.| | isNotificationEnabled(bundle: BundleOption, callback: AsyncCallback\<boolean>): void | Checks whether notification is enabled.|
| enableNotification(bundle: BundleOption, enable: boolean, callback: AsyncCallback<void>): void | Sets whether to enable notification. | | enableNotification(bundle: BundleOption, enable: boolean, callback: AsyncCallback\<void>): void | Sets whether to enable notification. |
If the notification function of an application is disabled, it cannot send notifications. If the notification function of an application is disabled, it cannot send notifications.
...@@ -45,11 +45,11 @@ If the notification function of an application is disabled, it cannot send notif ...@@ -45,11 +45,11 @@ If the notification function of an application is disabled, it cannot send notif
| API | Description | | API | Description |
| ------------------------------------------------------------ | ---------------- | | ------------------------------------------------------------ | ---------------- |
| subscribe(subscriber: NotificationSubscriber, info: NotificationSubscribeInfo, callback: AsyncCallback<void>): void | Subscribes to a notification with the subscription information specified.| | subscribe(subscriber: NotificationSubscriber, info: NotificationSubscribeInfo, callback: AsyncCallback\<void>): void | Subscribes to a notification with the subscription information specified.|
| subscribe(subscriber: NotificationSubscriber, callback: AsyncCallback<void>): void | Subscribes to all notifications. | | subscribe(subscriber: NotificationSubscriber, callback: AsyncCallback\<void>): void | Subscribes to all notifications. |
| unsubscribe(subscriber: NotificationSubscriber, callback: AsyncCallback<void>): void | Unsubscribes from a notification. | | unsubscribe(subscriber: NotificationSubscriber, callback: AsyncCallback\<void>): void | Unsubscribes from a notification. |
The subscription APIs support subscription to all notifications or notifications from specific applications. The subscription APIs support subscription to all notifications and notifications from specific applications.
...@@ -69,10 +69,10 @@ The subscription APIs support subscription to all notifications or notifications ...@@ -69,10 +69,10 @@ The subscription APIs support subscription to all notifications or notifications
| API | Description | | API | Description |
| ------------------------------------------------------------ | ------------------------ | | ------------------------------------------------------------ | ------------------------ |
| publish(request: NotificationRequest, callback: AsyncCallback<void>): void | Publishes a notification. | | publish(request: NotificationRequest, callback: AsyncCallback\<void>): void | Publishes a notification. |
| publish(request: NotificationRequest, userId: number, callback: AsyncCallback<void>): void | Publishes a notification to the specified user. | | publish(request: NotificationRequest, userId: number, callback: AsyncCallback\<void>): void | Publishes a notification to the specified user. |
| cancel(id: number, label: string, callback: AsyncCallback<void>): void | Cancels a specified notification. | | cancel(id: number, label: string, callback: AsyncCallback\<void>): void | Cancels a specified notification. |
| cancelAll(callback: AsyncCallback<void>): void; | Cancels all notifications published by the application.| | cancelAll(callback: AsyncCallback\<void>): void; | Cancels all notifications published by the application.|
The **publish** API that carries **userId** can be used to publish notifications to subscribers of a specified user. The **publish** API that carries **userId** can be used to publish notifications to subscribers of a specified user.
...@@ -136,7 +136,7 @@ var subscriber = { ...@@ -136,7 +136,7 @@ var subscriber = {
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. 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) => {
console.info('===>requestEnableNotification success'); console.info('===>requestEnableNotification success');
}).catch((err) => { }).catch((err) => {
console.error('===>requestEnableNotification failed because ' + JSON.stringify(err)); console.error('===>requestEnableNotification failed because ' + JSON.stringify(err));
...@@ -166,7 +166,7 @@ var notificationRequest = { ...@@ -166,7 +166,7 @@ var notificationRequest = {
} }
// Publish the notification. // Publish the notification.
Notification.publish(notificationRequest) .then((data) => { Notification.publish(notificationRequest).then((data) => {
console.info('===>publish promise success req.id : ' + notificationRequest.id); console.info('===>publish promise success req.id : ' + notificationRequest.id);
}).catch((err) => { }).catch((err) => {
console.error('===>publish promise failed because ' + JSON.stringify(err)); console.error('===>publish promise failed because ' + JSON.stringify(err));
...@@ -235,7 +235,7 @@ var notificationRequest = { ...@@ -235,7 +235,7 @@ var notificationRequest = {
} }
// Publish the notification. // Publish the notification.
Notification.publish(notificationRequest) .then((data) => { Notification.publish(notificationRequest).then((data) => {
console.info('===>publish promise success req.id : ' + notificationRequest.id); console.info('===>publish promise success req.id : ' + notificationRequest.id);
}).catch((err) => { }).catch((err) => {
console.error('===>publish promise failed because ' + JSON.stringify(err)); console.error('===>publish promise failed because ' + JSON.stringify(err));
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册