提交 00b6e797 编写于 作者: C caochuan

Merge remote-tracking branch 'docs/master' into copy

Signed-off-by: Ncaochuan <caochuan@huawei.com>

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
......@@ -18,7 +18,7 @@ This repository stores device and application development documents provided by
- master: the latest version.
- OpenHarmony 3.2 Beta5. [Learn more](en/release-notes/OpenHarmony-v3.2-beta5.md)
- OpenHarmony 3.2 Release. [Learn more](en/release-notes/OpenHarmony-v3.2-release.md)
- OpenHarmony 3.1 Release. [Learn more](en/release-notes/OpenHarmony-v3.1-release.md)
......
......@@ -24,6 +24,12 @@
- [Multi-HAP Usage Rules](quick-start/multi-hap-rules.md)
- [Multi-HAP Operation Mechanism and Data Communication Modes](quick-start/multi-hap-principles.md)
- [Application Installation and Uninstallation Process](quick-start/application-package-install-uninstall.md)
- Shared Package
- [Shared Package Overview](quick-start/shared-guide.md)
- [HAR](quick-start/har-package.md)
- HSP
- [In-Application HSP Development](quick-start/in-app-hsp.md)
- [Inter-Application HSP Development (for System Applications Only)](quick-start/cross-app-hsp.md)
- Application Configuration Files in Stage Model
- [Application Configuration File Overview (Stage Model)](quick-start/application-configuration-file-overview-stage.md)
- [app.json5 Configuration File](quick-start/app-configuration-file.md)
......@@ -36,18 +42,44 @@
- [Resource Categories and Access](quick-start/resource-categories-and-access.md)
- Learning ArkTS
- [Getting Started with ArkTS](quick-start/arkts-get-started.md)
- ArkTS Syntax (Declarative UI)
- [Basic UI Description](quick-start/arkts-basic-ui-description.md)
- State Management
- [Basic Concepts](quick-start/arkts-state-mgmt-concepts.md)
- [State Management with Page-level Variables](quick-start/arkts-state-mgmt-page-level.md)
- [State Management with Application-level Variables](quick-start/arkts-state-mgmt-application-level.md)
- [Dynamic UI Element Building](quick-start/arkts-dynamic-ui-elememt-building.md)
- [Rendering Control](quick-start/arkts-rendering-control.md)
- [Restrictions and Extensions](quick-start/arkts-restrictions-and-extensions.md)
- Basic Syntax
- [Basic Syntax Overview](quick-start/arkts-basic-syntax-overview.md)
- [Declarative UI Description](quick-start/arkts-declarative-ui-description.md)
- Custom Component
- [Creating a Custom Component](quick-start/arkts-create-custom-components.md)
- [Page and Custom Component Lifecycle](quick-start/arkts-page-custom-components-lifecycle.md)
- [\@Builder: Custom Builder Function](quick-start/arkts-builder.md)
- [\@BuilderParam: @Builder Function Reference](quick-start/arkts-builderparam.md)
- [\@Styles: Definition of Resusable Styles](quick-start/arkts-style.md)
- [\@Extend: Extension of Built-in Components](quick-start/arkts-extend.md)
- [stateStyles: Polymorphic Style](quick-start/arkts-statestyles.md)
- State Management
- [State Management Overview](quick-start/arkts-state-management-overview.md)
- Component State Management
- [\@State: State Owned by Component](quick-start/arkts-state.md)
- [\@Prop: One-Way Synchronization from Parent to Child Components](quick-start/arkts-prop.md)
- [\@Link: Two-Way Synchronization Between Parent and Child Components](quick-start/arkts-link.md)
- [\@Provide and \@Consume: Two-Way Synchronization with Descendant Components](quick-start/arkts-provide-and-consume.md)
- [\@Observed and \@ObjectLink: Observing Attribute Changes in Nested Class Objects](quick-start/arkts-observed-and-objectlink.md)
- Application State Management
- [Application State Management Overview](quick-start/arkts-application-state-management-overview.md)
- [LocalStorage: UI State Storage](quick-start/arkts-localstorage.md)
- [AppStorage: Application-wide UI State Storage](quick-start/arkts-appstorage.md)
- [PersistentStorage: Application State Persistence](quick-start/arkts-persiststorage.md)
- [Environment: Device Environment Query](quick-start/arkts-environment.md)
- Other State Management Features
- [Overview of Other State Management Features](quick-start/arkts-other-state-mgmt-functions-overview.md)
- [\@Watch: Getting Notified of State Variable Changes](quick-start/arkts-watch.md)
- [$$ Syntax: Two-Way Synchronization of Built-in Components](quick-start/arkts-two-way-sync.md)
- Rendering Control
- [Rendering Control Overview](quick-start/arkts-rendering-control-overview.md)
- [if/else: Conditional Rendering](quick-start/arkts-rendering-control-ifelse.md)
- [ForEach: Rendering of Repeated Content](quick-start/arkts-rendering-control-foreach.md)
- [LazyForEach: Lazy Data Loading](quick-start/arkts-rendering-control-lazyforeach.md)
- Development
- [Application Models](application-models/Readme-EN.md)
- [UI Development](ui/Readme-EN.md)
- [Web](web/Readme-EN.md)
- [Notification](notification/Readme-EN.md)
- [Window Manager](windowmanager/Readme-EN.md)
- [WebGL](webgl/Readme-EN.md)
......@@ -81,8 +113,10 @@
- [ArkTS and JS APIs](reference/apis/Readme-EN.md)
- [Error Codes](reference/errorcodes/Readme-EN.md)
- Native APIs
- [Native APIs](reference/native-apis/Readme-EN.md)
- [Standard Libraries](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md)
- [FAQs](faqs/Readme-EN.md)
- Contribution
- [How to Contribute](../contribute/documentation-contribution.md)
<!--no_check-->
\ No newline at end of file
......@@ -17,11 +17,35 @@
- ExtensionAbility Component
- [ExtensionAbility Component Overview](extensionability-overview.md)
- [ServiceExtensionAbility](serviceextensionability.md)
- [FormExtensionAbility (Widget)](widget-development-stage.md)
- [AccessibilityExtensionAbility](accessibilityextensionability.md)
- [EnterpriseAdminExtensionAbility](enterprise-extensionAbility.md)
- [InputMethodExtensionAbility](inputmethodextentionability.md)
- [WindowExtensionAbility](windowextensionability.md)
- Service Widget Development in Stage Model
- [Service Widget Overview](service-widget-overview.md)
- Developing an ArkTS Widget
- [ArkTS Widget Working Principles](arkts-ui-widget-working-principles.md)
- [ArkTS Widget Related Modules](arkts-ui-widget-modules.md)
- ArkTS Widget Development
- [Creating an ArkTS Widget](arkts-ui-widget-creation.md)
- [Configuring Widget Configuration Files](arkts-ui-widget-configuration.md)
- [Widget Lifecycle Management](arkts-ui-widget-lifecycle.md)
- Widget Page Development
- [Widget Page Capability Overview](arkts-ui-widget-page-overview.md)
- [Using Animations in the Widget](arkts-ui-widget-page-animation.md)
- [Applying Custom Drawing in the Widget](arkts-ui-widget-page-custom-drawing.md)
- Widget Event Development
- [Widget Event Capability Overview](arkts-ui-widget-event-overview.md)
- [Redirecting to a Specified Page Through the Router Event](arkts-ui-widget-event-router.md)
- [Updating Widget Content Through FormExtensionAbility](arkts-ui-widget-event-formextensionability.md)
- [Updating Widget Content Through UIAbility](arkts-ui-widget-event-uiability.md)
- Widget Data Interaction
- [Widget Data Interaction Overview](arkts-ui-widget-interaction-overview.md)
- [Configuring a Widget to Update Periodically](arkts-ui-widget-update-by-time.md)
- [Updating Local and Online Images in the Widget](arkts-ui-widget-image-update.md)
- [Updating Widget Content by State](arkts-ui-widget-update-by-status.md)
- [Updating Widget Content by Widget Host (for System Applications Only)](arkts-ui-widget-content-update.md)
- [Developing a JS Widget](js-ui-widget-development.md)
- [AbilityStage Component Container](abilitystage.md)
- [Context](application-context-stage.md)
- Want
......@@ -37,8 +61,8 @@
- [Cross-Device Migration (for System Applications Only)](hop-cross-device-migration.md)
- [Multi-device Collaboration (for System Applications Only)](hop-multi-device-collaboration.md)
- [Subscribing to System Environment Variable Changes](subscribe-system-environment-variable-changes.md)
- IPC
- [Process Model](process-model-stage.md)
- Process Model
- [Process Model Overview](process-model-stage.md)
- Common Events
- [Introduction to Common Events](common-event-overview.md)
- Common Event Subscription
......@@ -47,14 +71,15 @@
- [Subscribing to Common Events in Static Mode (for System Applications Only)](common-event-static-subscription.md)
- [Unsubscribing from Common Events](common-event-unsubscription.md)
- [Publishing Common Events](common-event-publish.md)
- [Removing Sticky Common Events](common-event-remove-sticky.md)
- [Background Services](background-services.md)
- Inter-Thread Communication
- [Thread Model](thread-model-stage.md)
- Thread Model
- [Thread Model Overview](thread-model-stage.md)
- [Using Emitter for Inter-Thread Communication](itc-with-emitter.md)
- [Using Worker for Inter-Thread Communication](itc-with-worker.md)
- Mission Management
- [Mission Management Scenarios](mission-management-overview.md)
- [Mission Management and Launch Type](mission-management-launch-type.md)
- [Mission and Launch Type](mission-management-launch-type.md)
- [Page Stack and MissionList](page-mission-stack.md)
- [Setting the Icon and Name of a Mission Snapshot](mission-set-icon-name-for-task-snapshot.md)
- [Application Configuration File](config-file-stage.md)
......@@ -94,12 +119,12 @@
- [Context](application-context-fa.md)
- [Want](want-fa.md)
- [Component Startup Rules](component-startup-rules-fa.md)
- IPC
- [Process Model](process-model-fa.md)
- Process Model
- [Process Model Overview](process-model-fa.md)
- [Common Events](common-event-fa.md)
- [Background Services](rpc.md)
- Inter-Thread Communication
- [Thread Model](thread-model-fa.md)
- Thread Model
- [Thread Model Overview](thread-model-fa.md)
- [Inter-Thread Communication](itc-fa-overview.md)
- [Mission Management](mission-management-fa.md)
- [Application Configuration File](config-file-fa.md)
......
......@@ -12,7 +12,7 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **myabilitystage**.
2. In the **myabilitystage** directory, right-click and choose **New > ts File** to create a file named **MyAbilityStage.ts**.
2. In the **myabilitystage** directory, right-click and choose **New > TypeScript File** to create a file named **MyAbilityStage.ts**.
3. Open the **MyAbilityStage.ts** file, and import the dependency package of AbilityStage. Customize a class that inherits from AbilityStage, and add the required lifecycle callbacks. The following code snippet adds the **onCreate()** lifecycle callback.
......@@ -20,17 +20,17 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
import AbilityStage from '@ohos.app.ability.AbilityStage';
export default class MyAbilityStage extends AbilityStage {
onCreate() {
// When the HAP of the application is loaded for the first time, initialize the module.
}
onAcceptWant(want) {
// Triggered only for the ability with the specified launch type.
return "MyAbilityStage";
}
onCreate() {
// When the HAP of the application is loaded for the first time, initialize the module.
}
onAcceptWant(want) {
// Triggered only for the ability with the specified launch type.
return "MyAbilityStage";
}
}
```
4. Set **srcEntry** in the [module.json5 file](../quick-start/module-configuration-file.md) to the code path of the module.
4. In the [module.json5 file](../quick-start/module-configuration-file.md), set **srcEntry** to specify the code path of the module as the entry for loading the HAP.
```json
{
"module": {
......@@ -42,7 +42,6 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
}
```
[AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md) has the lifecycle callback [onCreate()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageoncreate) and the event callbacks [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant), [onConfigurationUpdated()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonconfigurationupdate), and [onMemoryLevel()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonmemorylevel).
......@@ -53,7 +52,6 @@ AbilityStage is not automatically generated in the default project of DevEco Stu
- **onConfigurationUpdated()** event callback: triggered when the global system configuration changes. The global system configuration, such as the system language and theme, are defined in the [Configuration](../reference/apis/js-apis-app-ability-configuration.md) class before project configuration.
- **onMemoryLevel()** event callback: triggered when the system adjusts the memory.
When an application is switched to the background, it is cached in the background. This adversely affects the overall system performance. When system resources are insufficient, the system reclaims memory from applications in multiple ways. For example, the system may stop applications to release memory for executing key tasks. To further maintain the balance of the system memory and prevent the system from stopping application processes, you can subscribe to the system memory changes in the **onMemoryLevel()** lifecycle callback of AbilityStage to release unnecessary resources.
......@@ -62,8 +60,8 @@ When an application is switched to the background, it is cached in the backgroun
import AbilityStage from '@ohos.app.ability.AbilityStage';
export default class MyAbilityStage extends AbilityStage {
onMemoryLevel(level) {
// Release unnecessary memory based on the change of available system memory.
}
onMemoryLevel(level) {
// Release unnecessary memory based on the change of available system memory.
}
}
```
......@@ -12,10 +12,13 @@ The **AccessibilityExtensionAbility** module provides accessibility extension ca
This document is organized as follows:
- [Creating an AccessibilityExtAbility File](#creating-an-accessibility-extension-service)
- [Processing an Accessibility Event](#processing-an-accessibility-event)
- [Declaring Capabilities of Accessibility Extension Services](#declaring-capabilities-of-accessibility-extension-services)
- [Enabling a Custom Accessibility Extension Service](#enabling-a-custom-accessibility-extension-service)
- [AccessibilityExtensionAbility Development](#accessibilityextensionability-development)
- [Creating an Accessibility Extension Service](#creating-an-accessibility-extension-service)
- [Creating a Project](#creating-a-project)
- [Creating an AccessibilityExtAbility File](#creating-an-accessibilityextability-file)
- [Processing an Accessibility Event](#processing-an-accessibility-event)
- [Declaring Capabilities of Accessibility Extension Services](#declaring-capabilities-of-accessibility-extension-services)
- [Enabling a Custom Accessibility Extension Service](#enabling-a-custom-accessibility-extension-service)
## Creating an Accessibility Extension Service
......@@ -79,13 +82,13 @@ You can also process physical key events in the accessibility extension service.
## Declaring Capabilities of Accessibility Extension Services
After developing the custom logic for an accessibility extension service, you must add the configuration information of the service to the corresponding module-level **module.json5** file in the project directory. In the file, the **srcEntrance** tag indicates the path to the accessibility extension service. Make sure the value of the **type** tag is fixed at **accessibility**. Otherwise, the connection to the service will fail.
After developing the custom logic for an accessibility extension service, you must add the configuration information of the service to the corresponding module-level **module.json5** file in the project directory. In the file, the **srcEntry** tag indicates the path to the accessibility extension service. Make sure the value of the **type** tag is fixed at **accessibility**. Otherwise, the connection to the service will fail.
```json
"extensionAbilities": [
{
"name": "AccessibilityExtAbility",
"srcEntrance": "./ets/AccessibilityExtAbility/AccessibilityExtAbility.ts",
"srcEntry": "./ets/AccessibilityExtAbility/AccessibilityExtAbility.ts",
"label": "$string:MainAbility_label",
"description": "$string:MainAbility_desc",
"type": "accessibility",
......
......@@ -3,7 +3,7 @@
## Overview
[Context](../reference/apis/js-apis-inner-application-context.md) is the context of an object in an application. It provides basic information about the application, for example, **resourceManager**, **applicationInfo**, **dir** (application development path), and **area** (encrypted area). It also provides basic methods such as **createBundleContext()** and **getApplicationContext()**. The UIAbility component and ExtensionAbility derived class components have their own **Context** classes, for example, the base class **Context**, **ApplicationContext**, **AbilityStageContext**, **UIAbilityContext**, **ExtensionContext**, and **ServiceExtensionContext**.
[Context](../reference/apis/js-apis-inner-application-context.md) is the context of an object in an application. It provides basic information about the application, for example, **resourceManager**, **applicationInfo**, **dir** (application development path), and **area** (encryption level). It also provides basic methods such as **createBundleContext()** and **getApplicationContext()**. The UIAbility component and ExtensionAbility derived class components have their own **Context** classes, for example, the base class **Context**, **ApplicationContext**, **AbilityStageContext**, **UIAbilityContext**, **ExtensionContext**, and **ServiceExtensionContext**.
- The figure below illustrates the inheritance relationship of contexts.
......@@ -71,7 +71,7 @@ This topic describes how to use the context in the following scenarios:
- [Obtaining the Application Development Path](#obtaining-the-application-development-path)
- [Obtaining and Modifying Encryption Areas](#obtaining-and-modifying-encryption-areas)
- [Obtaining and Modifying Encryption Levels](#obtaining-and-modifying-encryption-levels)
- [Creating Context of Another Application or Module](#creating-context-of-another-application-or-module)
- [Subscribing to UIAbility Lifecycle Changes in a Process](#subscribing-to-uiability-lifecycle-changes-in-a-process)
......@@ -84,7 +84,7 @@ The following table describes the application development paths obtained from co
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| bundleCodeDir | string | Yes | No | Path for storing the application's installation package, that is, installation directory of the application on the internal storage. |
| bundleCodeDir | string | Yes | No | Path for storing the application's installation package, that is, installation directory of the application on the internal storage. Do not access resource files by concatenating paths. Use [@ohos.resourceManager] instead. |
| cacheDir | string | Yes| No| Path for storing the application's cache files, that is, cache directory of the application on the internal storage.<br>It is the content of **Storage** of an application under **Settings > Apps & services > Apps**.|
| filesDir | string | Yes | No | Path for storing the application's common files, that is, file directory of the application on the internal storage.<br>Files in this directory may be synchronized to other directories during application migration or backup.|
| preferencesDir | string | Yes | Yes | Path for storing the application's preference files, that is, preferences directory of the application. |
......@@ -144,19 +144,19 @@ export default class EntryAbility extends UIAbility {
>
> The sample code obtains the sandbox path of the application development path. The absolute path can be obtained by running the **find / -name <fileName>** command in the hdc shell after file creation or modification.
### Obtaining and Modifying Encryption Areas
### Obtaining and Modifying Encryption Levels
Encrypting application files enhances data security by preventing files from unauthorized access. Different application files require different levels of protection. For private files, such as alarms and wallpapers, the application must place them in the device-level encryption area (EL1) to ensure that they can be accessed before the user enters the password. For sensitive files, such as personal privacy data, the application must place them in the user-level encryption area (EL2).
Encrypting application files enhances data security by preventing files from unauthorized access. Different application files require different levels of protection. For private files, such as alarms and wallpapers, the application must place them in a directory with the device-level encryption (EL1) to ensure that they can be accessed before the user enters the password. For sensitive files, such as personal privacy data, the application must place them in a directory with the user-level encryption (EL2).
In practice, you need to select a proper encrypted area based on scenario-specific requirements to protect application data security. The proper use of EL1 and the EL2 can efficiently improve the security.
In practice, you need to select a proper encryption level based on scenario-specific requirements to protect application data security. The proper use of EL1 and the EL2 can efficiently improve the security.
> **NOTE**
>
> - AreaMode.EL1: device-level encryption area, which is accessible after the device is powered on.
> - AreaMode.EL1: device-level encryption. Directories with this encryption level are accessible after the device is powered on.
>
> - AreaMode.EL2: user-level encryption area, which is accessible only after the device is powered on and the password is entered (for the first time).
> - AreaMode.EL2: user-level encryption. Directories with this encryption level are accessible only after the device is powered on and the password is entered (for the first time).
You can obtain and set the encryption area by reading and writing the [area attribute in Context](../reference/apis/js-apis-inner-application-context.md).
You can obtain and set the encryption level by reading and writing the [area attribute in Context](../reference/apis/js-apis-inner-application-context.md).
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -187,13 +187,13 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../
> **NOTE**
>
> To obtain the context of another application:
>
>
> - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
>
>
> - This is a system API and cannot be called by third-party applications.
For example, application information displayed on the home screen includes the application name and icon. The home screen application calls the foregoing method to obtain the context information, so as to obtain the resource information including the application name and icon.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -248,7 +248,7 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../
In the DFX statistics scenario of an application, if you need to collect statistics on the stay duration and access frequency of a page, you can subscribe to UIAbility lifecycle changes in a process.
[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example.
[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext.md) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example.
```ts
......
# Configuring Widget Configuration Files
Widget-related configuration includes **FormExtensionAbility** configuration and widget configuration.
1. Configure FormExtensionAbility information under **extensionAbilities** in the [module.json5 file](../quick-start/module-configuration-file.md). For a FormExtensionAbility, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information.
Example configuration:
```json
{
"module": {
...
"extensionAbilities": [
{
"name": "EntryFormAbility",
"srcEntry": "./ets/entryformability/EntryFormAbility.ts",
"label": "$string:EntryFormAbility_label",
"description": "$string:EntryFormAbility_desc",
"type": "form",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
}
```
2. Configure the widget configuration information. In the **metadata** configuration item of FormExtensionAbility, you can specify the resource index of specific configuration information of the widget. For example, if resource is set to **$profile:form_config**, **form_config.json** in the **resources/base/profile/** directory of the development view is used as the profile configuration file of the widget. The following table describes the internal field structure.
**Table 1** form_config.json file
| Field| Description| Data Type| Default Value Allowed|
| -------- | -------- | -------- | -------- |
| name | Class name of the widget. The value is a string with a maximum of 127 bytes.| String| No|
| description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String| Yes (initial value: left empty)|
| src | Full path of the UI code corresponding to the widget. For an ArkTS widget, the full path must contain the widget file name extension, for example, **./ets/widget/pages/WidgetCard.ets**. For a JS widget, the full path does not need to contain the widget file name extension, for example, **./js/widget/pages/WidgetCard**.| String| No|
| uiSyntax | Type of the widget.<br>- **arkts**: ArkTS widget<br>- **hml**: JS widget| String| Yes (initial value: **hml**)|
| window | Window-related configurations.| Object| Yes|
| isDefault | Whether the widget is a default one. Each UIAbility has only one default widget.<br>- **true**: The widget is the default one.<br>- **false**: The widget is not the default one.| Boolean| No|
| colorMode | Color mode of the widget.<br>- **auto**: auto-adaptive color mode<br>- **dark**: dark color mode<br>- **light**: light color mode| String| Yes (initial value: **auto**)|
| supportDimensions | Grid styles supported by the widget.<br>- **1 * 2**: indicates a grid with one row and two columns.<br>- **2 * 2**: indicates a grid with two rows and two columns.<br>- **2 * 4**: indicates a grid with two rows and four columns.<br>- **4 * 4**: indicates a grid with four rows and four columns.| String array| No|
| defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String| No|
| updateEnabled | Whether the widget can be updated periodically.<br>- **true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.<br>- **false**: The widget cannot be updated periodically.| Boolean| No|
| scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.<br>**NOTE**<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| String| Yes (initial value: The widget cannot be updated periodically.)|
| 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>**NOTE**<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number| Yes (initial value: **0**)|
| formConfigAbility | Link to a specific page of the application. The value is a URI.| String| Yes (initial value: left empty)|
| formVisibleNotify | Whether the widget is allowed to use the widget visibility notification.| String| Yes (initial value: left empty)|
| metadata | Metadata of the widget. This field contains the array of the **customizeData** field.| Object| Yes (initial value: left empty)|
Example configuration:
```json
{
"forms": [
{
"name": "widget",
"description": "This is a service widget.",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDefault": true,
"updateEnabled": true,
"scheduledUpdateTime": "10:30",
"updateDuration": 1,
"defaultDimension": "2*2",
"supportDimensions": [
"2*2"
]
}
]
}
```
# Updating Widget Content by Widget Host (for System Applications Only)
Widgets that are updated periodically are subject to the scheduled time or interval settings. To offer more flexible updates, the widget host can provide a button to proactively trigger a widget update. Specifically, the widget host calls the [requestForm](../reference/apis/js-apis-app-form-formHost.md#requestform) API to request a widget update. The system then calls the [onUpdateForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onupdateform) lifecycle callback in the FormExtensionAbility of the widget provider. In the callback, the [updateForm](../reference/apis/js-apis-app-form-formProvider.md#updateform) API can be used to update the widget content. For details about the **onUpdateForm** lifecycle callback, see [Updating Widget Content Through FormExtensionAbility](arkts-ui-widget-event-formextensionability.md).
```ts
import formHost from '@ohos.app.form.formHost';
@Entry()
@Component
struct WidgetCard {
formId = ...; // Widget ID
build() {
Button (`Update Widget`)
.type(ButtonType.Capsule)
.width('50%')
.height(50)
.onClick(() => {
console.info('FormAbility update form click');
// formId is the ID of the widget to be updated.
formHost.requestForm(this.formId.toString()).then(() => {
console.info('Succeeded in requestForming.');
});
})
...
}
}
```
# Creating an ArkTS Widget
To create an ArkTS widget in an existing application project, perform the following steps:
1. Create a widget.
![WidgetProjectCreate1](figures/WidgetProjectCreate1.png)
2. Select a widget template based on the actual service scenario.
![WidgetProjectCreate2](figures/WidgetProjectCreate2.png)
3. Set **Language** to **ArkTS** and click **Finish**.
![WidgetProjectCreate3](figures/WidgetProjectCreate3.png)
After an ArkTS widget is created, the following widget-related files are added to the project directory: **EntryFormAbility.ts** (widget lifecycle management file), **WidgetCard.ets** (widget page file), and **form_config.json** (widget configuration file).
![WidgetProjectView](figures/WidgetProjectView.png)
# Updating Widget Content Through FormExtensionAbility
On the widget page, the **postCardAction** API can be used to trigger a message event to the FormExtensionAbility, which then updates the widget content. The following is an example of this widget update mode.
- On the widget page, register the **onClick** event callback of the button and call the **postCardAction** API in the callback to trigger the event to the FormExtensionAbility.
```ts
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('title') title: string = 'init';
@LocalStorageProp('detail') detail: string = 'init';
build() {
Column() {
Button ('Update')
.onClick(() => {
postCardAction(this, {
'action': 'message',
'params': {
'msgTest': 'messageEvent'
}
});
})
Text(`${this.title}`)
Text(`${this.detail}`)
}
.width('100%')
.height('100%')
}
}
```
- Call the [updateForm](../reference/apis/js-apis-app-form-formProvider.md#updateform) API to update the widget in the **onFormEvent** callback of the FormExtensionAbility.
```ts
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import formProvider from '@ohos.app.form.formProvider';
export default class EntryFormAbility extends FormExtensionAbility {
onFormEvent(formId, message) {
// Called when a specified message event defined by the form provider is triggered.
console.info(`FormAbility onEvent, formId = ${formId}, message: ${JSON.stringify(message)}`);
let formData = {
'title':'Title Update Success.', // Matches the widget layout.
'detail':'Detail Update Success.', // Matches the widget layout.
};
let formInfo = formBindingData.createFormBindingData(formData)
formProvider.updateForm(formId, formInfo).then((data) => {
console.info('FormAbility updateForm success.' + JSON.stringify(data));
}).catch((error) => {
console.error('FormAbility updateForm failed: ' + JSON.stringify(error));
})
}
// ...
}
```
The figure below shows the effect.
![WidgetUpdatePage](figures/WidgetUpdatePage.png)
# Widget Event Capability Overview
The ArkTS widget provides the **postCardAction()** API for interaction between the widget internal and the provider application. Currently, this API supports the router, message, and call events and can be called only in the widget.
![WidgetPostCardAction](figures/WidgetPostCardAction.png)
Definition: postCardAction(component: Object, action: Object): void
Parameters:
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| component | Object | Yes| Instance of the current custom component. Generally, **this** is transferred.|
| action | Object | Yes| Action description. For details, see the following table.|
Description of the action parameter
| **Key** | **Value** | Description|
| -------- | -------- | -------- |
| "action" | string | Action type.<br>- **"router"**: application redirection. If this type of action is triggered, the corresponding UIAbility is displayed. Only the UIAbility of the current application can be displayed.<br>- **"message"**: custom message. If this type of action is triggered, the [onFormEvent()](../reference/apis/js-apis-app-form-formExtensionAbility.md#onformevent) lifecycle callback of the provider FormExtensionAbility is called.<br>- **"call"**: application startup in the background. If this type of action is triggered, the corresponding UIAbility is started but does not run in the foreground. The target application must have the permission to run in the background ([ohos.permission.KEEP_BACKGROUND_RUNNING](../security/permission-list.md#ohospermissionkeep_background_running)).|
| "bundleName" | string | Name of the target bundle when **action** is **"router"** or **"call"**. This parameter is optional.|
| "moduleName" | string | Name of the target module when **action** is **"router"** or **"call"**. This parameter is optional.|
| "abilityName" | string | Name of the target UIAbility when **action** is **"router"** or **"call"**. This parameter is mandatory.|
| "params" | Object | Additional parameters carried in the current action. The value is a key-value pair in JSON format.|
Sample code of the **postCardAction()** API:
```typescript
Button ('Jump')
.width('40%')
.height('20%')
.onClick(() => {
postCardAction(this, {
'action': 'router',
'bundleName': 'com.example.myapplication',
'abilityName': 'EntryAbility',
'params': {
'message': 'testForRouter' // Customize the message to be sent.
}
});
})
```
The following are typical widget development scenarios that can be implemented through widget events:
- [Updating Widget Content Through FormExtensionAbility](arkts-ui-widget-event-formextensionability.md)
- [Updating Widget Content Through UIAbility](arkts-ui-widget-event-uiability.md)
- [Redirecting to a Specified Page Through the Router Event](arkts-ui-widget-event-router.md)
# Redirecting to a Specified Page Through the Router Event
The **router** capability of the **postCardAction** API can be used in a widget to quickly start the widget provider application. An application can provide different buttons through the widget so that users can jump to different pages at the touch of a button. For example, a camera widget provides the buttons that direct the user to respective pages, such as the page for taking a photo and the page for recording a video.
![WidgerCameraCard](figures/WidgerCameraCard.png)
Generally, a button is used to start a page.
- Design two buttons on the widget page. When one of the buttons is clicked, **postCardAction** is called to send a router event to the specified UIAbility, with the content to be transferred defined in the event.
```ts
@Entry
@Component
struct WidgetCard {
build() {
Column() {
Button ('Function A')
.margin('20%')
.onClick(() => {
console.info('Jump to EntryAbility funA');
postCardAction(this, {
'action': 'router',
'abilityName': 'EntryAbility', // Only the UIAbility of the current application is allowed.
'params': {
'targetPage': 'funA' // Process the information in the EntryAbility.
}
});
})
Button ('Function B')
.margin('20%')
.onClick(() => {
console.info('Jump to EntryAbility funB');
postCardAction(this, {
'action': 'router',
'abilityName': 'EntryAbility', // Only the UIAbility of the current application is allowed.
'params': {
'targetPage': 'funB' // Process the information in the EntryAbility.
}
});
})
}
.width('100%')
.height('100%')
}
}
```
- The UIAbility receives the router event and obtains parameters. It then starts the page specified in the received message.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
let selectPage = "";
let currentWindowStage = null;
export default class CameraAbility extends UIAbility {
// If the UIAbility is started for the first time, the onCreate lifecycle callback is triggered after the router event is received.
onCreate(want, launchParam) {
// Obtain the targetPage parameter passed in the router event.
console.info("onCreate want:" + JSON.stringify(want));
if (want.parameters.params !== undefined) {
let params = JSON.parse(want.parameters.params);
console.info("onCreate router targetPage:" + params.targetPage);
selectPage = params.targetPage;
}
}
// If the UIAbility is running in the background, the onNewWant lifecycle callback is triggered after the router event is received.
onNewWant(want, launchParam) {
console.info("onNewWant want:" + JSON.stringify(want));
if (want.parameters.params !== undefined) {
let params = JSON.parse(want.parameters.params);
console.info("onNewWant router targetPage:" + params.targetPage);
selectPage = params.targetPage;
}
if (currentWindowStage != null) {
this.onWindowStageCreate(currentWindowStage);
}
}
onWindowStageCreate(windowStage: window.WindowStage) {
let targetPage;
// Start the page specified by targetPage.
switch (selectPage) {
case 'funA':
targetPage = 'pages/FunA';
break;
case 'funB':
targetPage = 'pages/FunB';
break;
default:
targetPage = 'pages/Index';
}
if (currentWindowStage === null) {
currentWindowStage = windowStage;
}
windowStage.loadContent(targetPage, (err, data) => {
if (err && err.code) {
console.info('Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
});
}
};
```
# Updating Widget Content Through UIAbility
On the widget page, the **postCardAction** API can be used to trigger a router or call event to start the UIAbility, which then updates the widget content. The following is an example of this widget update mode.
- On the widget page, register the **onClick** event callback of the button and call the **postCardAction** API in the callback to trigger the event to the FormExtensionAbility.
```ts
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('detail') detail: string = 'init';
build() {
Column() {
Button ('Jump')
.margin('20%')
.onClick(() => {
console.info('postCardAction to EntryAbility');
postCardAction(this, {
'action': 'router',
'abilityName': 'EntryAbility', // Only the UIAbility of the current application is allowed.
'params': {
'detail': 'RouterFromCard'
}
});
})
Text(`${this.detail}`).margin('20%')
}
.width('100%')
.height('100%')
}
}
```
- In the **onCreate()** or **onNewWant()** lifecycle callback of the UIAbility, use the input parameter **want** to obtain the ID (**formID**) and other information of the widget, and then call the [updateForm](../reference/apis/js-apis-app-form-formProvider.md#updateform) API to update the widget.
```ts
import UIAbility from '@ohos.app.ability.UIAbility';
import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import formInfo from '@ohos.app.form.formInfo';
export default class EntryAbility extends UIAbility {
// If the UIAbility is started for the first time, the onCreate lifecycle callback is triggered after the router event is received.
onCreate(want, launchParam) {
console.info('Want:' + JSON.stringify(want));
if (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
let message = JSON.parse(want.parameters.params).detail;
console.info(`UpdateForm formId: ${curFormId}, message: ${message}`);
let formData = {
"detail": message +': onCreate UIAbility.', // Matches the widget layout.
};
let formMsg = formBindingData.createFormBindingData(formData)
formProvider.updateForm(curFormId, formMsg).then((data) => {
console.info('updateForm success.' + JSON.stringify(data));
}).catch((error) => {
console.error('updateForm failed:' + JSON.stringify(error));
})
}
}
// If the UIAbility is running in the background, the onNewWant lifecycle callback is triggered after the router event is received.
onNewWant(want, launchParam) {
console.info('onNewWant Want:' + JSON.stringify(want));
if (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
let message = JSON.parse(want.parameters.params).detail;
console.info(`UpdateForm formId: ${curFormId}, message: ${message}`);
let formData = {
"detail": message +': onNewWant UIAbility.', // Matches the widget layout.
};
let formMsg = formBindingData.createFormBindingData(formData)
formProvider.updateForm(curFormId, formMsg).then((data) => {
console.info('updateForm success.' + JSON.stringify(data));
}).catch((error) => {
console.error('updateForm failed:' + JSON.stringify(error));
})
}
}
...
}
```
# Updating Local and Online Images in the Widget
Generally, local images or online images downloaded from the network need to be displayed on a widget. To obtain local and online images, use the FormExtensionAbility. The following exemplifies how to show local and online images on a widget.
1. Internet access is required for downloading online images. Therefore, you need to apply for the **ohos.permission.INTERNET** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md).
2. Update local files in the **onAddForm** lifecycle callback of the EntryFormAbility.
```ts
import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';
export default class EntryFormAbility extends FormExtensionAbility {
...
// When the widget is added, a local image is opened and transferred to the widget page for display.
onAddForm(want) {
// Assume that the local image head.PNG is in the tmp directory of the current widget.
let tempDir = this.context.getApplicationContext().tempDir;
// Open the local image and obtain the FD after the image is opened.
let file;
try {
file = fs.openSync(tempDir + '/' + 'head.PNG');
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e)}`);
}
let formData = {
'text': 'Image: Bear',
'imgName': 'imgBear',
'formImages': {
'imgBear': file.fd
},
'loaded': true
}
// Encapsulate the FD in formData and return it to the widget page.
return formBindingData.createFormBindingData(formData);
}
...
}
```
3. Update online files in the onFormEvent lifecycle callback of the EntryFormAbility.
```ts
import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';
export default class EntryFormAbility extends FormExtensionAbility {
// When the message event is triggered on the widget page, an online image is downloaded and transferred to the widget page for display.
onFormEvent(formId, message) {
let formInfo = formBindingData.createFormBindingData({
'text': 'Updating...'
})
formProvider.updateForm(formId, formInfo)
// Note: The FormExtensionAbility is started when the lifecycle callback is triggered. It can run in the background for only 5 seconds.
// When possible, limit the size of the image to download. If an image cannot be downloaded within 5 seconds, it cannot be updated to the widget page.
let netFile = 'https://xxxx/xxxx.png'; // Specify the URL of the image to download.
let tempDir = this.context.getApplicationContext().tempDir;
let fileName = 'file' + Date.now();
let tmpFile = tempDir + '/' + fileName;
request.downloadFile(this.context, {
url: netFile, filePath: tmpFile, enableMetered: true, enableRoaming: true
}).then((task) => {
task.on('complete', function callback() {
console.info('ArkTSCard download complete:' + tmpFile);
let file;
try {
file = fs.openSync(tmpFile);
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e)}`);
}
let fileInfo = {};
fileInfo[fileName] = file.fd;
let formData = {
'text': 'Image:' + fileName,
'imgName': fileName,
'formImages': fileInfo,
'loaded': true
};
let formInfo = formBindingData.createFormBindingData(formData)
formProvider.updateForm(formId, formInfo).then((data) => {
console.info('FormAbility updateForm success.' + JSON.stringify(data));
}).catch((error) => {
console.error('FormAbility updateForm failed: ' + JSON.stringify(error));
})
})
task.on('fail', function callBack(err) {
console.info('ArkTSCard download task failed. Cause:' + err);
let formInfo = formBindingData.createFormBindingData({
'text':'Update failed.'
})
formProvider.updateForm(formId, formInfo)
});
}).catch((err) => {
console.error('Failed to request the download. Cause: ' + JSON.stringify(err));
});
}
...
};
```
4. On the widget page, use the **\<Image>** component to display the widget content transferred from the EntryFormAbility.
```ts
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('text') text: string = 'Loading...';
@LocalStorageProp('loaded') loaded: boolean = false;
@LocalStorageProp('imgName') imgName: string = 'name';
build() {
Column() {
Text(this.text)
.fontSize('12vp')
.textAlign(TextAlign.Center)
.width('100%')
.height('15%')
Row() {
if (this.loaded) {
Image('memory://' + this.imgName)
.width('50%')
.height('50%')
.margin('5%')
} else {
Image('common/start.PNG')
.width('50%')
.height('50%')
.margin('5%')
}
}.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
Button ('Update')
.height('15%')
.onClick(() => {
postCardAction(this, {
'action': 'message',
'params': {
'info': 'refreshImage'
}
});
})
}
.width('100%').height('100%')
.alignItems(HorizontalAlign.Center)
.padding('5%')
}
}
```
> **NOTE**
> - The **\<Image>** component displays images in the remote memory based on the **memory://** identifier in the input parameter (**memory://fileName**). The **fileName** value must be consistent with the key in the object (**'formImages': {key: fd}**) passed by the EntryFormAbility.
>
> - The **\<Image>** component determines whether to update the image based on whether the input parameter is changed. Therefore, the value of **imgName** passed by the EntryFormAbility each time must be different. If the two values of **imgName** passed consecutively are identical, the image is not updated.
# Widget Data Interaction
The ArkTS widget framework provides the **updateForm()** and **requestForm()** APIs to proactively trigger widget updates.
![WidgetLocalStorageProp](figures/WidgetLocalStorageProp.png)
| API| System Capability| Constraints|
| -------- | -------- | -------- |
| updateForm | No| 1. Invoked by the provider.<br>2. Allows only the widget provider to update its own widgets. It cannot be used to update widgets by other providers.|
| requestForm | Yes| 1. Invoked by the host.<br>2. Allows only the widget host to update the widgets added to it. It cannot be used to update widgets added to other hosts.|
The following describes the typical use cases of widget updates:
- [Configuring a Widget to Update Periodically](arkts-ui-widget-update-by-time.md)
- [Updating Local and Online Images](arkts-ui-widget-image-update.md)
- [Updating Widget Content by State](arkts-ui-widget-update-by-status.md)
- [Updating Widget Content by Widget Host (for System Applications Only)](arkts-ui-widget-content-update.md)
# Widget Lifecycle Management
When creating an ArkTS widget, you need to implement the [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) lifecycle APIs.
1. Import related modules to **EntryFormAbility.ts**.
```ts
import formInfo from '@ohos.app.form.formInfo';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import formProvider from '@ohos.app.form.formProvider';
```
2. In **EntryFormAbility.ts**, implement the [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) lifecycle APIs, including **onAddForm**, whose **want** parameter can be used to obtain the widget information through [FormParam](../reference/apis/js-apis-app-form-formInfo.md#formparam).
```typescript
import formInfo from '@ohos.app.form.formInfo';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import formProvider from '@ohos.app.form.formProvider';
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want) {
console.info('[EntryFormAbility] onAddForm');
// Obtain the unique widget ID formId from the want parameter.
let formId: string = want.parameters[formInfo.FormParam.IDENTITY_KEY];
// Called when the widget is created. The widget provider should return the widget data binding class.
let obj = {
'title': 'titleOnAddForm',
'detail': 'detailOnAddForm'
};
let formData = formBindingData.createFormBindingData(obj);
return formData;
}
onCastToNormalForm(formId) {
// Called when the form provider is notified that a temporary form is successfully
// converted to a normal form.
// Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion.
console.info(`[EntryFormAbility] onCastToNormalForm, formId: ${formId}`);
}
onUpdateForm(formId) {
// Override this method to support scheduled updates, periodic updates, or updates requested by the widget host.
console.info('[EntryFormAbility] onUpdateForm');
let obj = {
'title': 'titleOnUpdateForm',
'detail': 'detailOnUpdateForm'
};
let formData = formBindingData.createFormBindingData(obj);
formProvider.updateForm(formId, formData).catch((err) => {
if (err) {
// Print errors.
console.error(`[EntryFormAbility] Failed to updateForm. Code: ${err.code}, message: ${err.message}`);
return;
}
});
}
onChangeFormVisibility(newStatus) {
// Called when the form provider receives form events from the system.
// The callback is performed only when formVisibleNotify is set to true and the application is a system application.
console.info('[EntryFormAbility] onChangeFormVisibility');
}
onFormEvent(formId, message) {
// Called when a specified message event defined by the form provider is triggered.
// If the widget supports event triggering, override this method and implement the trigger.
console.info('[EntryFormAbility] onFormEvent');
}
onRemoveForm(formId) {
// Called to notify the form provider that a specified form has been destroyed.
// Called when the corresponding widget is deleted. The input parameter is the ID of the deleted card.
console.info('[EntryFormAbility] onRemoveForm');
}
onConfigurationUpdate(config) {
// Called when the system configuration is updated.
console.info('[EntryFormAbility] configurationUpdate:' + JSON.stringify(config));
}
onAcquireFormState(want) {
// Called to return a {@link FormState} object.
// Called when the widget provider receives the status query result of a widget. By default, the initial state of the widget is returned.
return formInfo.FormState.READY;
}
}
```
> **NOTE**
> The FormExtensionAbility cannot reside in the background. Therefore, continuous tasks cannot be processed in the widget lifecycle callbacks. The FormExtensionAbility persists for 5 seconds after the lifecycle callback is completed and will exit if no new lifecycle callback is invoked during this time frame. For the service logic that may take more than 5 seconds to complete, it is recommended that you [start the application](arkts-ui-widget-event-uiability.md). After the processing is complete, use the [updateForm](../reference/apis/js-apis-app-form-formProvider.md#updateform) to notify the widget of the update.
# ArkTS Widget Related Modules
**Figure 1** ArkTS widget related modules
![WidgetModules](figures/WidgetModules.png)
- [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md): provides lifecycle callbacks invoked when a widget is created, destroyed, or updated.
- [FormExtensionContext](../reference/apis/js-apis-inner-application-formExtensionContext.md): provides context for FormExtensionAbilities. You can use the APIs of this module to start FormExtensionAbilities.
- [formProvider](../reference/apis/js-apis-app-form-formProvider.md): provides APIs related to the widget provider. You can use the APIs to update a widget, set the next update time for a widget, obtain widget information, and request a widget release.
- [formInfo](../reference/apis/js-apis-app-form-formInfo.md): provides types and enums related to the widget information and state.
- [formBindingData](../reference/apis/js-apis-app-form-formBindingData.md): provides APIs for widget data binding. You can use the APIs to create a **FormBindingData** object and obtain related information.
- [Page Layout (Card.ets)](arkts-ui-widget-page-overview.md): provides APIs for a declarative paradigm UI.
- [ArkTS widget capabilities](arkts-ui-widget-event-overview.md): include the **postCardAction** API used for interaction between the widget internal and the provider application and can be called only in the widget.
- [ArkTS widget capability list](arkts-ui-widget-page-overview.md#page-capabilities-supported-by-arkts-widgets): lists the APIs, components, events, attributes, and lifecycle callbacks that can be used in ArkTS widgets.
- [Widget configuration](arkts-ui-widget-configuration.md): includes FormExtensionAbility configuration and widget configuration.
- Configure FormExtensionAbility information under **extensionAbilities** in the [module.json5 file](../quick-start/module-configuration-file.md).
- Configure the widget configuration information (**WidgetCard.ets**) in the [form_config.json](arkts-ui-widget-configuration.md) file in **resources/base/profile**.
# Using Animations in the Widget
To make your ArkTS widget more engaging, you can apply animations to it, including [explicit animation](../reference/arkui-ts/ts-explicit-animation.md), [attribute animation](../reference/arkui-ts/ts-animatorproperty.md), and [component transition](../reference/arkui-ts/ts-transition-animation-component.md). Note the following restrictions when using the animations in ArkTS widgets.
**Table 1** Restrictions on animation parameters
| Name| Description| Description|
| -------- | -------- | -------- |
| duration | Animation playback duration| The maximum value is 1 second. If a larger value is set, the animation is still played for 1 second.|
| tempo | Animation playback speed.| Do not set this parameter in the widget. Use the default value 1.|
| delay | Animation delay duration.| Do not set this parameter in the widget. Use the default value 0.|
| iterations | Number of times that the animation is played.| Do not set this parameter in the widget. Use the default value 1.|
The following sample code implements the animation effect of button rotation:
![WidgetAnimation](figures/WidgetAnimation.gif)
```ts
@Entry
@Component
struct AttrAnimationExample {
@State rotateAngle: number = 0;
build() {
Column() {
Button('change rotate angle')
.onClick(() => {
this.rotateAngle = 90;
})
.margin(50)
.rotate({ angle: this.rotateAngle })
.animation({
curve: Curve.EaseOut,
playMode: PlayMode.AlternateReverse
})
}.width('100%').margin({ top: 20 })
}
}
```
# Applying Custom Drawing in the Widget
You can apply custom drawing in your ArkTS widget to create a more vibrant experience. Use the [Canvas](../reference/arkui-ts/ts-components-canvas-canvas.md) component to create a canvas on the widget, and then use the [CanvasRenderingContext2D](../reference/arkui-ts/ts-canvasrenderingcontext2d.md) object to draw custom graphics on the canvas. The following code shows how to draw a smiling face in the center of the canvas.
```typescript
@Entry
@Component
struct Card {
private canvasWidth: number = 0;
private canvasHeight: number = 0;
// Initialize CanvasRenderingContext2D and RenderingContextSettings.
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
build() {
Column() {
Row() {
Canvas(this.context)
.margin('5%')
.width('90%')
.height('90%')
.onReady(() => {
console.info('[ArkTSCard] onReady for canvas draw content');
// Obtain the actual width and height of the canvas in the onReady callback.
this.canvasWidth = this.context.width;
this.canvasHeight = this.context.height;
// Draw the background of the canvas.
this.context.fillStyle = 'rgba(203, 154, 126, 1.00)';
this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
// Draw a red circle in the center of the canvas.
this.context.beginPath();
let radius = this.context.width / 3
let circleX = this.context.width / 2
let circleY = this.context.height / 2
this.context.moveTo(circleX - radius, circleY);
this.context.arc(circleX, circleY, radius, 2 * Math.PI, 0, true);
this.context.closePath();
this.context.fillStyle = 'red';
this.context.fill();
// Draw the left eye of the smiling face.
let leftR = radius / 4
let leftX = circleX - (radius / 2)
let leftY = circleY - (radius / 3.5)
this.context.beginPath();
this.context.arc(leftX, leftY, leftR, 0, Math.PI, true);
this.context.strokeStyle = '#ffff00'
this.context.lineWidth = 10
this.context.stroke()
// Draw the right eye of the smiling face.
let rightR = radius / 4
let rightX = circleX + (radius / 2)
let rightY = circleY - (radius / 3.5)
this.context.beginPath();
this.context.arc(rightX, rightY, rightR, 0, Math.PI, true);
this.context.strokeStyle = '#ffff00'
this.context.lineWidth = 10
this.context.stroke()
// Draw the mouth of the smiling face.
let mouthR = radius / 2.5
let mouthX = circleX
let mouthY = circleY + (radius / 3)
this.context.beginPath();
this.context.arc(mouthX, mouthY, mouthR, Math.PI, 0, true);
this.context.strokeStyle = '#ffff00'
this.context.lineWidth = 10
this.context.stroke()
})
}
}.height('100%').width('100%')
}
}
```
The figure below shows the effect.
![WidgetCanvasDemo](figures/WidgetCanvasDemo.jpeg)
# Widget Page Capability Overview
You can leverage the ArkUI declarative paradigm to develop ArkTS widget pages. The following widget pages are automatically generated by a DevEco Studio template. You can adjust the pages based on the real-world service scenarios.
![WidgetPreviewPage](figures/WidgetPreviewPage.png)
ArkTS widgets have full capabilities of JS widgets, with added animation and custom drawing capabilities plus partial support for components, events, animations, data management, and state management capabilities of the [declarative paradigm](../reference/arkui-ts/ts-components-summary.md). For details, see [Page Capabilities Supported by ArkTS Widgets](#page-capabilities-supported-by-arkts-widgets).
## Page Capabilities Supported by ArkTS Widgets
For details about the page capabilities supported by ArkTS widgets, see [Learning ArkTS](../quick-start/arkts-create-custom-components.md) and [ArkTS-based Declarative Development Paradigm](../reference/arkui-ts/ts-components-summary.md).
Only the APIs marked with "supported in ArkTS widgets" can be used for ArkTS widgets. Pay special attention to the capability differences with applications.
For example, the following description indicates that the @Component decorator can be used in ArkTS widgets.
![WidgetSupportApi](figures/WidgetSupportApi.png)
# Updating Widget Content by State
Multiple widgets of the same application can be configured to implement different features. For example, two weather widgets can be added to the home screen: one for displaying the weather of London, and the other Beijing. The widget is set to be updated at 07:00 every morning. It needs to detect the configured city, and then updates the city-specific weather information. The following example describes how to dynamically update the widget content based on the state.
- Widget configuration file: Configure the widget to be updated at 07:00 every morning.
```json
{
"forms": [
{
"name": "widget",
"description": "This is a service widget.",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDefault": true,
"updateEnabled": true,"scheduledUpdateTime": "07:00",
"updateDuration": 0,
"defaultDimension": "2*2",
"supportDimensions": ["2*2"]
}
]
}
```
- Widget page: A widget has different states and needs to be updated by state. When the state changes, **postCardAction** is called to notify the EntryFormAbility.
```ts
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('textA') textA: string = 'To be updated...';
@LocalStorageProp('textB') textB: string ='To be updated...';
@State selectA: boolean = false;
@State selectB: boolean = false;
build() {
Column() {
Row() {
Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
.select(false)
.onChange((value: boolean) => {
this.selectA = value;
postCardAction(this, {
'action': 'message',
'params': {
'selectA': JSON.stringify(value)
}
});
})
Text ('State A')
}
Row() {
Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
.select(false)
.onChange((value: boolean) => {
this.selectB = value;
postCardAction(this, {
'action': 'message',
'params': {
'selectB': JSON.stringify(value)
}
});
})
Text ('State B')
}
Row() {// Content that is updated only in state A
Text('State A: ')
Text(this.textA)
}
Row() { // Content that is updated only in state B
Text ('State B:')
Text(this.textB)
}
}.padding('10%')
}
}
```
- EntryFormAbility: The widget state data is stored in the local database. When the update event callback is triggered, the current widget state is obtained through **formId**, and then content is updated based on the state obtained.
```ts
import formInfo from '@ohos.app.form.formInfo'
import formProvider from '@ohos.app.form.formProvider';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import dataStorage from '@ohos.data.storage'
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want) {
let formId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
let isTempCard: boolean = want.parameters[formInfo.FormParam.TEMPORARY_KEY];
if (isTempCard === false) {// If the widget is a normal one, the widget information is persisted.
console.info('Not temp card, init db for:' + formId);
let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
storeDB.putSync('A' + formId, 'false');
storeDB.putSync('B' + formId, 'false');
storeDB.flushSync();
}
let formData = {};
return formBindingData.createFormBindingData(formData);
}
onRemoveForm(formId) {
console.info('onRemoveForm, formId:' + formId);
let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
storeDB.deleteSync('A' + formId);
storeDB.deleteSync('B' + formId);
}
// If the widget is a temporary one, it is recommended that the widget information be persisted when the widget is converted to a normal one.
onCastToNormalForm(formId) {
console.info('onCastToNormalForm, formId:' + formId);
let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
storeDB.putSync('A' + formId, 'false');
storeDB.putSync('B' + formId, 'false');
storeDB.flushSync();
}
onUpdateForm(formId) {
let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
let stateA = storeDB.getSync('A' + formId, 'false').toString()
let stateB = storeDB.getSync('B' + formId, 'false').toString()
// Update textA in state A.
if (stateA === 'true') {
let formInfo = formBindingData.createFormBindingData({
'textA': 'AAA'
})
formProvider.updateForm(formId, formInfo)
}
// Update textB in state B.
if (stateB === 'true') {
let formInfo = formBindingData.createFormBindingData({
'textB': 'BBB'
})
formProvider.updateForm(formId, formInfo)
}
}
onFormEvent(formId, message) {
// Store the widget state.
console.info('onFormEvent formId:' + formId + 'msg:' + message);
let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
let msg = JSON.parse(message)
if (msg.selectA != undefined) {
console.info('onFormEvent selectA info:' + msg.selectA);
storeDB.putSync('A' + formId, msg.selectA);
}
if (msg.selectB != undefined) {
console.info('onFormEvent selectB info:' + msg.selectB);
storeDB.putSync('B' + formId, msg.selectB);
}
storeDB.flushSync();
}
};
```
> **NOTE**
> When the local database is used for widget information persistence, it is recommended that [TEMPORARY_KEY](../reference/apis/js-apis-app-form-formInfo.md#formparam) be used to determine whether the currently added widget is a normal one in the [onAddForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onaddform) lifecycle callback. If the widget is a normal one, the widget information is directly persisted. If the widget is a temporary one, the widget information is persisted when the widget is converted to a normal one ([onCastToNormalForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#oncasttonormalform)). In addition, the persistent widget information needs to be deleted when the widget is destroyed ([onRemoveForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onremoveform)), preventing the database size from continuously increasing due to repeated widget addition and deletion.
# Configuring a Widget to Update Periodically
Before configuring a widget to update periodically, enable the periodic update feature by setting the **updateEnabled** field to **true** in the **form_config.json** file.
The widget framework provides the following modes of updating widgets periodically:
- Set the update interval: The widget will be updated at the specified interval. You can specify the interval by setting the [updateDuration](arkts-ui-widget-configuration.md) field in the **form_config.json** file. For example, you can configure the widget to update once an hour.
> **NOTE**
>
> **updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.
```json
{
"forms": [
{
"name": "widget",
"description": "This is a service widget.",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDefault": true,
"updateEnabled": true, // Enable the periodic update feature.
"scheduledUpdateTime": "10:30",
"updateDuration": 2, // Set the interval to update the widget. The value is a natural number, in the unit of 30 minutes.
"defaultDimension": "2*2",
"supportDimensions": ["2*2"]
}
]
}
```
- Set the scheduled update time: The widget will be updated at the scheduled time every day. You can specify the time by setting the [scheduledUpdateTime](arkts-ui-widget-configuration.md) field in the **form_config.json** file. For example, you can configure the widget to update at 10:30 a.m. every day.
> **NOTE**
>
> **updateDuration** takes precedence over **scheduledUpdateTime**. For the **scheduledUpdateTime** settings to take effect, set **updateDuration** to **0**.
```json
{
"forms": [
{
"name": "widget",
"description": "This is a service widget.",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDefault": true,
"updateEnabled": true, // Enable the periodic update feature.
"scheduledUpdateTime": "10:30", // Set the scheduled time to update the widget.
"updateDuration": 0,
"defaultDimension": "2*2",
"supportDimensions": ["2*2"]
}
]
}
```
- Set the next update time: The widget will be updated next time at the specified time. You can specify the time by calling the [setFormNextRefreshTime()](../reference/apis/js-apis-app-form-formProvider.md#setformnextrefreshtime) API. The minimum update interval is 5 minutes. For example, you can configure the widget to update within 5 minutes after the API is called.
```ts
import formProvider from '@ohos.app.form.formProvider';
let formId = '123456789'; // Use the actual widget ID in real-world scenarios.
try {
// Configure the widget to update in 5 minutes.
formProvider.setFormNextRefreshTime(formId, 5, (err, data) => {
if (err) {
console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
return;
} else {
console.info('Succeeded in setFormNextRefreshTimeing.');
}
});
} catch (err) {
console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
}
```
When periodic update is triggered, the system calls the [onUpdateForm()](../reference/apis/js-apis-app-form-formExtensionAbility.md#onupdateform) lifecycle callback of the FormExtensionAbility. In the callback, [updateForm()](../reference/apis/js-apis-app-form-formProvider.md#updateform) can be used to update the widget by the provider. For details about how to use **onUpdateForm()**, see [Updating Widget Content Through FormExtensionAbility](arkts-ui-widget-event-formextensionability.md).
> **NOTE**
> 1. Each widget can be updated at the specified interval for a maximum of 50 times every day, including updates triggered by setting [updateDuration](arkts-ui-widget-configuration.md) or calling [setFormNextRefreshTime()](../reference/apis/js-apis-app-form-formProvider.md#setformnextrefreshtime). When the limit is reached, the widget cannot be updated in this mode again. The number of update times is reset at 00:00 every day.
>
> 2. The same timer is used for timing updates at the specified interval. Therefore, the first scheduled update of widgets may have a maximum deviation of 30 minutes. For example, the first widget A (updated every half an hour) is added at 03:20. The timer starts and triggers an update every half an hour. The second widget B (updated every half an hour) is added at 03:40. When the timer event is triggered at 03:50, widget A is updated, and widget B will be updated at 04:20 next time.
>
> 3. Updates at the specified interval and updates at the scheduled time are triggered only when the screen is on. When the screen is off, the update action is merely recorded. When the screen is on, the update action is performed.
# ArkTS Widget Working Principles
## Implementation Principles
**Figure 1** ArkTS widget implementation principles
![WidgetPrinciple](figures/WidgetPrinciple.png)
- Widget host: an application that displays the widget content and controls the widget location. Only the system application can function as a widget host.
- Widget provider: an application that provides the widget content to display and controls how widget components are laid out and how they interact with users.
- Widget Manager: a resident agent that manages widgets in the system. It provides the [formProvider](../reference/apis/js-apis-app-form-formProvider.md) and [formHost](../reference/apis/js-apis-app-form-formHost.md) APIs as well as widget management, usage, and periodic updates.
- Widget rendering service: a service that manages widget rendering instances. Widget rendering instances are bound to the [widget components](../reference/arkui-ts/ts-basic-components-formcomponent.md) on the widget host on a one-to-one basis. The widget rendering service runs the widget page code **widgets.abc** for rendering, and sends the rendered data to the corresponding widget component on the widget host.
**Figure 2** Working principles of the ArkTS widget rendering service
![WidgetRender](figures/WidgetRender.png)
Unlike JS widgets, ArkTS widgets support logic code running. To avoid potential ArkTS widget issues from affecting the use of applications, the widget page code **widgets.abc** is executed by the widget rendering service, which is managed by the Widget Manager. Each widget component of a widget host corresponds to a rendering instance in the widget rendering service. Rendering instances of an application provider run in the same virtual machine operating environment, and rendering instances of different application providers run in different virtual machine operating environments. In this way, the resources and state data are isolated between widgets of different application providers. During development, pay attention to the use of the [globalThis](uiability-data-sync-with-ui.md#using-globalthis-between-uiability-and-page) object. Use one **globalThis** object for widgets by the same application provider, and different **globalThis** objects for widgets by different application providers.
## Advantages of ArkTS Widgets
As a quick entry to applications, ArkTS widgets have the following advantages over JS widgets:
- Improved development experience and efficiency, thanks to the unified development paradigm
ArkTS widgets share the same declarative UI development framework as application pages. This means that the page layouts can be directly reused in widgets, improving development experience and efficiency.
**Figure 3** Comparison of widget project structures
![WidgetProject](figures/WidgetProject.png)
- More widget features
- Animation: The ArkTS widget supports the [attribute animation](../reference/arkui-ts/ts-animatorproperty.md) and [explicit animation](../reference/arkui-ts/ts-explicit-animation.md) capabilities, which can be leveraged to deliver a more engaging experience.
- Custom drawing: The ArkTS widget allows you to draw graphics with the [Canvas](../reference/arkui-ts/ts-components-canvas-canvas.md) component to present information more vividly.
- Logic code execution: The capability to run logic code in widgets means that service logic can be self-closed in widgets, expanding the service application scenarios of widgets.
## Constraints on ArkTS Widgets
Compared with JS widgets, ArkTS widgets provide more capabilities, but they are also more prone to malicious behavior. The ArkTS widget is displayed in the widget host, which is usually the home screen. To ensure user experience and power consumption, the ArkTS widget capability is restricted as follows:
- The .so file cannot be loaded.
- The native programming language cannot be used for development.
- Only [partial](arkts-ui-widget-page-overview.md) components, events, animations, data management, state management, and API capabilities of the declarative paradigm are supported.
- The event processing of the widget is independent of that of the widget host. It is recommended that you do not use the left and right sliding components when the widget host supports left and right swipes to prevent gesture conflicts.
The following features are coming to ArkTS widgets in later versions:
- Breakpoint debugging
- import statements
- Instant preview
# Removing Sticky Common Events
## When to Use
Subscribers can receive sticky common events that have been sent. If the events are no longer forwarded, the event publisher needs to remove them. OpenHarmony provides an API for removing sticky common events.
## Available APIs
For details, see [Common Event](../reference/apis/js-apis-commonEventManager.md)
| Name| Description|
| -------- | -------- |
| removeStickyCommonEvent(event: string, callback: AsyncCallback\<void>): void | Removes a sticky common event.|
## How to Develop
1. Import the module.
```ts
import commonEventManager from '@ohos.commonEventManager';
```
2. The sticky common event to be removed must have been released by the application. For details about how to release sticky common events, see [Publishing Common Events](common-event-publish.md).
```ts
CommonEventManager.removeStickyCommonEvent("sticky_event", (err) => { // sticky_event indicates the name of the sticky common event to remove.
if (err) {
console.info(`Remove sticky event AsyncCallback failed, errCode: ${err.code}, errMes: ${err.message}`);
return;
}
console.info(`Remove sticky event AsyncCallback success`);
}
});
```
......@@ -22,8 +22,6 @@ A static subscriber is started once it receives a target event published by the
You can implement service logic in the **onReceiveEvent** callback.
2. Project Configuration for a Static Subscriber
After writing the static subscriber code, configure the subscriber in the **module.json5** file. The configuration format is as follows:
......@@ -35,12 +33,12 @@ A static subscriber is started once it receives a target event published by the
"extensionAbilities": [
{
"name": "StaticSubscriber",
"srcEntrance": "./ets/StaticSubscriber/StaticSubscriber.ts",
"srcEntry": "./ets/StaticSubscriber/StaticSubscriber.ts",
"description": "$string:StaticSubscriber_desc",
"icon": "$media:icon",
"label": "$string:StaticSubscriber_label",
"type": "staticSubscriber",
"visible": true,
"exported": true,
"metadata": [
{
"name": "ohos.extension.staticSubscriber",
......@@ -56,7 +54,7 @@ A static subscriber is started once it receives a target event published by the
Pay attention to the following fields in the JSON file:
- **srcEntrance**: entry file path of the ExtensionAbility, that is, the file path of the static subscriber declared in Step 2.
- **srcEntry**: entry file path of the ExtensionAbility, that is, the file path of the static subscriber declared in Step 2.
- **type**: ExtensionAbility type. For a static subscriber, set this field to **staticSubscriber**.
......
......@@ -23,8 +23,8 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
- **Before starting a component of another application, verify the visible field of the target component.**
- If the **visible** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission.
- For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities).
- If the **exported** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission.
- For details, see [Component exported Configuration](../quick-start/module-configuration-file.md#abilities).
- **Before starting a component of a background application, verify the BACKGROUND permission.**
- An application is considered as a foreground application only when the application process gains focus or its UIAbility component is running in the foreground.
......@@ -37,8 +37,8 @@ In view of this, OpenHarmony formulates a set of component startup rules, as fol
> **NOTE**
>
> - Component startup control has been implemented since OpenHarmony v3.2 Release.
>
> - The new component startup rules are more strict than the original ones. You must be familiar with the new startup rules to prevent service exceptions.
>
> - The new component startup rules are more strict than the original ones. You must be familiar with the new startup rules to prevent service exceptions.
## Intra-Device Component Startup Rules
......
# DataShareExtensionAbility (for System Applications Only)
DataShareExtensionAbility provides the data sharing capability. System applications can implement a DataShareExtensionAbility or access an existing DataShareExtensionAbility in the system. Third-party applications can only access an existing DataShareExtensionAbility. For details, see [DataShare Development](../database/database-datashare-guidelines.md).
......@@ -60,15 +60,15 @@ To implement EnterpriseAdminExtensionAbility, you need to activate the device ad
};
```
4. Register **ServiceExtensionAbility** in the [**module.json5**](../quick-start/module-configuration-file.md) file corresponding to the project module. Set **type** to **enterpriseAdmin** and **srcEntrance** to the path of the ExtensionAbility code.
4. Register **ServiceExtensionAbility** in the [**module.json5**](../quick-start/module-configuration-file.md) file corresponding to the project module. Set **type** to **enterpriseAdmin** and **srcEntry** to the path of the ExtensionAbility code.
```ts
"extensionAbilities": [
{
"name": "ohos.samples.enterprise_admin_ext_ability",
"type": "enterpriseAdmin",
"visible": true,
"srcEntrance": "./ets/enterpriseextability/EnterpriseAdminAbility.ts"
"exported": true,
"srcEntry": "./ets/enterpriseextability/EnterpriseAdminAbility.ts"
}
]
```
......
......@@ -25,7 +25,8 @@ An [ExtensionAbilityType](../reference/apis/js-apis-bundleManager.md#extensionab
- [EnterpriseAdminExtensionAbility](../reference/apis/js-apis-EnterpriseAdminExtensionAbility.md): ExtensionAbility component of the enterprise_admin type, which provides APIs for processing enterprise management events, such as application installation events on devices and events indicating too many incorrect screen-lock password attempts.
> **NOTE**<br>
> **NOTE**
>
> 1. Third-party applications cannot implement ServiceExtensionAbility, DataShareExtensionAbility, StaticSubscriberExtensionAbility, or WindowExtensionAbility.
>
> 2. To implement transaction processing in the background for a third-party application, use background tasks rather than ServiceExtensionAbility. For details, see [Background Task](../task-management/background-task-overview.md).
......@@ -45,7 +46,7 @@ The following uses [InputMethodExtensionAbility](../reference/apis/js-apis-input
## Implementing ExtensionAbility of the Specified Type
The following uses [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) as an example. The widget framework provides the base class [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). You derive this base class to create your own class (such as **MyFormExtensionAbility**), implement the callbacks, such as **onCreate()** and **onUpdateForm()**, to provide specific widget functionalities. For details, see [FormExtensionAbility](Widget-development-stage.md).
The following uses [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) as an example. The widget framework provides the base class [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). You derive this base class to create your own class (such as **MyFormExtensionAbility**), implement the callbacks, such as **onCreate()** and **onUpdateForm()**, to provide specific widget functionalities. For details, see [FormExtensionAbility](service-widget-overview.md).
You do not need to care when to add or delete a widget. The lifecycle of the FormExtensionAbility instance and the lifecycle of the ExtensionAbility process where the FormExtensionAbility instance is located are scheduled and managed by FormManagerService.
......@@ -63,3 +64,5 @@ You do not need to care when to add or delete a widget. The lifecycle of the For
> - The two FormExtensionAbility components run in an independent process.
>
> - The two ImeExtensionAbility components run in an independent process.
<!--no_check-->
\ No newline at end of file
en/application-dev/application-models/figures/JSCardPrinciple.png

266.7 KB

en/application-dev/application-models/figures/WidgerCameraCard.png

19.6 KB

en/application-dev/application-models/figures/WidgetAnimation.gif

130.5 KB

en/application-dev/application-models/figures/WidgetArchitecture.png

89.9 KB

en/application-dev/application-models/figures/WidgetCardPage.png

7.5 KB

en/application-dev/application-models/figures/WidgetLocalStorageProp.png

97.5 KB

en/application-dev/application-models/figures/WidgetModules.png

188.1 KB

en/application-dev/application-models/figures/WidgetPostCardAction.png

92.7 KB

en/application-dev/application-models/figures/WidgetPreviewPage.png

9.4 KB

en/application-dev/application-models/figures/WidgetPrinciple.png

190.2 KB

en/application-dev/application-models/figures/WidgetProject.png

189.0 KB

en/application-dev/application-models/figures/WidgetProjectCreate1.png

33.1 KB

en/application-dev/application-models/figures/WidgetProjectCreate2.png

19.3 KB

en/application-dev/application-models/figures/WidgetProjectCreate3.png

15.2 KB

en/application-dev/application-models/figures/WidgetProjectView.png

10.9 KB

en/application-dev/application-models/figures/WidgetRender.png

71.7 KB

en/application-dev/application-models/figures/WidgetSupportApi.png

15.3 KB

en/application-dev/application-models/figures/WidgetUpdatePage.png

976.5 KB

en/application-dev/application-models/figures/WidgetUse.png

1.7 MB

en/application-dev/application-models/figures/mission-and-multiton.png

86.4 KB

en/application-dev/application-models/figures/uiability-launch-type1.gif

663.9 KB

en/application-dev/application-models/figures/uiability-launch-type2.gif

1.5 MB

en/application-dev/application-models/figures/uiability-launch-type3.gif

1.5 MB

......@@ -5,7 +5,7 @@
Multi-device coordination involves the following scenarios:
- [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned)
- [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned)
- [Starting UIAbility Across Devices (Data Returned)](#starting-uiability-across-devices-data-returned)
......@@ -31,9 +31,9 @@ The figure below shows the multi-device collaboration process.
- For better user experience, you are advised to use the **want** parameter to transmit data smaller than 100 KB.
## Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)
## Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)
On device A, touch the **Start** button provided by the initiator application to start a specified UIAbility on device B.
On device A, touch the **Start** button provided by the initiator application to start a specified UIAbility or ServiceExtensionAbility on device B.
### Available APIs
......@@ -42,7 +42,9 @@ On device A, touch the **Start** button provided by the initiator application to
| **API**| **Description**|
| -------- | -------- |
| startAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void; | Starts UIAbility and ServiceExtensionAbility. This API uses an asynchronous callback to return the result.|
| startAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void; | Starts a UIAbility or ServiceExtensionAbility. This API uses an asynchronous callback to return the result.|
| stopServiceExtensionAbility(want: Want, callback: AsyncCallback&lt;void&gt;): void; | Stops a ServiceExtensionAbility. This API uses an asynchronous callback to return the result.|
| stopServiceExtensionAbility(want: Want): Promise&lt;void&gt;; | Stops a ServiceExtensionAbility. This API uses a promise to return the result.|
### How to Develop
......@@ -81,7 +83,7 @@ On device A, touch the **Start** button provided by the initiator application to
}
```
4. Set the target component parameters, and call [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to start UIAbility or ServiceExtensionAbility.
4. Set the target component parameters, and call [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to start a UIAbility or ServiceExtensionAbility.
```ts
let want = {
......@@ -98,6 +100,22 @@ On device A, touch the **Start** button provided by the initiator application to
})
```
5. Call stopServiceExtensionAbility(../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstopserviceextensionability) to stop the ServiceExtensionAbility when it is no longer required on device B. (This API cannot be used to stop a UIAbility. Users must manually stop a UIAbility through task management.)
```ts
let want = {
deviceId: getRemoteDeviceId(),
bundleName: 'com.example.myapplication',
abilityName: 'FuncAbility',
moduleName: 'module1', // moduleName is optional.
}
// Stop the ServiceExtensionAbility started by calling startAbility().
this.context.stopServiceExtensionAbility(want).then(() => {
console.info("stop service extension ability success")
}).catch((err) => {
console.info("stop service extension ability err is " + JSON.stringify(err))
})
```
## Starting UIAbility Across Devices (Data Returned)
......@@ -121,7 +139,7 @@ On device A, touch the **Start** button provided by the initiator application to
2. Display a dialog box to ask authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/accesstoken-guidelines.md#requesting-user-authorization).
3. Set the target component parameters on the initiator, and call **startAbilityForResult()** to start the target UIAbility. **data** in the asynchronous callback is used to receive the information returned by the target UIAbility to the initiator UIAbility after the target UIAbility terminates itself. For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned).
3. Set the target component parameters on the initiator, and call **startAbilityForResult()** to start the target UIAbility. **data** in the asynchronous callback is used to receive the information returned by the target UIAbility to the initiator UIAbility after the target UIAbility terminates itself. For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
```ts
let want = {
......@@ -253,7 +271,7 @@ A system application can connect to a service on another device by calling [conn
let connectionId = this.context.connectServiceExtensionAbility(want, options);
```
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned).
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
5. Disconnect the connection. Use **disconnectServiceExtensionAbility()** to disconnect from the background service.
......@@ -313,12 +331,12 @@ The following describes how to implement multi-device collaboration through cros
```json
"abilities":[{
"name": ".CalleeAbility",
"srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
"srcEntry": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"visible": true
"exported": true
}]
```
2. Import the **UIAbility** module.
......@@ -438,7 +456,7 @@ The following describes how to implement multi-device collaboration through cros
}
```
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned).
For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility or ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-or-serviceextensionability-across-devices-no-data-returned).
5. Sends agreed parcelable data to the CalleeAbility.
1. The parcelable data can be sent to the CalleeAbility with or without a return value. The method and parcelable data must be consistent with those of the CalleeAbility. The following example describes how to send data to the CalleeAbility.
......
......@@ -54,7 +54,7 @@ The minimum template contains four files: **KeyboardController.ts**, **InputMeth
1. **InputMethodService.ts** file:
In this file, add the dependency package for importing InputMethodExtensionAbility. Customize a class that inherits from InputMethodExtensionAbility and add the required lifecycle callbacks.
In the **InputMethodService.ts** file, add the dependency package for importing InputMethodExtensionAbility. Customize a class that inherits from InputMethodExtensionAbility and add the required lifecycle callbacks.
```ts
import InputMethodExtensionAbility from '@ohos.InputMethodExtensionAbility';
......@@ -233,7 +233,7 @@ The minimum template contains four files: **KeyboardController.ts**, **InputMeth
Add the path to this file to the **src** field in the **resources/base/profile/main_pages.json** file.
```ets
```ts
import { numberSourceListData, sourceListType } from './keyboardKeyData'
@Component
......@@ -342,7 +342,7 @@ The minimum template contains four files: **KeyboardController.ts**, **InputMeth
}
```
Register the InputMethodExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the target module. Set **type** to **"inputMethod"** and **srcEntrance** to the code path of the InputMethodExtensionAbility component.
Register the InputMethodExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the target module. Set **type** to **"inputMethod"** and **srcEntry** to the code path of the InputMethodExtensionAbility component.
```ts
{
......@@ -353,9 +353,9 @@ The minimum template contains four files: **KeyboardController.ts**, **InputMeth
"description": "inputMethod",
"icon": "$media:icon",
"name": "InputMethodExtAbility",
"srcEntrance": "./ets/inputmethodextability/InputMethodService.ts",
"srcEntry": "./ets/inputmethodextability/InputMethodService.ts",
"type": "inputMethod",
"visible": true,
"exported": true,
}
]
}
......
# LifecycleApp Switching
| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model|
| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model|
| -------- | -------- | -------- |
| onShow?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback&lt;WindowStageEventType&gt;): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)<br>Listens for the switching to the [foreground](../reference/apis/js-apis-window.md#windowstageeventtype9).|
| onHide?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback&lt;WindowStageEventType&gt;): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)<br>Listens for the switching to the [background](../reference/apis/js-apis-window.md#windowstageeventtype9).|
| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) |
| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) |
| onCreate?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate) |
| onWindowDisplayModeChanged?(isShownInMultiWindow: boolean, newConfig: resourceManager.Configuration): void; | There is no corresponding API in the stage model.| No corresponding API is provided.|
| onStartContinuation?(): boolean; | There is no corresponding API in the stage model.| In the stage model, an application does not need to detect whether the continuation is successful (detected when the application initiates the continuation request). Therefore, the **onStartContinuation()** callback is deprecated.|
| onSaveData?(data: Object): boolean; | \@ohos.app.ability.UIAbility.d.ts | [onContinue(wantParam : {[key: string]: any}): AbilityConstant.OnContinueResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncontinue) |
| onCompleteContinuation?(result: number): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) |
| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)<br>In standard or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.|
| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)<br>In multiton or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.|
| onRemoteTerminated?(): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) |
| onSaveAbilityState?(outState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onSaveState(reason: AbilityConstant.StateType, wantParam : {[key: string]: any}): AbilityConstant.OnSaveResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonsavestate) |
| onRestoreAbilityState?(inState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)<br>After the application is restarted, the **onCreate()** callback is triggered. In the callback, **launchParam.launchReason** is used to determine whether it is a self-recovery scenario. If it is, the data saved before the restart can be obtained from the **want** parameter.|
......
# Mission Management and Launch Type
# Mission and Launch Type
One UIAbility instance corresponds to one mission. The number of UIAbility instances is related to the UIAbility launch type, specified by **launchType**, which is configured in the **config.json** file in the FA model and the [module.json5](../quick-start/module-configuration-file.md) file in the stage model.
......@@ -8,16 +8,19 @@ The following describes how the mission list manager manages the UIAbility insta
- **singleton**: Only one UIAbility instance exists for an application.
**Figure 1** Missions and singleton mode
![mission-and-singleton](figures/mission-and-singleton.png)
- **standard**: Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a **UIAbility** instance is created in the application process.
- **multiton**: Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a UIAbility instance is created in the application process.
**Figure 2** Missions and multiton mode
**Figure 2** Missions and standard mode
![mission-and-standard](figures/mission-and-standard.png)
![mission-and-multiton](figures/mission-and-multiton.png)
- **specified**: The ([onAcceptWant](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create an instance.
- **specified**: The ([onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create a UIAbility instance.
**Figure 3** Missions and specified mode
![mission-and-specified](figures/mission-and-specified.png)
......
......@@ -4,7 +4,7 @@
Before getting started with the development of mission management, be familiar with the following concepts related to mission management:
- AbilityRecord: minimum unit for the system service to manage a UIAbility instance. It corresponds to a UIAbility component instance of an application.
- AbilityRecord: minimum unit for the system service to manage a UIAbility instance. It corresponds to a UIAbility component instance of an application. A maximum of 512 UIAbility instances can be managed on the system service side.
- MissionRecord: minimum unit for mission management. One MissionRecord has only one AbilityRecord. In other words, a UIAbility component instance corresponds to a mission.
......@@ -30,42 +30,42 @@ Missions are managed by system applications (such as home screen), rather than t
A UIAbility instance corresponds to an independent mission. Therefore, when an application calls [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to start a UIAbility, a mission is created.
To call [missionManager](../reference/apis/js-apis-application-missionManager.md) to manage missions, the home screen application must request the **ohos.permission.MANAGE_MISSIONS** permission. For details about the configuration, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
1. To call [missionManager](../reference/apis/js-apis-application-missionManager.md) to manage missions, the home screen application must request the **ohos.permission.MANAGE_MISSIONS** permission. For details about the configuration, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
You can use **missionManager** to manage missions, for example, listening for mission changes, obtaining mission information or snapshots, and clearing, locking, or unlocking missions.
2. You can use **missionManager** to manage missions, for example, listening for mission changes, obtaining mission information or snapshots, and clearing, locking, or unlocking missions.
```ts
import missionManager from '@ohos.app.ability.missionManager'
let listener = {
// Listen for mission creation.
onMissionCreated: function (mission) {
console.info("--------onMissionCreated-------")
},
// Listen for mission destruction.
onMissionDestroyed: function (mission) {
console.info("--------onMissionDestroyed-------")
},
// Listen for mission snapshot changes.
onMissionSnapshotChanged: function (mission) {
console.info("--------onMissionSnapshotChanged-------")
},
// Listen for switching the mission to the foreground.
onMissionMovedToFront: function (mission) {
console.info("--------onMissionMovedToFront-------")
},
// Listen for mission icon changes.
onMissionIconUpdated: function (mission, icon) {
console.info("--------onMissionIconUpdated-------")
},
// Listen for mission name changes.
onMissionLabelUpdated: function (mission) {
console.info("--------onMissionLabelUpdated-------")
},
// Listen for mission closure events.
onMissionClosed: function (mission) {
console.info("--------onMissionClosed-------")
}
// Listen for mission creation.
onMissionCreated: function (mission) {
console.info("--------onMissionCreated-------")
},
// Listen for mission destruction.
onMissionDestroyed: function (mission) {
console.info("--------onMissionDestroyed-------")
},
// Listen for mission snapshot changes.
onMissionSnapshotChanged: function (mission) {
console.info("--------onMissionSnapshotChanged-------")
},
// Listen for switching the mission to the foreground.
onMissionMovedToFront: function (mission) {
console.info("--------onMissionMovedToFront-------")
},
// Listen for mission icon changes.
onMissionIconUpdated: function (mission, icon) {
console.info("--------onMissionIconUpdated-------")
},
// Listen for mission name changes.
onMissionLabelUpdated: function (mission) {
console.info("--------onMissionLabelUpdated-------")
},
// Listen for mission closure events.
onMissionClosed: function (mission) {
console.info("--------onMissionClosed-------")
}
};
// 1. Register a mission change listener.
......@@ -73,56 +73,56 @@ You can use **missionManager** to manage missions, for example, listening for mi
// 2. Obtain the latest 20 missions in the system.
missionManager.getMissionInfos("", 20, (error, missions) => {
console.info("getMissionInfos is called, error.code = " + error.code);
console.info("size = " + missions.length);
console.info("missions = " + JSON.stringify(missions));
console.info("getMissionInfos is called, error.code = " + error.code);
console.info("size = " + missions.length);
console.info("missions = " + JSON.stringify(missions));
});
// 3. Obtain the detailed information about a mission.
let missionId = 11; // The mission ID 11 is only an example.
let mission = missionManager.getMissionInfo("", missionId).catch(function (err) {
console.info(err);
console.info(err);
});
// 4. Obtain the mission snapshot.
missionManager.getMissionSnapShot("", missionId, (error, snapshot) => {
console.info("getMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
console.info("getMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
})
// 5. Obtain the low-resolution mission snapshot.
missionManager.getLowResolutionMissionSnapShot("", missionId, (error, snapshot) => {
console.info("getLowResolutionMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
console.info("getLowResolutionMissionSnapShot is called, error.code = " + error.code);
console.info("bundleName = " + snapshot.ability.bundleName);
})
// 6. Lock or unlock the mission.
missionManager.lockMission(missionId).then(() => {
console.info("lockMission is called ");
console.info("lockMission is called ");
});
missionManager.unlockMission(missionId).then(() => {
console.info("unlockMission is called ");
console.info("unlockMission is called ");
});
// 7. Switch the mission to the foreground.
missionManager.moveMissionToFront(missionId).then(() => {
console.info("moveMissionToFront is called ");
console.info("moveMissionToFront is called ");
});
// 8. Clear a single mission.
missionManager.clearMission(missionId).then(() => {
console.info("clearMission is called ");
console.info("clearMission is called ");
});
// 9. Clear all missions.
missionManager.clearAllMissions().catch(function (err) {
console.info(err);
console.info(err);
});
// 10. Deregister the mission change listener.
missionManager.off('mission', listenerId, (error) => {
console.info("unregisterMissionListener");
console.info("unregisterMissionListener");
})
```
......
......@@ -8,7 +8,7 @@ Figure 1 Mission snapshot of a UIAbility
![](figures/mission-list-recent.png)
You can also use [UIAbilityContext.setMissionIcon()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextsetmissionicon) and [UIAbilityContext.setMissionLabel()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextsetmissionlabel) to customize the icon and name for a mission snapshot. For example, for a UIAbility instance with the launch type set to **standard**, you can configure the icon and name for each mission snapshot based on different functions.
You can also use [UIAbilityContext.setMissionIcon()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextsetmissionicon) and [UIAbilityContext.setMissionLabel()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextsetmissionlabel) to customize the icon and name for a mission snapshot. For example, for a UIAbility instance in multiton mode, you can configure the icon and name for each mission snapshot based on different functions.
This document describes the following operations:
......@@ -48,4 +48,4 @@ The display effect is shown below.
Figure 3 Mission snapshot name
![](figures/mission-set-task-snapshot-label.png)
\ No newline at end of file
![](figures/mission-set-task-snapshot-label.png)
......@@ -3,7 +3,7 @@
When switching an application from the FA model to the stage model, you must migrate the configurations under the **module** tag in the **config.json** file to the **module** tag in the **module.json5** file.
### **Table 1** module comparison
### Table 1 module Comparison
| Field Name in the FA Model| Field Description| Field Name in the Stage Model| Difference|
| -------- | -------- | -------- | -------- |
......@@ -21,13 +21,13 @@ When switching an application from the FA model to the stage model, you must mig
| shortcuts | Shortcuts of the application.| shortcut_config.json| In the stage model, the **shortcut_config.json** file is defined in **resources/base/profile** in the development view.|
| reqPermissions | Permissions that the application requests from the system when it is running.| requestPermissions | The field name is changed.|
| colorMode | Color mode of the application.| / | This configuration is not supported in the stage model.|
| distroFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.|
| distributionFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.|
| reqCapabilities | Device capabilities required for running the application.| / | This configuration is not supported in the stage model.|
| commonEvents | Common events.| common_event_config.json| In the stage model, the **common_event_config.json** file is defined in **resources/base/profile** in the development view.|
| entryTheme | Keyword of an OpenHarmony internal theme.| / | This configuration is not supported in the stage model.|
### Table 2 metaData comparison
### Table 2 metaData Comparison
| Field Name Under metaData in the FA Model| Field Description| Field Name Under metaData in the Stage Model| Difference|
| -------- | -------- | -------- | -------- |
......@@ -35,7 +35,7 @@ When switching an application from the FA model to the stage model, you must mig
| results | Metadata of the ability return value.| / | This configuration is not supported in the stage model.|
| customizeData | Custom metadata of the parent component. **parameters** and **results** cannot be configured in **application**.| metadata | See [Table 3](#table-3-comparison-between-customizedata-under-metadata-in-the-fa-model-and-metadata-in-the-stage-model).|
### Table 3 Comparison between customizeData under metaData in the FA model and metadata in the stage model
### Table 3 Comparison Between customizeData Under metaData in the FA Model and metadata in the Stage Model
| Field Name Under customizeData in metaData in the FA Model| Field Description| Field Name Under metaData in the Stage Model| Difference|
| -------- | -------- | -------- | -------- |
......@@ -44,14 +44,14 @@ When switching an application from the FA model to the stage model, you must mig
| extra | Format of the current custom data. The value is the resource value of **extra**.| resource | The field name is changed. For details, see [Table 4](#table 4-metadata-examples).|
### Table 4 metaData examples
### Table 4 metaData Examples
| Example in the FA Model| Example in the Stage Model|
| -------- | -------- |
| "meteData": {<br> "customizeDate": [{<br> "name": "label",<br> "value": "string",<br> "extra": "$string:label",<br> }]<br>} | "meteData": [{<br> "name": "label",<br> "value": "string",<br> "resource": "$string:label",<br>}] |
### Table 5 abilities comparison
### Table 5 abilities Comparison
| Field Name Under abilities in the FA Model| Field Description| Field Name Under abilities in the Stage Model| Difference|
| -------- | -------- | -------- | -------- |
......@@ -71,5 +71,5 @@ When switching an application from the FA model to the stage model, you must mig
| formsEnabled | Whether the ability can provide widgets.| / | This configuration is not supported in the stage model.|
| forms | Information about the widgets used by the ability. This field is valid only when **formsEnabled** is set to **true**.| form_config.json| In the stage model, the **form_config.json** file is defined in **resources/base/profile** in the development view.|
| srcLanguage | Programming language used to develop the ability.| / | This configuration is not supported in the stage model.|
| srcPath | Path of the JS component code corresponding to the ability.| srcEntrance | Path of the JS code corresponding to the ability.|
| srcPath | Path of the JS component code corresponding to the ability.| srcEntry | Path of the JS code corresponding to the ability.|
| uriPermission | Application data that the ability can access.| / | This configuration is not supported in the stage model.|
......@@ -5,10 +5,10 @@ Depending on the launch type, the action performed when the PageAbility starts d
**Table 1** PageAbility launch types
| Launch Type| Description|
| -------- | -------- |
| singleton | Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.<br>A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.|
| standard | Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.<br>A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.|
| Launch Type| Meaning | Description|
| -------- | -------- | -------- |
| singleton | Singleton mode| Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.<br>A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.|
| standard | Multiton mode| Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.<br>A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.|
You can set **launchType** in the **config.json** file to configure the launch type. The sample code is as follows:
......@@ -19,8 +19,8 @@ You can set **launchType** in the **config.json** file to configure the launch t
// ...
"abilities": [
{
// singleton mode.
// standard mode.
// singleton means the singleton mode.
// standard means the multiton mode.
"launchType": "standard",
// ...
}
......@@ -30,7 +30,8 @@ You can set **launchType** in the **config.json** file to configure the launch t
```
When the PageAbility is started for the first time (either in standard or singleton mode), the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not.
When the PageAbility is started in multiton mode or it is started in singleton mode for the first time, the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not.
**Table 2** Callbacks specific to the singleton mode
......
# Process Model (FA Model)
# Process Model Overview (FA Model)
The OpenHarmony process model is shown below.
......
# Process Model (Stage Model)
# Process Model Overview (Stage Model)
The OpenHarmony process model is shown below.
......@@ -15,7 +15,8 @@ The OpenHarmony process model is shown below.
> NOTE
>
> You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications.
> - You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications.
> - To view information about all running processes, run the **hdc shell** command to enter the shell CLI of the device, and run the **ps -ef** command.
A system application can apply for multi-process permissions (as shown in the following figure) and configure a custom process for an HAP. UIAbility, DataShareExtensionAbility, and ServiceExtensionAbility in the HAP run in the custom process. Different HAPs run in different processes by configuring different process names.
......
......@@ -33,4 +33,4 @@ To enable an ability to be called by any application, configure the **config.jso
```
If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant.
If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant.
# Service Widget Overview
A service widget (also called widget) is a set of UI components that display important information or operations specific to an application. It provides users with direct access to a desired application service, without the need to open the application first. A widget usually appears as a part of the UI of another application (which currently can only be a system application, such as the home screen) and provides basic interactive features such as opening a UI page or sending a message.
## Service Widget Architecture
**Figure 1** Service widget architecture
![WidgetArchitecture](figures/WidgetArchitecture.png)
Before you get started, it would be helpful if you have a basic understanding of the following concepts:
- Widget host: an application that displays the widget content and controls the widget location. An example is the home screen in the preceding figure.
- Application icon: an application entry icon, clicking which starts the application process. The icon content does not support interactions.
- Widget: an interactive UI in various sizes. It may provide buttons to implement different functions, such as the button to [update the widget content](arkts-ui-widget-event-formextensionability.md) or [switch to an application](arkts-ui-widget-event-router.md).
- Card provider: an application that provides service widget content to be displayed. It controls the display content, display logic, and component click events triggered on a service widget.
- FormExtensionAbility: widget service logic module, which provides lifecycle callbacks invoked when a widget is created, destroyed, or updated.
- Widget page: widget UI module, which contains display and interaction information such as components, layouts, and events.
Below is the typical procedure of using the widget:
**Figure 2** Typical procedure of using the widget
![WidgetUse](figures/WidgetUse.png)
1. Touch and hold an application icon on the home screen to display the shortcut menu.
2. Touch **Service widget** to access the preview screen.
3. Touch the **Add to home** button. The widget is then added to the home screen.
## Widget UI Development Mode
In the stage model, the UI of a widget can be developed in [ArkTS](arkts-ui-widget-working-principles.md) or [JS](js-ui-widget-development.md).
- A widget developed in the ArkTS-based declarative development paradigm is called ArkTS widget.
- A widget developed in the JS-compatible web-like development paradigm is called JS widget.
ArkTS widgets and JS widgets have different implementation principles and features. The following table lists the differences in capabilities.
| Category| JS widget| ArkTS widget|
| -------- | -------- | -------- |
| Development paradigm| Web-like paradigm| Declarative paradigm|
| Component capability| Supported| Supported|
| Layout capability| Supported| Supported|
| Event capability| Supported| Supported|
| Custom animation| Not supported| Supported|
| Custom drawing| Not supported| Supported|
| Logic code execution (excluding the import capability)| Not supported| Supported|
As can be seen above, ArkTS widgets have more capabilities and use cases than JS widgets. Therefore, ArkTS widgets are always recommended, except for the case where the widget consists of only static pages.
......@@ -70,7 +70,7 @@ struct Index {
```
When the launch type of a PageAbility is set to **standard** or when the PageAbility with the launch type set to **singleton** is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page.
When a PageAbility in multiton mode is started or when the PageAbility in singleton mode is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page.
When a user touches the button on the page of the caller PageAbility, the **startAbility()** method is called to start the target PageAbility. The **want** parameter in **startAbility()** carries the specified page information.
......
# Thread Model (FA Model)
# Thread Model Overview (FA Model)
There are three types of threads in the FA model:
- Main thread
Manages other threads.
Manages other threads.
- Ability thread
- One ability thread for each ability.
- Distributes input events.
......@@ -19,10 +17,8 @@ Manages other threads.
Performs time-consuming operations
Based on the OpenHarmony thread model, different services run on different threads. Service interaction requires inter-thread communication. Threads can communicate with each other in Emitter or Worker mode. Emitter is mainly used for event synchronization between threads, and Worker is mainly used to execute time-consuming tasks.
> **NOTE**
>
> The FA model provides an independent thread for each ability. Emitter is mainly used for event synchronization within the ability thread, between a pair of ability threads, or between the ability thread and worker thread.
# Thread Model (Stage Model)
# Thread Model Overview (Stage Model)
For an OpenHarmony application, each process has a main thread to provide the following functionalities:
- Manage other threads.
- Enable multiple UIAbility components of the same application to share the same main thread.
- Distribute input events.
- Draw the UI.
- Invoke application code callbacks (event processing and lifecycle callbacks).
- Manage the ArkTS engine instance of the main thread so that multiple UIAbility components can run on it.
- Manage ArkTS engine instances of other threads (such as the worker thread), for example, starting and terminating other threads.
- Distribute interaction events.
- Process application code callbacks (event processing and lifecycle management).
- Receive messages sent by the worker thread.
In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. It cannot directly operate the UI. The worker thread is created in the main thread and is independent of the main thread. A maximum of seven worker threads can be created.
In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. The worker thread is created in the main thread and is independent from the main thread. It cannot directly operate the UI. A maximum of seven worker threads can be created.
![thread-model-stage](figures/thread-model-stage.png)
......@@ -22,4 +17,5 @@ Based on the OpenHarmony thread model, different services run on different threa
> **NOTE**
>
> The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread.
> - The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread.
> - To view thread information about an application process, run the **hdc shell** command to enter the shell CLI of the device, and then run the **ps -p *<pid>* -T command**, where *<pid>* indicates the ID of the application process.
......@@ -124,14 +124,14 @@ By binding attributes or methods to **globalThis**, you can implement data synch
```ts
let entryAbilityWant;
@Entry
@Component
struct Index {
aboutToAppear() {
entryAbilityWant = globalThis.entryAbilityWant;
}
// Page display.
build() {
// ...
......@@ -161,7 +161,7 @@ To implement data synchronization between two UIAbility components in the same a
```ts
import UIAbility from '@ohos.app.ability.UIAbility'
export default class UIAbilityB extends UIAbility {
onCreate(want, launch) {
// UIAbilityB reads name from globalThis and outputs it.
......@@ -194,7 +194,7 @@ To implement data synchronization between the UIAbility and ExtensionAbility com
```ts
import Extension from '@ohos.app.ability.ServiceExtensionAbility'
export default class ServiceExtAbility extends Extension {
onCreate(want) {
/ / ServiceExtAbility reads name from globalThis and outputs it.
......@@ -247,7 +247,7 @@ The following provides an example to describe the object overwritten problem in
}
}
```
3. In the UIAbilityB file, [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) is stored in **globalThis** and has the same name as that in the UIAbilityA file.
```ts
......@@ -277,7 +277,7 @@ The following provides an example to describe the object overwritten problem in
}
}
```
5. Switch the UIAbilityB instance to the background and switch the UIAbilityA instance to the foreground. In this case, UIAbilityA will not enter the **onCreate()** lifecycle again.
```ts
......@@ -309,4 +309,6 @@ The following provides an example to describe the object overwritten problem in
## Using AppStorage or LocalStorage for Data Synchronization
ArkUI provides AppStorage and LocalStorage to implement application- and UIAbility-level data synchronization, respectively. Both solutions can be used to manage the application state, enhance application performance, and improve user experience. The AppStorage is a global state manager and is applicable when multiple UIAbilities share the same state data. The LocalStorage is a local state manager that manages state data used inside a single UIAbility. They help you control the application state more flexibly and improve the maintainability and scalability of applications. For details, see [State Management of Application-Level Variables](../quick-start/arkts-state-mgmt-application-level.md).
ArkUI provides AppStorage and LocalStorage to implement application- and UIAbility-level data synchronization, respectively. Both solutions can be used to manage the application state, enhance application performance, and improve user experience. The AppStorage is a global state manager and is applicable when multiple UIAbilities share the same state data. The LocalStorage is a local state manager that manages state data used inside a single UIAbility. They help you control the application state more flexibly and improve the maintainability and scalability of applications. For details, see [State Management of Application-Level Variables](../quick-start/arkts-application-state-management-overview.md).
<!--no_check-->
\ No newline at end of file
......@@ -222,7 +222,7 @@ This section describes how to start the UIAbility of another application through
```ts
let context = ...; // UIAbilityContext
// context is the AbilityContext of the UIAbility instance to stop.
// context is the UIAbilityContext of the UIAbility instance to stop.
context.terminateSelf((err) => {
// ...
});
......@@ -487,7 +487,7 @@ In summary, when a UIAbility instance of application A has been created and the
> **NOTE**
>
> When the [launch type of the target UIAbility](uiability-launch-type.md) is set to **standard**, a new instance is created each time the target UIAbility is started. In this case, the [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback will not be invoked.
> When the [launch type of the target UIAbility](uiability-launch-type.md) is set to **multiton**, a new instance is created each time the target UIAbility is started. In this case, the [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback will not be invoked.
## Using Call to Implement UIAbility Interaction (for System Applications Only)
......
......@@ -6,7 +6,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility
- [Singleton](#singleton)
- [Standard](#standard)
- [Multiton](#multiton)
- [Specified](#specified)
......@@ -18,8 +18,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility
Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, if a UIAbility instance of this type already exists in the application process, the instance is reused. Therefore, only one UIAbility instance of this type exists in the system, that is, displayed in **Recents**.
**Figure 1** Demonstration effect in singleton mode
![uiability-launch-type1](figures/uiability-launch-type1.png)
![uiability-launch-type1](figures/uiability-launch-type1.gif)
> **NOTE**
>
......@@ -43,15 +42,15 @@ To use the singleton mode, set **launchType** in the [module.json5 configuration
```
## Standard
## Multiton
In standard mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**.
In multiton mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**.
**Figure 2** Demonstration effect in standard mode
**Figure 2** Demonstration effect in multiton mode
![standard-mode](figures/standard-mode.png)
![uiability-launch-type2](figures/uiability-launch-type2.gif)
To use the standard mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **standard**.
To use the multiton mode, set **launchType** in the [module.json5 file](../quick-start/module-configuration-file.md) to **multiton**.
```json
......@@ -60,7 +59,7 @@ To use the standard mode, set **launchType** in the [module.json5 configuration
// ...
"abilities": [
{
"launchType": "standard",
"launchType": "multiton",
// ...
}
]
......@@ -73,9 +72,8 @@ To use the standard mode, set **launchType** in the [module.json5 configuration
The **specified** mode is used in some special scenarios. For example, in a document application, you want a document instance to be created each time you create a document, but you want to use the same document instance when you repeatedly open an existing document.
**Figure 3** Demonstration effect in specified mode
![uiability-launch-type2](figures/uiability-launch-type2.png)
**Figure 3** Demonstration effect in specified mode
![uiability-launch-type3](figures/uiability-launch-type3.gif)
For example, there are two UIAbility components: EntryAbility and SpecifiedAbility (with the launch type **specified**). You are required to start SpecifiedAbility from EntryAbility.
......@@ -155,3 +153,5 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili
2. Close the process of file A in **Recents**. UIAbility instance 1 is destroyed. Return to the home screen and open file A again. A new UIAbility instance is started, for example, UIAbility instance 2.
3. Return to the home screen and open file B. A new UIAbility instance is started, for example, UIAbility instance 3.
4. Return to the home screen and open file A again. UIAbility instance 2 is started. This is because the system automatically matches the key of the UIAbility instance and starts the UIAbility instance that has a matching key. In this example, UIAbility instance 2 has the same key as file A. Therefore, the system pulls back UIAbility instance 2 and focuses it without creating a new instance.
<!--no_check-->
\ No newline at end of file
......@@ -11,7 +11,7 @@ The following design philosophy is behind UIAbility:
2. Support for multiple device types and window forms
For details, see [Interpretation of the Application Model](application-model-description.md).
For details, see [Interpretation of the Application Model] (application-model-description.md).
The UIAbility division principles and suggestions are as follows:
......@@ -37,7 +37,7 @@ To enable an application to properly use a UIAbility component, declare the UIAb
"abilities": [
{
"name": "EntryAbility", // Name of the UIAbility component.
"srcEntrance": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component.
"srcEntry": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component.
"description": "$string:EntryAbility_desc", // Description of the UIAbility component.
"icon": "$media:icon", // Icon of the UIAbility component.
"label": "$string:EntryAbility_label", // Label of the UIAbility component.
......
......@@ -323,7 +323,7 @@ async function deleteFormInfo(formId: string) {
// ...
```
For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md).
For details about how to implement persistent data storage, see [Application Data Persistence Overview](../database/app-data-persistence-overview.md).
The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary.
......@@ -364,7 +364,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi
> **NOTE**
>
> Only the JavaScript-based web-like development paradigm is supported when developing the widget UI.
> In the FA model, only the JavaScript-based web-like development paradigm is supported when developing the widget UI.
- HML: uses web-like paradigm components to describe the widget page information.
......
......@@ -11,7 +11,7 @@ Widget switching involves the following parts:
| Configuration Item | FA Model | Stage Model |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------ |
| Configuration item location | **formAbility** and **forms** are in the **config.json** file.| **extensionAbilities** (configuration for **formExtensionAbility**) is in the **module.json5** file in the level-1 directory, and **forms** (configuration for **forms** contained in **formExtensionAbility**) is in the **form_config.json** file in the level-2 directory.|
| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEntrance**, with the file name. |
| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEntry**, with the file name. |
| Programming language | **srcLanguage** can be set to **js** or **ets**. | This configuration item is unavailable. Only ets is supported. |
| Whether to enable widgets | formsEnabled | This configuration item is unavailable. The setting of **type** set to **form** means that the widgets are enabled. |
| Ability type | type: service | type: form |
......@@ -32,7 +32,7 @@ Figure 2 Widget configuration differences
| Item| FA Model| Stage Model|
| -------- | -------- | -------- |
| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEntrance**|
| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEntry**|
| Lifecycle| export default| import FormExtension from '\@ohos.app.form.FormExtensionAbility';<br>export default class FormAbility extends FormExtension|
......
# WindowExtensionAbility
[WindowExtensionAbility](../reference/apis/js-apis-application-windowExtensionAbility.md) is a type of ExtensionAbility component that allows a system application to be embedded in and displayed over another application.
The WindowExtensionAbility component must be used together with the [AbilityComponent](../reference/arkui-ts/ts-container-ability-component.md) to process services of the started application. WindowExtensionAbility is run in connection mode. A system application must use the AbilityComponent to start the WindowExtensionAbility component.
Each ExtensionAbility has its own context. For WindowExtensionAbility,
the context is [WindowExtensionContext](../reference/apis/js-apis-inner-application-windowExtensionContext.md).
the context is [WindowExtensionContext](../reference/apis/js-apis-inner-application-windowExtensionContext.md).
> **NOTE**
>
......@@ -14,7 +15,7 @@ the context is [WindowExtensionContext](../reference/apis/js-apis-inner-applicat
>
## Setting an Embedded Ability (for System Applications Only)
## Setting an Embedded UIAbility (for System Applications Only)
The **WindowExtensionAbility** class provides **onConnect()**, **onDisconnect()**, and **onWindowReady()** lifecycle callbacks, which can be overridden.
......@@ -58,7 +59,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i
}
```
4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEntrance** to the code path of the ExtensionAbility component.
4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEntry** to the code path of the ExtensionAbility component.
```json
{
......@@ -66,11 +67,11 @@ To implement an embedded application, manually create a WindowExtensionAbility i
"extensionAbilities": [
{
"name": "WindowExtAbility",
"srcEntrance": "./ets/WindowExtAbility/WindowExtAbility.ts",
"srcEntry": "./ets/WindowExtAbility/WindowExtAbility.ts",
"icon": "$media:icon",
"description": "WindowExtension",
"type": "window",
"visible": true,
"exported": true,
}
],
}
......@@ -78,7 +79,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i
```
## Starting an Embedded Ability (for System Applications Only)
## Starting an Embedded UIAbility (for System Applications Only)
System applications can load the created WindowExtensionAbility through the AbilityComponent.
......@@ -90,23 +91,23 @@ System applications can load the created WindowExtensionAbility through the Abil
3. Set the width and height. The sample code is as follows:
```ts
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
AbilityComponent({ abilityName: "WindowExtAbility", bundleName: "com.example.WindowExtAbility"})
.width(500)
.height(500)
}
.width('100%')
}
.height('100%')
.backgroundColor(0x64BB5c)
}
}
```
```ts
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
AbilityComponent({ abilityName: "WindowExtAbility", bundleName: "com.example.WindowExtAbility"})
.width(500)
.height(500)
}
.width('100%')
}
.height('100%')
.backgroundColor(0x64BB5c)
}
}
```
\ No newline at end of file
......@@ -9,6 +9,7 @@
- [Network Sharing](net-sharing.md)
- [Ethernet Connection](net-ethernet.md)
- [Network Connection Management](net-connection-manager.md)
- [mDNS Management](net-mdns.md)
- IPC & RPC
- [IPC & RPC Overview](ipc-rpc-overview.md)
- [IPC & RPC Development](ipc-rpc-development-guideline.md)
......
......@@ -158,5 +158,4 @@ httpRequest.request2(
httpRequest.destroy();
}
);
```
\ No newline at end of file
......@@ -81,7 +81,7 @@ For the complete list of APIs and example code, see [Network Connection Manageme
6. Call **conn.unregister()** to unsubscribe from the network status changes if required.
```js
// Import the connection namespace.
// Import the connection namespace.
import connection from '@ohos.net.connection'
let netCap = {
......@@ -128,7 +128,7 @@ conn.unregister((err, data) => {
2. Call **getAllNets** to obtain the list of all connected networks.
```js
// Import the connection namespace.
// Import the connection namespace.
import connection from '@ohos.net.connection'
// Obtain the list of all connected networks.
......@@ -154,7 +154,7 @@ connection.getAllNets((err, data) => {
4. Call **getConnectionProperties** to obtain the connection information of the data network specified by **NetHandle**.
```js
// Import the connection namespace.
// Import the connection namespace.
import connection from '@ohos.net.connection'
// Call getDefaultNet to obtain the default data network specified by **NetHandle**.
......
......@@ -44,7 +44,7 @@ For the complete list of APIs and example code, see [Ethernet Connection](../ref
5. Call **getIfaceConfig** in user mode to obtain the static network attributes of the **eth0** port. By default, an unconfigured Ethernet network uses the DHCP mode, in which the Ethernet network obtains the automatically assigned network attributes.
```js
// Import the ethernet namespace from @ohos.net.ethernet.
// Import the ethernet namespace from @ohos.net.ethernet.
import ethernet from '@ohos.net.ethernet'
// Call getAllActiveIfaces to obtain the list of all active network ports.
......@@ -96,7 +96,7 @@ ethernet.getIfaceConfig("eth0", (error, data) => {
6. Call **getIfaceConfig** in user mode to obtain the static network attributes of the **eth0** port.
```js
// Import the ethernet namespace from @ohos.net.ethernet.
// Import the ethernet namespace from @ohos.net.ethernet.
import ethernet from '@ohos.net.ethernet'
// Call getAllActiveIfaces to obtain the list of all active network ports.
......@@ -158,13 +158,13 @@ ethernet.getIfaceConfig("eth0", (error, data) => {
4. Call the **off()** method to unsubscribe from **interfaceStateChange** events.
```js
// Import the ethernet namespace from @ohos.net.ethernet.
// Import the ethernet namespace from @ohos.net.ethernet.
import ethernet from '@ohos.net.ethernet'
// Subscribe to interfaceStateChange events.
ethernet.on('interfaceStateChange', ((data) => {
ethernet.on('interfaceStateChange', (data) => {
console.log(JSON.stringify(data));
}));
});
// Unsubscribe from interfaceStateChange events.
ethernet.off('interfaceStateChange');
......
# MDNS Management
## Introduction
Multicast DNS (mDNS) provides functions such as adding, removing, discovering, and resolving local services on a LAN.
- Local service: a service provider on a LAN, for example, a printer or scanner.
Typical MDNS management scenarios include:
- Managing local services on a LAN, such as adding, removing, and resolving local services.
- Discovering local services and listening to the status changes of local services of the specified type through the **DiscoveryService** object.
> **NOTE**
> To maximize the application running efficiency, most API calls are called asynchronously in callback or promise mode. The following code examples use the callback mode. For details about the APIs, see [mDNS Management](../reference/apis/js-apis-net-mdns.md).
The following describes the development procedure specific to each application scenario.
## Available APIs
For the complete list of APIs and example code, see [mDNS Management](../reference/apis/js-apis-net-mdns.md).
| Type| API| Description|
| ---- | ---- | ---- |
| ohos.net.mdns | addLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback\<LocalServiceInfo>): void | Adds an mDNS service. This API uses an asynchronous callback to return the result.|
| ohos.net.mdns | removeLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback\<LocalServiceInfo>): void | Removes an mDNS service. This API uses an asynchronous callback to return the result.|
| ohos.net.mdns | createDiscoveryService(context: Context, serviceType: string): DiscoveryService | Creates a **DiscoveryService** object, which is used to discover mDNS services of the specified type.|
| ohos.net.mdns | resolveLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback\<LocalServiceInfo>): void | Resolves an mDNS service. This API uses an asynchronous callback to return the result.|
| ohos.net.mdns.DiscoveryService | startSearchingMDNS(): void | Searches for mDNS services on the LAN.|
| ohos.net.mdns.DiscoveryService | stopSearchingMDNS(): void | Stops searching for mDNS services on the LAN.|
| ohos.net.mdns.DiscoveryService | on(type: 'discoveryStart', callback: Callback<{serviceInfo: LocalServiceInfo, errorCode?: MdnsError}>): void | Enables listening for **discoveryStart** events.|
| ohos.net.mdns.DiscoveryService | on(type: 'discoveryStop', callback: Callback<{serviceInfo: LocalServiceInfo, errorCode?: MdnsError}>): void | Enables listening for **discoveryStop** events.|
| ohos.net.mdns.DiscoveryService | on(type: 'serviceFound', callback: Callback\<LocalServiceInfo>): void | Enables listening for **serviceFound** events.|
| ohos.net.mdns.DiscoveryService | on(type: 'serviceLost', callback: Callback\<LocalServiceInfo>): void | Enables listening for **serviceLost** events.|
## Managing Local Services
1. Connect the device to the Wi-Fi network.
2. Import the **mdns** namespace from **@ohos.net.mdns**.
3. Call **addLocalService** to add a local service.
4. (Optional) Call **resolveLocalService** to resolve the local service for the IP address of the local network.
5. Call **removeLocalService** to remove the local service.
```js
// Import the mdns namespace from @ohos.net.mdns.
import mdns from '@ohos.net.mdns'
// Obtain the context of the FA model.
import featureAbility from '@ohos.ability.featureAbility';
let context = featureAbility.getContext();
// Obtain the context of the stage model.
import UIAbility from '@ohos.app.ability.UIAbility';
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
globalThis.context = this.context;
}
}
let context = globalThis.context;
// Create a LocalService object.
let localServiceInfo = {
serviceType: "_print._tcp",
serviceName: "servicename",
port: 5555,
host: {
address: "10.14.**.***",
},
serviceAttribute: [{
key: "111",
value: [1]
}]
}
// Call addLocalService to add a local service.
mdns.addLocalService(context, localServiceInfo, function (error, data) {
console.log(JSON.stringify(error));
console.log(JSON.stringify(data));
});
// (Optional) Call resolveLocalService to resolve the local service.
mdns.resolveLocalService(context, localServiceInfo, function (error, data) {
console.log(JSON.stringify(error));
console.log(JSON.stringify(data));
});
// Call removeLocalService to remove the local service.
mdns.removeLocalService(context, localServiceInfo, function (error, data) {
console.log(JSON.stringify(error));
console.log(JSON.stringify(data));
});
```
## Discovering Local Services
1. Connect the device to the Wi-Fi network.
2. Import the **mdns** namespace from **@ohos.net.mdns**.
3. Create a **DiscoveryService** object, which is used to discover mDNS services of the specified type.
4. Subscribe to mDNS service discovery status changes.
5. Enable discovery of mDNS services on the LAN.
6. Stop searching for mDNS services on the LAN.
```js
// Import the mdns namespace from @ohos.net.mdns.
import mdns from '@ohos.net.mdns'
// Obtain the context of the FA model.
import featureAbility from '@ohos.ability.featureAbility';
let context = featureAbility.getContext();
// Obtain the context of the stage model.
import UIAbility from '@ohos.app.ability.UIAbility';
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
globalThis.context = this.context;
}
}
let context = globalThis.context;
// Create a LocalService object.
let localServiceInfo = {
serviceType: "_print._tcp",
serviceName: "servicename",
port: 5555,
host: {
address: "10.14.**.***",
},
serviceAttribute: [{
key: "111",
value: [1]
}]
}
// Create a DiscoveryService object, which is used to discover mDNS services of the specified type.
let serviceType = "_print._tcp";
let discoveryService = mdns.createDiscoveryService(context, serviceType);
// Subscribe to mDNS service discovery status changes.
discoveryService.on('discoveryStart', (data) => {
console.log(JSON.stringify(data));
});
discoveryService.on('discoveryStop', (data) => {
console.log(JSON.stringify(data));
});
discoveryService.on('serviceFound', (data) => {
console.log(JSON.stringify(data));
});
discoveryService.on('serviceLost', (data) => {
console.log(JSON.stringify(data));
});
// Enable discovery of mDNS services on the LAN.
discoveryService.startSearchingMDNS();
// Stop searching for mDNS services on the LAN.
discoveryService.stopSearchingMDNS();
```
......@@ -2,13 +2,14 @@
Network management functions include:
- [HTTP data request](http-request.md): Initiates a data request through HTTP.
- [WebSocket connection](websocket-connection.md): Establishes a bidirectional connection between the server and client through WebSocket.
- [Socket connection](socket-connection.md): Transmits data through Socket.
- [Network policy management](net-policy-management.md): Restricts network capabilities by setting network policies, including cellular network policy, sleep/power-saving mode policy, and background network policy, and resets network policies as needed.
- [Network sharing](net-sharing.md): Shares a device's Internet connection with other connected devices by means of Wi-Fi hotspot, Bluetooth, and USB sharing, and queries the network sharing state and shared mobile data volume.
- [Ethernet connection](net-ethernet.md): Provides wired network capabilities, which allow you to set the IP address, subnet mask, gateway, and Domain Name System (DNS) server of a wired network.
- [Network connection management](net-connection-manager.md): Provides basic network management capabilities, including management of Wi-Fi/cellular/Ethernet connection priorities, network quality evaluation, subscription to network connection status changes, query of network connection information, and DNS resolution.
- [HTTP data request](http-request.md): initiates a data request through HTTP.
- [WebSocket connection](websocket-connection.md): establishes a bidirectional connection between the server and client through WebSocket.
- [Socket connection](socket-connection.md): transmits data through Socket.
- [Network policy management](net-policy-management.md): restricts network capabilities by setting network policies, including cellular network policy, sleep/power-saving mode policy, and background network policy, and resets network policies as needed.
- [Network sharing](net-sharing.md): shares a device's Internet connection with other connected devices by means of Wi-Fi hotspot, Bluetooth, and USB sharing, and queries the network sharing state and shared mobile data volume.
- [Ethernet connection](net-ethernet.md): provides wired network capabilities, which allow you to set the IP address, subnet mask, gateway, and Domain Name System (DNS) server of a wired network.
- [Network connection management](net-connection-manager.md): provides basic network management capabilities, including management of Wi-Fi/cellular/Ethernet connection priorities, network quality evaluation, subscription to network connection status changes, query of network connection information, and DNS resolution.
- [mDNS management](net-mdns.md): provides Multicast DNS (mDNS) management capabilities, such as adding, removing, discovering, and resolving local services on a LAN.
## Constraints
......
......@@ -60,7 +60,7 @@ For the complete list of APIs and example code, see [Network Sharing](../referen
4. Return the callback for successfully starting network sharing.
```js
// Import the sharing namespace from @ohos.net.sharing.
// Import the sharing namespace from @ohos.net.sharing.
import sharing from '@ohos.net.sharing'
// Subscribe to network sharing state changes.
......@@ -85,7 +85,7 @@ sharing.startSharing(sharing.SharingIfaceType.SHARING_WIFI, (error) => {
4. Return the callback for successfully stopping network sharing.
```js
// Import the sharing namespace from @ohos.net.sharing.
// Import the sharing namespace from @ohos.net.sharing.
import sharing from '@ohos.net.sharing'
// Subscribe to network sharing state changes.
......@@ -110,7 +110,7 @@ sharing.stopSharing(sharing.SharingIfaceType.SHARING_WIFI, (error) => {
4. Call **stopSharing** to stop network sharing of the specified type and clear the data volume of network sharing.
```js
// Import the sharing namespace from @ohos.net.sharing.
// Import the sharing namespace from @ohos.net.sharing.
import sharing from '@ohos.net.sharing'
// Call startSharing to start network sharing of the specified type.
......
......@@ -87,81 +87,81 @@ The implementation is similar for UDP Socket and TCP Socket connections. The fol
7. Enable the TCP Socket connection to be automatically closed after use.
```js
import socket from '@ohos.net.socket'
// Create a TCPSocket object.
let tcp = socket.constructTCPSocketInstance();
// Subscribe to TCP Socket connection events.
tcp.on('message', value => {
console.log("on message")
let buffer = value.message
let dataView = new DataView(buffer)
let str = ""
for (let i = 0;i < dataView.byteLength; ++i) {
str += String.fromCharCode(dataView.getUint8(i))
}
console.log("on connect received:" + str)
});
tcp.on('connect', () => {
console.log("on connect")
});
tcp.on('close', () => {
console.log("on close")
});
// Bind the local IP address and port number.
let bindAddress = {
address: '192.168.xx.xx',
port: 1234, // Bound port, for example, 1234.
family: 1
};
tcp.bind(bindAddress, err => {
if (err) {
console.log('bind fail');
return;
}
console.log('bind success');
// Set up a connection to the specified IP address and port number.
let connectAddress = {
address: '192.168.xx.xx',
port: 5678, // Connection port, for example, 5678.
family: 1
};
tcp.connect({
address: connectAddress, timeout: 6000
}, err => {
if (err) {
console.log('connect fail');
return;
}
console.log('connect success');
// Send data.
tcp.send({
data: 'Hello, server!'
}, err => {
if (err) {
console.log('send fail');
return;
}
console.log('send success');
})
});
});
// Enable the TCP Socket connection to be automatically closed after use. Then, disable listening for TCP Socket connection events.
setTimeout(() => {
tcp.close((err) => {
console.log('close socket.')
});
tcp.off('message');
tcp.off('connect');
tcp.off('close');
}, 30 * 1000);
```
```js
import socket from '@ohos.net.socket'
// Create a TCPSocket object.
let tcp = socket.constructTCPSocketInstance();
// Subscribe to TCP Socket connection events.
tcp.on('message', value => {
console.log("on message")
let buffer = value.message
let dataView = new DataView(buffer)
let str = ""
for (let i = 0; i < dataView.byteLength; ++i) {
str += String.fromCharCode(dataView.getUint8(i))
}
console.log("on connect received:" + str)
});
tcp.on('connect', () => {
console.log("on connect")
});
tcp.on('close', () => {
console.log("on close")
});
// Bind the local IP address and port number.
let bindAddress = {
address: '192.168.xx.xx',
port: 1234, // Bound port, for example, 1234.
family: 1
};
tcp.bind(bindAddress, err => {
if (err) {
console.log('bind fail');
return;
}
console.log('bind success');
// Set up a connection to the specified IP address and port number.
let connectAddress = {
address: '192.168.xx.xx',
port: 5678, // Connection port, for example, 5678.
family: 1
};
tcp.connect({
address: connectAddress, timeout: 6000
}, err => {
if (err) {
console.log('connect fail');
return;
}
console.log('connect success');
// Send data.
tcp.send({
data: 'Hello, server!'
}, err => {
if (err) {
console.log('send fail');
return;
}
console.log('send success');
})
});
});
// Enable the TCP Socket connection to be automatically closed after use. Then, disable listening for TCP Socket connection events.
setTimeout(() => {
tcp.close((err) => {
console.log('close socket.')
});
tcp.off('message');
tcp.off('connect');
tcp.off('close');
}, 30 * 1000);
```
## Implementing Encrypted Data Transmission over TLS Socket Connections
......@@ -184,7 +184,7 @@ TLS Socket connection process on the client:
7. Enable the TLS Socket connection to be automatically closed after use.
```js
import socket from '@ohos.net.socket'
import socket from '@ohos.net.socket'
// Create a TLS Socket connection (for two-way authentication).
let tlsTwoWay = socket.constructTLSSocketInstance();
......@@ -208,7 +208,7 @@ tlsTwoWay.on('close', () => {
});
// Bind the local IP address and port number.
tlsTwoWay.bind({address: '192.168.xxx.xxx', port: xxxx, family: 1}, err => {
tlsTwoWay.bind({ address: '192.168.xxx.xxx', port: xxxx, family: 1 }, err => {
if (err) {
console.log('bind fail');
return;
......@@ -280,7 +280,7 @@ tlsTwoWay.on('close', () => {
});
// Bind the local IP address and port number.
tlsOneWay.bind({address: '192.168.xxx.xxx', port: xxxx, family: 1}, err => {
tlsOneWay.bind({ address: '192.168.xxx.xxx', port: xxxx, family: 1 }, err => {
if (err) {
console.log('bind fail');
return;
......@@ -318,4 +318,12 @@ tlsTwoWay.close((err) => {
tlsTwoWay.off('connect');
tlsTwoWay.off('close');
});
```
\ No newline at end of file
```
## Samples
The following samples are provided to help you better understand how to develop Socket connection features:
- [`Socket`: Socket Connection (ArkTS) (API9)] (https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Connectivity/Socket)
- [UDP Socket (ArkTS) (API9)](https://gitee.com/openharmony/codelabs/tree/master/NetworkManagement/UdpDemoOH)
- [TCP Socket (ArkTS) (API9)](https://gitee.com/openharmony/codelabs/tree/master/NetworkManagement/TcpSocketDemo)
......@@ -37,46 +37,52 @@ The WebSocket connection function is mainly implemented by the WebSocket module.
5. Close the WebSocket connection if it is no longer needed.
```js
import webSocket from '@ohos.net.webSocket';
var defaultIpAddress = "ws://";
let ws = webSocket.createWebSocket();
ws.on('open', (err, value) => {
console.log("on open, status:" + JSON.stringify(value));
// When receiving the on('open') event, the client can use the send() API to communicate with the server.
ws.send("Hello, server!", (err, value) => {
if (!err) {
console.log("Message sent successfully");
} else {
console.log("Failed to send the message. Err:" + JSON.stringify(err));
}
});
});
ws.on('message', (err, value) => {
console.log("on message, message:" + value);
// When receiving the `bye` message (the actual message name may differ) from the server, the client proactively disconnects from the server.
if (value === 'bye') {
ws.close((err, value) => {
if (!err) {
console.log("Connection closed successfully");
} else {
console.log("Failed to close the connection. Err: " + JSON.stringify(err));
}
});
}
});
ws.on('close', (err, value) => {
console.log("on close, code is " + value.code + ", reason is " + value.reason);
});
ws.on('error', (err) => {
console.log("on error, error:" + JSON.stringify(err));
});
ws.connect(defaultIpAddress, (err, value) => {
if (!err) {
console.log("Connected successfully");
} else {
console.log("Connection failed. Err:" + JSON.stringify(err));
}
});
```
```js
import webSocket from '@ohos.net.webSocket';
var defaultIpAddress = "ws://";
let ws = webSocket.createWebSocket();
ws.on('open', (err, value) => {
console.log("on open, status:" + JSON.stringify(value));
// When receiving the on('open') event, the client can use the send() API to communicate with the server.
ws.send("Hello, server!", (err, value) => {
if (!err) {
console.log("Message sent successfully");
} else {
console.log("Failed to send the message. Err:" + JSON.stringify(err));
}
});
});
ws.on('message', (err, value) => {
console.log("on message, message:" + value);
// When receiving the `bye` message (the actual message name may differ) from the server, the client proactively disconnects from the server.
if (value === 'bye') {
ws.close((err, value) => {
if (!err) {
console.log("Connection closed successfully");
} else {
console.log("Failed to close the connection. Err: " + JSON.stringify(err));
}
});
}
});
ws.on('close', (err, value) => {
console.log("on close, code is " + value.code + ", reason is " + value.reason);
});
ws.on('error', (err) => {
console.log("on error, error:" + JSON.stringify(err));
});
ws.connect(defaultIpAddress, (err, value) => {
if (!err) {
console.log("Connected successfully");
} else {
console.log("Connection failed. Err:" + JSON.stringify(err));
}
});
```
## Samples
The following samples are provided to help you better understand how to develop WebSocket connection features:
- [`WebSocket`: WebSocket (ArkTS) (API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Connectivity/WebSocket)
......@@ -5,7 +5,7 @@
- [Overview of Application Data Persistence](app-data-persistence-overview.md)
- [Persisting Preferences Data](data-persistence-by-preferences.md)
- [Persisting KV Store Data](data-persistence-by-kv-store.md)
- [Persisting RDB Store Data] (data-persistence-by-rdb-store.md)
- [Persisting RDB Store Data](data-persistence-by-rdb-store.md)
- Distributed Application Data Synchronization
- [Distributed Application Data Synchronization Overview](sync-app-data-across-devices-overview.md)
- [Cross-Device Synchronization of KV Stores](data-sync-of-kv-store.md)
......@@ -16,7 +16,7 @@
- [Database Backup and Restoration](data-backup-and-restore.md)
- [Database Encryption](data-encryption.md)
- [Access Control by Device and Data Level](access-control-by-device-and-data-level.md)
- Cross-Application Data Sharing (Available Only for System Applications)
- Cross-Application Data Sharing (for System Applications Only)
- [Cross-Application Data Sharing Overview](share-device-data-across-apps-overview.md)
- [Sharing Data Using DataShareExtensionAbility](share-data-by-datashareextensionability.md)
- [Sharing Data in Silent Access](share-data-by-silent-access.md)
......@@ -32,8 +32,9 @@ The following table lists the APIs used for KV data persistence. Most of the API
## How to Develop
1. Create a **KvManager** instance to manage database objects. Example:
1. Create a **KvManager** instance to manage database objects.
Example:
Stage model:
......@@ -90,13 +91,14 @@ The following table lists the APIs used for KV data persistence. Most of the API
}
```
2. Create and obtain a KV store. Example:
2. Create and obtain a KV store.
Example:
```js
try {
const options = {
createIfMissing: true, // Whether to create a KV store when the database file does not exist. By default, a KV store is created.
createIfMissing: true, // Whether to encrypt database files. By default, database files are not encrypted.
encrypt: false, // Whether to encrypt the KV store. By default, KV stores are not encrypted.
backup: false, // Whether to back up database files. By default, the database files are backed up.
autoSync: true, // Whether to automatically synchronize database files. The value **true** means to automatically synchronize database files; the value **false** (default) means the opposite.
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // Type of the KV store to create. By default, a device KV store is created.
......@@ -116,8 +118,9 @@ The following table lists the APIs used for KV data persistence. Most of the API
}
```
3. Use **put()** to add data to the KV store. Example:
3. Use **put()** to add data to the KV store.
Example:
```js
const KEY_TEST_STRING_ELEMENT = 'key_test_string';
const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
......@@ -138,8 +141,9 @@ The following table lists the APIs used for KV data persistence. Most of the API
>
> The **put()** method adds a KV pair if the specified key does not exists and changes the value if the the specified key already exists.
4. Use **get()** to obtain the value of a key. Example:
4. Use **get()** to obtain the value of a key.
Example:
```js
const KEY_TEST_STRING_ELEMENT = 'key_test_string';
const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
......@@ -163,8 +167,9 @@ The following table lists the APIs used for KV data persistence. Most of the API
}
```
5. Use **delete()** to delete the data of the specified key. Example:
5. Use **delete()** to delete the data of the specified key.
Example:
```js
const KEY_TEST_STRING_ELEMENT = 'key_test_string';
const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
......
......@@ -10,7 +10,9 @@ The **Preferences** module provides APIs for processing data in the form of key-
User applications call **Preference** through the JS interface to read and write data files. You can load the data of a **Preferences** persistence file to a **Preferences** instance. Each file uniquely corresponds to an instance. The system stores the instance in memory through a static container until the instance is removed from the memory or the file is deleted. The following figure illustrates how **Preference** works.
**Figure 1** Preferences working mechanism
The preference persistent file of an application is stored in the application sandbox. You can use **context** to obtain the file path. For details, see [Obtaining the Application Development Path](../application-models/application-context-stage.md#obtaining-the-application-development-path).
**Figure 1** Preferences working mechanism
![preferences](figures/preferences.jpg)
......@@ -28,23 +30,23 @@ User applications call **Preference** through the JS interface to read and write
The following table lists the APIs used for preferences data persistence. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [User Preferences](../reference/apis/js-apis-data-preferences.md).
| API| Description|
| API| Description|
| -------- | -------- |
| getPreferences(context: Context, name: string, callback: AsyncCallback&lt;Preferences&gt;): void | Obtain a **Preferences** instance.|
| put(key: string, value: ValueType, callback: AsyncCallback&lt;void&gt;): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data.|
| has(key: string, callback: AsyncCallback&lt;boolean&gt;): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty.|
| get(key: string, defValue: ValueType, callback: AsyncCallback&lt;ValueType&gt;): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned.|
| delete(key: string, callback: AsyncCallback&lt;void&gt;): void | Deletes the KV pair with the given key from the **Preferences** instance.|
| flush(callback: AsyncCallback&lt;void&gt;): void | Flushes the data of this **Preferences** instance to a file for data persistence.|
| on(type: 'change', callback: Callback&lt;{ key : string }&gt;): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data.|
| off(type: 'change', callback?: Callback&lt;{ key : string }&gt;): void | Unsubscribes from data changes.|
| deletePreferences(context: Context, name: string, callback: AsyncCallback&lt;void&gt;): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.|
| getPreferences(context: Context, name: string, callback: AsyncCallback&lt;Preferences&gt;): void | Obtain a **Preferences** instance.|
| put(key: string, value: ValueType, callback: AsyncCallback&lt;void&gt;): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data.|
| has(key: string, callback: AsyncCallback&lt;boolean&gt;): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty.|
| get(key: string, defValue: ValueType, callback: AsyncCallback&lt;ValueType&gt;): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned.|
| delete(key: string, callback: AsyncCallback&lt;void&gt;): void | Deletes the KV pair with the given key from the **Preferences** instance.|
| flush(callback: AsyncCallback&lt;void&gt;): void | Flushes the data of this **Preferences** instance to a file for data persistence.|
| on(type: 'change', callback: Callback&lt;{ key : string }&gt;): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data.|
| off(type: 'change', callback?: Callback&lt;{ key : string }&gt;): void | Unsubscribes from data changes.|
| deletePreferences(context: Context, name: string, callback: AsyncCallback&lt;void&gt;): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.|
## How to Develop
1. Import the **@ohos.data.preferences** module.
```js
import dataPreferences from '@ohos.data.preferences';
```
......@@ -53,7 +55,7 @@ The following table lists the APIs used for preferences data persistence. Most o
Stage model:
```js
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -77,7 +79,7 @@ The following table lists the APIs used for preferences data persistence. Most o
FA model:
```js
import featureAbility from '@ohos.ability.featureAbility';
......@@ -108,7 +110,7 @@ The following table lists the APIs used for preferences data persistence. Most o
Example:
```js
try {
preferences.has('startup', function (err, val) {
......@@ -157,11 +159,11 @@ The following table lists the APIs used for preferences data persistence. Most o
}
```
5. Deletes data.
5. Delete data.
Use delete() to delete a KV pair.<br>Example:
```js
try {
preferences.delete('startup', (err) => {
......@@ -232,7 +234,7 @@ The following table lists the APIs used for preferences data persistence. Most o
Example:
```js
try {
dataPreferences.deletePreferences(this.context, 'mystore', (err, val) => {
......@@ -245,4 +247,4 @@ The following table lists the APIs used for preferences data persistence. Most o
} catch (err) {
console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
}
```
```
\ No newline at end of file
......@@ -18,7 +18,7 @@ A relational database (RDB) store is used to store data in complex relational mo
**RelationalStore** provides APIs for applications to perform data operations. With SQLite as the underlying persistent storage engine, **RelationalStore** provides SQLite database features, including transactions, indexes, views, triggers, foreign keys, parameterized queries, prepared SQL statements, and more.
**Figure 1** Working mechanism
![relationStore_local](figures/relationStore_local.jpg)
......@@ -37,15 +37,15 @@ A relational database (RDB) store is used to store data in complex relational mo
The following table lists the APIs used for RDB data persistence. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md).
| API| Description|
| API| Description|
| -------- | -------- |
| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback&lt;RdbStore&gt;): void | Obtains a **RdbStore** instance to implement RDB store operations. You can set **RdbStore** parameters based on actual requirements and use **RdbStore** APIs to perform data operations.|
| executeSql(sql: string, bindArgs: Array&lt;ValueType&gt;, callback: AsyncCallback&lt;void&gt;):void | Executes an SQL statement that contains specified arguments but returns no value.|
| insert(table: string, values: ValuesBucket, callback: AsyncCallback&lt;number&gt;):void | Inserts a row of data into a table.|
| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback&lt;number&gt;):void | Updates data in the RDB store based on the specified **RdbPredicates** instance.|
| delete(predicates: RdbPredicates, callback: AsyncCallback&lt;number&gt;):void | Deletes data from the RDB store based on the specified **RdbPredicates** instance.|
| query(predicates: RdbPredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;ResultSet&gt;):void | Queries data in the RDB store based on specified conditions.|
| deleteRdbStore(context: Context, name: string, callback: AsyncCallback&lt;void&gt;): void | Deletes an RDB store.|
| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback&lt;RdbStore&gt;): void | Obtains a **RdbStore** instance to implement RDB store operations. You can set **RdbStore** parameters based on actual requirements and use **RdbStore** APIs to perform data operations.|
| executeSql(sql: string, bindArgs: Array&lt;ValueType&gt;, callback: AsyncCallback&lt;void&gt;):void | Executes an SQL statement that contains specified arguments but returns no value.|
| insert(table: string, values: ValuesBucket, callback: AsyncCallback&lt;number&gt;):void | Inserts a row of data into a table.|
| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback&lt;number&gt;):void | Updates data in the RDB store based on the specified **RdbPredicates** instance.|
| delete(predicates: RdbPredicates, callback: AsyncCallback&lt;number&gt;):void | Deletes data from the RDB store based on the specified **RdbPredicates** instance.|
| query(predicates: RdbPredicates, columns: Array&lt;string&gt;, callback: AsyncCallback&lt;ResultSet&gt;):void | Queries data in the RDB store based on specified conditions.|
| deleteRdbStore(context: Context, name: string, callback: AsyncCallback&lt;void&gt;): void | Deletes an RDB store.|
## How to Develop
......@@ -53,7 +53,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
1. Obtain an **RdbStore** instance.<br> Example:
Stage model:
```js
import relationalStore from '@ohos.data.relationalStore'; // Import the module.
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -84,7 +84,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
FA model:
```js
import relationalStore from '@ohos.data.relationalStore'; // Import the module.
import featureAbility from '@ohos.ability.featureAbility';
......@@ -119,7 +119,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
> - When an application calls **getRdbStore()** to obtain an RDB store instance for the first time, the corresponding database file is generated in the application sandbox. If you want to move the files of an RDB store to another place for view, you must also move the temporary files with finename extensions **-wal** or **-shm** in the same directory. Once an application is uninstalled, the database files and temporary files generated by the application on the device are also removed.
2. Use **insert()** to insert data to the RDB store. Example:
```js
const valueBucket = {
'NAME': 'Lisa',
......@@ -142,8 +142,10 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
3. Modify or delete data based on the specified **Predicates** instance.
Use **update()** to modify data and **delete()** to delete data. Example:
Use **update()** to modify data and **delete()** to delete data.
Example:
```js
// Modify data.
const valueBucket = {
......@@ -176,8 +178,10 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
4. Query data based on the conditions specified by **Predicates**.
Use **query()** to query data. The data obtained is returned in a **ResultSet** object. Example:
Use **query()** to query data. The data obtained is returned in a **ResultSet** object.
Example:
```js
let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
predicates.equalTo('NAME', 'Rose');
......@@ -197,11 +201,13 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
5. Delete the RDB store.
Use **deleteRdbStore()** to delete the RDB store and related database files. Example:
Use **deleteRdbStore()** to delete the RDB store and related database files.
Stage model:
Example:
Stage model:
```js
import UIAbility from '@ohos.app.ability.UIAbility';
......@@ -215,12 +221,12 @@ The following table lists the APIs used for RDB data persistence. Most of the AP
console.info('Succeeded in deleting RdbStore.');
});
}
}
}
```
FA model:
```js
import featureAbility from '@ohos.ability.featureAbility';
......
......@@ -68,7 +68,7 @@ When data is added, deleted, or modified, a notification is sent to the subscrib
- The KV stores do not support custom conflict resolution policies for applications.
- A maximum of 16 distributed KV stores can be opened simultaneously for an application.
- A maximum of 16 KV stores can be opened simultaneously for an application.
- Each KV store supports a maximum of eight callbacks for subscription of data change notifications.
......@@ -91,7 +91,7 @@ The following table lists the APIs for cross-device data synchronization of the
## How to Develop
The following uses a single KV store as an example to describe how to implement cross-device data synchronization. The following describes the development process.
The following uses a single KV store as an example to describe how to implement cross-device data synchronization. The development process is as follows.
![kvStore_development_process](figures/kvStore_development_process.png)
......
......@@ -3,7 +3,7 @@
## When to Use
When creating a data table, you can set the table to support cross-device access. You can also use APIs to move the data to be accessed across devices to a distributed data.
You can synchronize the application data in a local RDB store on a device to other divices that form a Super Device.
## Basic Concepts
......@@ -51,14 +51,14 @@ When data is added, deleted, or modified, a notification is sent to the subscrib
The following table lists the APIs for cross-device data synchronization of RDB stores. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md).
| API| Description|
| API| Description|
| -------- | -------- |
| setDistributedTables(tables: Array&lt;string&gt;, callback: AsyncCallback&lt;void&gt;): void | Sets the distributed tables to be synchronized.|
| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback&lt;Array&lt;[string, number]&gt;&gt;): void | Synchronizes data across devices.|
| on(event: 'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Subscribes to changes in the distributed data.|
| off(event:'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Unsubscribe from changes in the distributed data.|
| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback&lt;string&gt;): void; | Obtains the table name on the specified device based on the local table name.|
| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array&lt;string&gt; , callback: AsyncCallback&lt;ResultSet&gt;): void | Queries data from the RDB store of a remote device based on specified conditions.|
| setDistributedTables(tables: Array&lt;string&gt;, callback: AsyncCallback&lt;void&gt;): void | Sets the distributed tables to be synchronized.|
| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback&lt;Array&lt;[string, number]&gt;&gt;): void | Synchronizes data across devices.|
| on(event: 'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Subscribes to changes in the distributed data.|
| off(event:'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Unsubscribe from changes in the distributed data.|
| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback&lt;string&gt;): void; | Obtains the table name on the specified device based on the local table name.|
| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array&lt;string&gt; , callback: AsyncCallback&lt;ResultSet&gt;): void | Queries data from the RDB store of a remote device based on specified conditions.|
## How to Develop
......@@ -68,7 +68,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
> The data on a device can be synchronized only to the devices whose data security labels are not higher than the security level of the device. For details, see [Access Control Mechanism in Cross-Device Synchronization](sync-app-data-across-devices-overview.md#access-control-mechanism-in-cross-device-synchronization).
1. Import the module.
```js
import relationalStore from '@ohos.data.relationalStore';
```
......@@ -79,7 +79,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
2. Display a dialog box to ask authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/accesstoken-guidelines.md#requesting-user-authorization).
3. Create an RDB store and set a table for distributed synchronization.
```js
const STORE_CONFIG = {
name: 'RdbTest.db', // Database file name.
......@@ -95,7 +95,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
```
4. Synchronize data across devices. After **sync()** is called to trigger a synchronization, data is synchronized from the local device to all other devices on the network.
```js
// Construct the predicate object for synchronizing the distributed table.
let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
......@@ -114,7 +114,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
```
5. Subscribe to changes in the distributed data. The data synchronization triggers the **observer** callback registered in **on()**. The input parameter of the callback is the ID of the device whose data changes.
```js
let observer = function storeObserver(devices) {
for (let i = 0; i < devices.length; i++) {
......@@ -144,7 +144,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
>
> **deviceIds** is obtained by using [devManager.getTrustedDeviceListSync](../reference/apis/js-apis-device-manager.md#gettrusteddevicelistsync). The APIs of the **deviceManager** module are all system interfaces and available only to system applications.
```js
// Obtain device IDs.
import deviceManager from '@ohos.distributedHardware.deviceManager';
......
......@@ -16,7 +16,8 @@ There are two roles in **DataShare**:
- Data consumer: accesses the data provided by the provider using [createDataShareHelper()](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper).
**Figure 1** Data sharing mechanism
**Figure 1** Data sharing mechanism
![dataShare](figures/dataShare.jpg)
- The **DataShareExtensionAbility** module, as the data provider, implements services related to data sharing between applications.
......@@ -125,15 +126,15 @@ override the service implementation as required. For example, if the data provid
**Table 1** Fields in module.json5
| Field| Description| Mandatory|
| Field| Description| Mandatory|
| -------- | -------- | -------- |
| name | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**.| Yes|
| type | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template.| Yes|
| uri | URI used for communication. It is the unique identifier for the data consumer to connect to the provider.| Yes|
| exported | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**.| Yes|
| readPermission | Permission required for accessing data. If this parameter is not set, the read permission is not verified by default.| No|
| writePermission | Permission required for modifying data. If this parameter is not set, write permission verification is not performed by default.| No|
| metadata | Configuration for silent access, including the **name** and **resource** fields.<br> The **name** field identifies the configuration, which has a fixed value of **ohos.extension.dataShare**.<br> The **resource** field has a fixed value of **$profile:data_share_config**, which indicates that the profile name is **data_share_config.json**.| **metadata** is mandatory when the ability launch type is **singleton**. For details about the ability launch type, see **launchType** in the [Internal Structure of the abilities Attribute](../quick-start/module-structure.md#internal-structure-of-the-abilities-attribute).|
| name | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**.| Yes|
| type | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template.| Yes|
| uri | URI used for communication. It is the unique identifier for the data consumer to connect to the provider.| Yes|
| exported | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**.| Yes|
| readPermission | Permission required for accessing data. If this parameter is not set, the read permission is not verified by default.| No|
| writePermission | Permission required for modifying data. If this parameter is not set, write permission verification is not performed by default.| No|
| metadata | Configuration for silent access, including the **name** and **resource** fields.<br> The **name** field identifies the configuration, which has a fixed value of **ohos.extension.dataShare**.<br> The **resource** field has a fixed value of **$profile:data_share_config**, which indicates that the profile name is **data_share_config.json**.| **metadata** is mandatory when the ability launch type is **singleton**. For details about the ability launch type, see **launchType** in the [Internal Structure of the abilities Attribute](../quick-start/module-structure.md#internal-structure-of-the-abilities-attribute).|
**module.json5 example**
......
......@@ -3,7 +3,7 @@
## When to Use
According to big data statistics, in a typical cross-application data access scenario, applications are started nearly 83 times on average in a day.
In a typical cross-application data access scenario, an application may be started multiple times.
To reduce the number of application startup times and improve the access speed, OpenHarmony provides the silent access feature, which allows direct access to the database without starting the data provider.
......
# DataShare Overview
# Cross-Application Data Sharing Overview
## Function
The **DataShare** module allows an application to share its data with other applications. Currently, data can be shared only between applications on the same device.
The application data on a device, such as the Contacts, short message service (SMS), and Gallery data, always needs to be shared with other applications. However, certain data, such as the accounts and passwords, cannot be shared. Certain data, such as SMS messages, can be accessed but not modified by other applications. The **DataShare** module provides a secure and easy-to-use mechanism for sharing data of an application with other applications on the same device.
Data needs to be shared in a wealth of scenarios. For example, the Contacts, short message service (SMS), and Gallery data always needs to be shared with other applications. However, certain data, such as accounts and passwords, cannot be shared. Some data, such as SMS messages, can be queried but not modified by other applications. **DataShare** provides a secure and convenient sharing mechanism for application data.
## Basic Concepts
The data provider can directly use **DataShare** to share data with other applications without complex encapsulation. The data consumer only needs to use a set of APIs because the DataShare access mode does not vary with the data provision mode. This greatly reduces the learning time and development difficulty.
Before developing cross-application data sharing on a device, understand the following concepts:
Data can be shared across applications in either of the following ways:
- Data provider: an application that provides data and implements related services. It is also called the data producer or server.
- Using **DataShareExtensionAbility**
An extension ability is implemented in the HAP to invoke a callback. When the data consumer calls an API, the extension ability of the data provider will be automatically started to invoke the registered callback.
- Data consumer: an application that accesses the data or services provided by the data provider. It is also called the client.
You can use **DataShareExtensionAbility** when the cross-application data access involves service operations other than mere addition, deletion, modification, and query of data in databases.
- **ValuesBucket**: a set of data to be inserted. It can be one or more data records in KV pairs. In each KV pair, the key must be of the string type, and the value can be a number, a string, a Boolean value, or an unsigned integer array.
- Using Silent Access
Database access rules are configured in the HAP. When the data consumer calls an API, the system ability automatically obtains the access rules in the HAP and returns data without starting the data provider.
- **ResultSet**: a set of query results. It provides flexible modes for obtaining various data.
You can use the silent access feature when the cross-application data access involves only the operations for adding, deleting, modifying, and querying data in databases.
- **Predicates**: an object that specifies the conditions for updating, deleting, or querying data in a database.
## Basic Concepts
## Implementation
Before developing cross-application data sharing on a device, understand the following concepts:
The data provider can directly use **DataShare** to share data with other applications without complex encapsulation. The data consumer only needs to use a set of APIs to access the data, because the **DataShare** access mode does not vary with the data provisioning mode. This greatly reduces the learning time and development difficulty.
- Data provider: an application that provides data and implements related services. It is also called the producer or server.
The cross-application data sharing can be implemented in either of the following ways:
- Data consumer: an application that accesses the data or services provided by the data provider. It is also called the client.
- **DataShareExtensionAbility**
- **ValuesBucket**: a set of data to be inserted. It can be one or more data records in KV pairs. In each KV pair, the key must be of the string type, and the value can be a number, a string, a Boolean value, or an unsigned integer array.
You can implement an ExtensionAbility with a callback in the HAP. When the data consumer calls an API, the ExtensionAbility of the data provider will be automatically started to invoke the registered callback.
- **ResultSet**: a set of query results. It provides flexible modes for users to obtain various data.
This method is recommended when the cross-application data access involves service operations other than mere addition, deletion, modification, and query of data in databases.
- **Predicates**: an object that specifies the conditions for updating, deleting, or querying data in a database.
- Silent access
You can configure database access rules in the HAP. When the data consumer calls an API, the system ability automatically obtains the access rules in the HAP and returns data without starting the data provider.
This method is recommended when the cross-application data access involves only the operations for adding, deleting, modifying, and querying data in databases.
## Constraints
- **DataShare** is subject to the limitations on the database used by the data provider. For example, the supported data models, length of the keys and values, and maximum number of databases that can be accessed at a time by each application vary with the database in use.
- **DataShare** is subject to the limitations on the database used by the data provider. The supported data models, length of the keys and values, and maximum number of databases that can be accessed at a time by each application vary with the database in use.
- The payloads of **ValuesBucket**, **Predicates**, and **ResultSet** are restricted by IPC.
- The payloads of **ValuesBucket**, **Predicates**, and **ResultSet** are restricted by inter-process communication (IPC).
- Currently, **dataShare** supports development based on the stage model only.
......@@ -36,14 +36,4 @@ Strong consistency has high requirements on distributed data management and may
## Access Control Mechanism in Cross-Device Synchronization
In the application data synchronization across devices, data access is controlled based on the device level and [data security label](access-control-by-device-and-data-level.md#data-security-labels). In principle, data can be synchronized only to the devices whose data security labels are not higher than the device's security level. The access control matrix is as follows:
|Device Security Level|Data Security Labels of the Synchornizable Device|
|---|---|
|SL1|S1|
|SL2|S1 to S2|
|SL3|S1 to S3|
|SL4|S1 to S4|
|SL5|S1 to S4|
For example, the security level of development boards RK3568 and Hi3516 is SL1. The database with data security label S1 can be synchronized with RK3568 and Hi3516, but the database with database labels S2-S4 cannot.
When data is synchronized across devices, access control is performed based on the device level and data security label. For details, see [Access Control Mechanism in Cross-Device Synchronization](access-control-by-device-and-data-level.md#access-control-mechanism-in-cross-device-synchronization).
......@@ -6,4 +6,7 @@
- [HiLog Development (Native)](hilog-guidelines.md)
- Error Management
- [Development of Error Manager](errormanager-guidelines.md)
- [Development of Application Recovery](apprecovery-guidelines.md)
\ No newline at end of file
- [Development of Application Recovery](apprecovery-guidelines.md)
- Log Management
- [Application Freeze (appfreeze) Log Analysis](appfreeze-guidelines.md)
- [Process Crash (cppcrash) Log Analysis](cppcrash-guidelines.md)
# Application Freeze (appfreeze) Log Analysis
## Introduction
Application freeze (appfreeze) means that an application does not respond to user operations (for example, clicking) within a given period of time. OpenHarmony provides a mechanism for detecting appfreeze faults and generates appfreeze logs for fault analysis.
> NOTE
>
> This guide applies only to applications in the stage model.
> Before using this guide, you must have basic knowledge about the JS applications, C++ program stacks, and application-related subsystems.
## How to Obtain
appfreeze log is a type of fault logs managed together with the native process crash, JS application crash, and system process crash logs . You can obtain the log in any of the following ways.
### Collecting Logs by Using Shell
appfreeze logs start with **appfreeze-** in **/data/log/faultlog/faultlogger/**.
The log files are named in the format of **appfreeze-application package name-application UID-time (seconds level)**.
![appfreeze_20230308145160](figures/appfreeze_20230308145160.png)
### Collecting Logs by Using DevEco Studio
DevEco Studio collects device fault logs and saves them to FaultLog.
The logs are displayed by the bundle name, fault, and time.
![appfreeze_20230308145161](figures/appfreeze_20230308145161.png)
### Collecting Logs by Using faultLogger APIs
The FaultLogger module provides APIs to query various fault information. For details, see [@ohos.faultLogger](../reference/apis/js-apis-faultLogger.md).
## appfreeze Detection
Currently, appfreeze detection supports the fault types listed in the following table.
| Fault Type| Description|
| -------- | -------- |
| THREAD_BLOCK_6S | The application main thread times out due to a suspension.|
| APPLICATION_BLOCK_INPUT | The user input response times out.|
| LIFECYCLE_TIMEOUT | Ability lifecycle switching times out.|
| APP_LIFECYCLE_TIMEOUT | Application lifecycle switching times out.|
### Application Main Thread Timeout
If this fault occurs, the main thread of the current application is suspended or too many tasks are executed, affecting task execution smoothness and experience.
Such a fault can be detected as follows: The watchdog thread of the application periodically inserts an activation detection subthread to the main thread and inserts a timeout reporting subthread to its own thread. If activation detection is not executed within 3 seconds, the THREAD_BLOCK_3S event is reported; if activation detection is not executed within 6 seconds, the THREAD_BLOCK_6S event is reported. The two events together form an appfreeze log. The following figure shows the working principle.
![appfreeze_20230308145163](figures/appfreeze_20230308145163.png)
### User Input Response Timeout
This fault affects user experience. If this fault occurs, the system does not respond to a click event within 10 seconds.
Such a fault can be detected as follows: When a user clicks a certain button of the application, the input system sends a click event to the application. If the input system does not receive a response from the application within 10 seconds, a fault event is reported. The following figure shows the working principle.
![appfreeze_20230308145162](figures/appfreeze_20230308145162.png)
### Lifecycle Switching Timeout
This fault refers to an ability lifecycle switching timeout (LIFECYCLE\_TIMEOUT) or an application lifecycle switching timeout (APP\_LIFECYCLE\_TIMEOUT).
The fault occurs during lifecycle switching and affects the switchover between abilities in the current application or the switchover between applications.
Such a fault can be detected as follows: Upon the start of a lifecycle switchover process, the main thread inserts a timeout task to the watchdog thread, and then removes the timeout task when the lifecycle switchover is complete. If the timeout duration expires, a fault event is reported.
![appfreeze_20230308145164](figures/appfreeze_20230308145164.png)
The timeout duration varies according to the lifecycle.
| Lifecycle| Timeout Duration|
| -------- | -------- |
| Load | 10s |
| Terminate | 10s |
| Connect | 3s |
| Disconnect | 0.5s |
| Foreground | 5s |
| Background | 3s |
## appfreeze Log Analysis
To identify the cause of appfreeze, analyze the appfreeze logs together with HiLog logs.
The following example uses main tread suspension as an example to illustrate how to conduct log analysis. You can treat other types of faults in a similar way.
appfreeze logs are divided into several parts, including header information, and general and specific information in the body.
### Log Header Information
| Field| Description|
| -------- | -------- |
| Reason | Reason why the application does not respond. For details, see [appfreeze Detection](#appfreeze-detection).|
| PID | PID of the failed process, which can be used to search for related process information in the log.|
| PACKAGE_NAME | Application package name.|
![appfreeze_20230310105865](figures/appfreeze_20230310105865.png)
### General Information in the Log Body
General information is present in all logs. It contains the fields listed in the following table. You can search for these fields to locate the related information in the log.
| Field| Description|
| -------- | -------- |
| EVENTNAME | One or more fault events that constitute the cause of main thread suspension.|
| TIMESTAMP | Time when the fault event reported. You can narrow down the time range for viewing HiLog logs based on the timeout duration described in [appfreeze Detection](#appfreeze-detection).|
| PID | PID of the failed process, which can be used with the timestamp and timeout duration to search for related process information in the log.|
| PACKAGE_NAME | Application package name.|
| MSG | Dump information or description of the fault.|
| OpenStacktraceCatcher | Stack trace information of the process.|
| BinderCatcher | Information about IPC calls between a process and other system processes, such as the call waiting time.|
| PeerBinder Stacktrace | Information about stack trace of the peer process.|
| cpuusage | CPU usage of the device.|
| memory | Memory usage of the process.|
The following is an example process stack of OpenStacktraceCatcher.
In this example, when the stack surface window sends events through IPC, the process is stuck in the IPC communication phase.
![appfreeze_20230310105869](figures/appfreeze_20230310105869.png)
Example BinderCatcher information:
In the following example, process 1561 sends an IPC request to process 685 but does not receive any response within 10 seconds.
![appfreeze_20230310105868](figures/appfreeze_20230310105868.png)
Example PeerBinder Stacktrace information:
The following example shows the stack information of process 685, which is suspended at the peer end.
![appfreeze_20230310105870](figures/appfreeze_20230310105870.png)
Example CPU usage information:
The following example shows the CPU usage information of the device.
![appfreeze_20230310105871](figures/appfreeze_20230310105871.png)
Example memory usage information:
The following example shows the memory usage information of the process.
![appfreeze_20230310105872](figures/appfreeze_20230310105872.png)
### Specific Information in the Log Body (Application Main Thread Timeout)
According to [Application Main Thread Timeout] (#application-main-thread-timeout), the log in which **Reason** is **THREAD\_BLOCK\_6S** consists of two parts: THREAD\_BLOCK\_3S and THREAD\_BLOCK\_6S. By comparing the two parts, you can determine whether the appfreeze is due to a suspension or an excess number of tasks.
THREAD\_BLOCK\_3S is followed by THREAD\_BLOCK\_6S in the log. You can use the **EVENTNAME** field to search for the locations of the two events in the log.
Both events contain the **MSG** field, which stores information about the processing queue of the main thread when the suspension occurs. Hence, you can view the status of the event processing queue of the main thread at the two time points.
The example log shows that the event carrying **05:06:18.145** in the low-priority queue is being processed, and it is present in both the THREAD_BLOCK_3S and THREAD_BLOCK_6S. This indicates that the main thread suspension is not caused by an excess number of tasks.
Because THREAD_BLOCK_6S indicates a main thread suspension, you only need to analyze the stack information of the main thread (the ID of the main thread is the same as the process ID). In the example log, the main thread stack is run in the JS through ArkUI and therefore it can be concluded that the suspension occurs in the JS. Because stack is present in both THREAD_BLOCK_3S and THREAD_BLOCK_6S in the same position, the JS suspension is not caused by an excess number of tasks.
THREAD_BLOCK_3S:
![appfreeze_20230310105866](figures/appfreeze_20230310105866.png)
THREAD_BLOCK_6S:
![appfreeze_20230310105867](figures/appfreeze_20230310105867.png)
Then, you can check for the code segment being executed on the application side based on the HiLog log.
Generally, you can view the [general information in the log body](#general-information-in-the-log-body) to check for the cause of the suspension, for example, IPC suspension, high CPU usage, memory leakage, or high memory usage.
### Specific Information in the Log Body (User Input Response Timeout)
If **Reason** is **APPLICATION\_BLOCK\_INPUT**, no response is received within 10 seconds after a user click.
You can find the event description in **MSG**.
For details, see [General Information in the Log Body](#general-information-in-the-log-body). Note that there is a high probability that the main thread is suspended in the case of no response to the user input. You can compare the stack and BinderCatcher information in two log records for further analysis. If there is no log record indicating a main thread suspension, a large number of other events may exist before the input event. This may not cause a main thread suspension but can probably result in no response to user input.
### Specific Information in the Log Body (Lifecycle Switching Timeout)
For a lifecycle switching timeout, **Reason** can be **LIFECYCLE\_TIMEOUT** or **APP\_LIFECYCLE\_TIMEOUT**.
**LIFECYCLE\_TIMEOUT** indicates a lifecycle switching timeout at the ability level, and **APP\_LIFECYCLE\_TIMEOUT** indicates a lifecycle switching timeout at the application level.
MSG indicates the lifecycle that encounters a timeout.
In this example, **LIFECYCLE\_TIMEOUT** indicates that the timeout occurs during switching of the ability to the background, and **APP\_LIFECYCLE\_TIMEOUT** indicates that the timeout occurs in the application termination phase. You can locate related HiLog logs according to the timeout duration described in [Lifecycle Switching Timeout] (#lifecycle-switching-timeout).
LIFECYCLE_TIMEOUT:
![appfreeze_20230310105873](figures/appfreeze_20230310105873.png)
APP_LIFECYCLE_TIMEOUT:
![appfreeze_20230310105874](figures/appfreeze_20230310105874.png)
For details about other log information, see [General Information in the Log Body](#general-information-in-the-log-body). Note that there is a high probability that the main thread is suspended during lifecycle switching. You can compare the stack and BinderCatcher information in two log records for further analysis.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部