diff --git a/en/application-dev/application-models/Readme-EN.md b/en/application-dev/application-models/Readme-EN.md index b38074f214762a1d42474e7e12005314427d3ee1..65f2b4c16ea42ecdf37082a5a9f8e26eb20dd6e6 100644 --- a/en/application-dev/application-models/Readme-EN.md +++ b/en/application-dev/application-models/Readme-EN.md @@ -17,11 +17,36 @@ - ExtensionAbility Component - [ExtensionAbility Component Overview](extensionability-overview.md) - [ServiceExtensionAbility](serviceextensionability.md) - - [FormExtensionAbility (Widget)](widget-development-stage.md) + - [DataShareExtensionAbility (for System Applications Only)](datashareextensionability.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) + - [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) + - 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 @@ -47,6 +72,7 @@ - [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) diff --git a/en/application-dev/application-models/accessibilityextensionability.md b/en/application-dev/application-models/accessibilityextensionability.md index 4c912d5e58a1b8083ba1037cccf449dd953d245c..688eaefa4bc10723d23f880dfbb4c1502cb42053 100644 --- a/en/application-dev/application-models/accessibilityextensionability.md +++ b/en/application-dev/application-models/accessibilityextensionability.md @@ -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", diff --git a/en/application-dev/application-models/arkts-ui-widget-configuration.md b/en/application-dev/application-models/arkts-ui-widget-configuration.md new file mode 100644 index 0000000000000000000000000000000000000000..7e438ce4215a583c4ad7ccebc8cfc591b5251ad6 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-configuration.md @@ -0,0 +1,84 @@ +# 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.
- **arkts**: ArkTS widget
- **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.
- **true**: The widget is the default one.
- **false**: The widget is not the default one.| Boolean| No| + | colorMode | Color mode of the widget.
- **auto**: auto-adaptive color mode
- **dark**: dark color mode
- **light**: light color mode| String| Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget.
- **1 * 2**: indicates a grid with one row and two columns.
- **2 * 2**: indicates a grid with two rows and two columns.
- **2 * 4**: indicates a grid with two rows and four columns.
- **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.
- **true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.
- **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.
**NOTE**
**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.
If the value is **0**, this field does not take effect.
If the value is a positive integer *N*, the interval is calculated by multiplying *N* and 30 minutes.
**NOTE**
**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" + ] + } + ] + } + ``` diff --git a/en/application-dev/application-models/arkts-ui-widget-content-update.md b/en/application-dev/application-models/arkts-ui-widget-content-update.md new file mode 100644 index 0000000000000000000000000000000000000000..c0f4c840b6c11b497405ce8777a04317b5ffca4d --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-content-update.md @@ -0,0 +1,30 @@ +# 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.'); + }); + }) + + ... + } +} +``` diff --git a/en/application-dev/application-models/arkts-ui-widget-creation.md b/en/application-dev/application-models/arkts-ui-widget-creation.md new file mode 100644 index 0000000000000000000000000000000000000000..cc8843c0294cf745e7737164e46cb8f69256efa2 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-creation.md @@ -0,0 +1,19 @@ +# 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) diff --git a/en/application-dev/application-models/arkts-ui-widget-event-formextensionability.md b/en/application-dev/application-models/arkts-ui-widget-event-formextensionability.md new file mode 100644 index 0000000000000000000000000000000000000000..861f5ca66eea9a06ee50c7b1448e1f6ed040c01a --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-event-formextensionability.md @@ -0,0 +1,66 @@ +# 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) diff --git a/en/application-dev/application-models/arkts-ui-widget-event-overview.md b/en/application-dev/application-models/arkts-ui-widget-event-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..fbc77b97a27b52b0f7b2a3b0cebc5b5cb5940f72 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-event-overview.md @@ -0,0 +1,62 @@ +# 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.
- **"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.
- **"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.
- **"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) diff --git a/en/application-dev/application-models/arkts-ui-widget-event-router.md b/en/application-dev/application-models/arkts-ui-widget-event-router.md new file mode 100644 index 0000000000000000000000000000000000000000..371cbc6b2729a7985ed2fd183297ed771fddb11d --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-event-router.md @@ -0,0 +1,110 @@ +# 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; + } + }); + } + }; + ``` diff --git a/en/application-dev/application-models/arkts-ui-widget-event-uiability.md b/en/application-dev/application-models/arkts-ui-widget-event-uiability.md new file mode 100644 index 0000000000000000000000000000000000000000..0d6cb33a3749c81b6b41dd4904ba64c89a7942ae --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-event-uiability.md @@ -0,0 +1,86 @@ +# 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)); + }) + } + } + + ... + } + ``` diff --git a/en/application-dev/application-models/arkts-ui-widget-image-update.md b/en/application-dev/application-models/arkts-ui-widget-image-update.md new file mode 100644 index 0000000000000000000000000000000000000000..00c00a744afd8422274617005a50583fef5d92ee --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-image-update.md @@ -0,0 +1,166 @@ +# 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 **\** 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 **\** 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 **\** 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. diff --git a/en/application-dev/application-models/arkts-ui-widget-interaction-overview.md b/en/application-dev/application-models/arkts-ui-widget-interaction-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..76c4a202543c00f3df44f71b0a33d417831b5f53 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-interaction-overview.md @@ -0,0 +1,20 @@ +# 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.
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.
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) diff --git a/en/application-dev/application-models/arkts-ui-widget-lifecycle.md b/en/application-dev/application-models/arkts-ui-widget-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..4cb68536312e26e0f7c98546839134c0ab435a8c --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-lifecycle.md @@ -0,0 +1,95 @@ +# 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. diff --git a/en/application-dev/application-models/arkts-ui-widget-modules.md b/en/application-dev/application-models/arkts-ui-widget-modules.md new file mode 100644 index 0000000000000000000000000000000000000000..5084b7ea5045002759ca57f10c055ef5623eb7d0 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-modules.md @@ -0,0 +1,24 @@ +# 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**. diff --git a/en/application-dev/application-models/arkts-ui-widget-page-animation.md b/en/application-dev/application-models/arkts-ui-widget-page-animation.md new file mode 100644 index 0000000000000000000000000000000000000000..9a940aeecb62682a185ba8c0529adc38017c8e2d --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-page-animation.md @@ -0,0 +1,45 @@ +# 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 }) + } +} +``` diff --git a/en/application-dev/application-models/arkts-ui-widget-page-custom-drawing.md b/en/application-dev/application-models/arkts-ui-widget-page-custom-drawing.md new file mode 100644 index 0000000000000000000000000000000000000000..49523d60af886db40b55fc90d80c9bd5027cade8 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-page-custom-drawing.md @@ -0,0 +1,79 @@ +# 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) diff --git a/en/application-dev/application-models/arkts-ui-widget-page-overview.md b/en/application-dev/application-models/arkts-ui-widget-page-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..2c709ff5c7c13c09e5a303f0adfeebe5c97690bd --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-page-overview.md @@ -0,0 +1,21 @@ +# 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) diff --git a/en/application-dev/application-models/arkts-ui-widget-update-by-status.md b/en/application-dev/application-models/arkts-ui-widget-update-by-status.md new file mode 100644 index 0000000000000000000000000000000000000000..8952b8dff4ecdd3acad6b1a65513d8e529c4dc70 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-update-by-status.md @@ -0,0 +1,170 @@ +# 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. diff --git a/en/application-dev/application-models/arkts-ui-widget-update-by-time.md b/en/application-dev/application-models/arkts-ui-widget-update-by-time.md new file mode 100644 index 0000000000000000000000000000000000000000..5b27a636f83f144110c5533a3d43baf0087c3716 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-update-by-time.md @@ -0,0 +1,99 @@ +# 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. diff --git a/en/application-dev/application-models/arkts-ui-widget-working-principles.md b/en/application-dev/application-models/arkts-ui-widget-working-principles.md new file mode 100644 index 0000000000000000000000000000000000000000..a0edb6c6c68d9ada32cd3ff34f5117d5cc012ed6 --- /dev/null +++ b/en/application-dev/application-models/arkts-ui-widget-working-principles.md @@ -0,0 +1,57 @@ +# 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 diff --git a/en/application-dev/application-models/common-event-remove-sticky.md b/en/application-dev/application-models/common-event-remove-sticky.md new file mode 100644 index 0000000000000000000000000000000000000000..358cf8ccf912e0c329684ff904207b933713835b --- /dev/null +++ b/en/application-dev/application-models/common-event-remove-sticky.md @@ -0,0 +1,36 @@ +# 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 | 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`); + } + }); + ``` diff --git a/en/application-dev/application-models/common-event-static-subscription.md b/en/application-dev/application-models/common-event-static-subscription.md index 85852f5712df84107c6593160d276ed33557baf9..53e014abe38ac3f8ec89fe8a21dc9280184a280b 100644 --- a/en/application-dev/application-models/common-event-static-subscription.md +++ b/en/application-dev/application-models/common-event-static-subscription.md @@ -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**. diff --git a/en/application-dev/application-models/enterprise-extensionAbility.md b/en/application-dev/application-models/enterprise-extensionAbility.md index 0038b41e5b4f654d8c7924ec1232bb342dd616cb..1c39325cbe87435189896816a17bcb9537bb80ac 100644 --- a/en/application-dev/application-models/enterprise-extensionAbility.md +++ b/en/application-dev/application-models/enterprise-extensionAbility.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" } ] ``` diff --git a/en/application-dev/application-models/figures/JSCardPrinciple.png b/en/application-dev/application-models/figures/JSCardPrinciple.png new file mode 100644 index 0000000000000000000000000000000000000000..558c2c2a679737eed2bf3b129f632e6300d0d2da Binary files /dev/null and b/en/application-dev/application-models/figures/JSCardPrinciple.png differ diff --git a/en/application-dev/application-models/figures/WidgerCameraCard.png b/en/application-dev/application-models/figures/WidgerCameraCard.png new file mode 100644 index 0000000000000000000000000000000000000000..55e62cdb8791ca6bbc95b7ea4c054e93270ce7a6 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgerCameraCard.png differ diff --git a/en/application-dev/application-models/figures/WidgetAnimation.gif b/en/application-dev/application-models/figures/WidgetAnimation.gif new file mode 100644 index 0000000000000000000000000000000000000000..eaddfb4cf4d0bf9613b3a108c26ea1617d68d3c1 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetAnimation.gif differ diff --git a/en/application-dev/application-models/figures/WidgetArchitecture.png b/en/application-dev/application-models/figures/WidgetArchitecture.png new file mode 100644 index 0000000000000000000000000000000000000000..b97ddda74fb89f32ed248c1d4c6d3e8e6e100a05 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetArchitecture.png differ diff --git a/en/application-dev/application-models/figures/WidgetCanvasDemo.jpeg b/en/application-dev/application-models/figures/WidgetCanvasDemo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9c797ff4575ae0aaf9aad27ae5d4d701181faf97 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetCanvasDemo.jpeg differ diff --git a/en/application-dev/application-models/figures/WidgetCardPage.png b/en/application-dev/application-models/figures/WidgetCardPage.png new file mode 100644 index 0000000000000000000000000000000000000000..795e96171e6d890e72a09382906302dd0fa45fab Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetCardPage.png differ diff --git a/en/application-dev/application-models/figures/WidgetLocalStorageProp.png b/en/application-dev/application-models/figures/WidgetLocalStorageProp.png new file mode 100644 index 0000000000000000000000000000000000000000..1a45723865ff9f990c3a4197338e9cbc9eb3b6f4 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetLocalStorageProp.png differ diff --git a/en/application-dev/application-models/figures/WidgetModules.png b/en/application-dev/application-models/figures/WidgetModules.png new file mode 100644 index 0000000000000000000000000000000000000000..6eaac0b6ca404eb9575587add72935e9ce580030 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetModules.png differ diff --git a/en/application-dev/application-models/figures/WidgetPostCardAction.png b/en/application-dev/application-models/figures/WidgetPostCardAction.png new file mode 100644 index 0000000000000000000000000000000000000000..42a07e13036d6252309ca4e4bc857043486269c8 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetPostCardAction.png differ diff --git a/en/application-dev/application-models/figures/WidgetPreviewPage.png b/en/application-dev/application-models/figures/WidgetPreviewPage.png new file mode 100644 index 0000000000000000000000000000000000000000..5f614e3db780f8d83f3c2f0865a9521aacd2b0de Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetPreviewPage.png differ diff --git a/en/application-dev/application-models/figures/WidgetPrinciple.png b/en/application-dev/application-models/figures/WidgetPrinciple.png new file mode 100644 index 0000000000000000000000000000000000000000..588975d0095de58d0d220809ba77aec541a64984 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetPrinciple.png differ diff --git a/en/application-dev/application-models/figures/WidgetProject.png b/en/application-dev/application-models/figures/WidgetProject.png new file mode 100644 index 0000000000000000000000000000000000000000..788bb3ac63ca5727527bd104f76689f762b7b33d Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetProject.png differ diff --git a/en/application-dev/application-models/figures/WidgetProjectCreate1.png b/en/application-dev/application-models/figures/WidgetProjectCreate1.png new file mode 100644 index 0000000000000000000000000000000000000000..5369f48edcee476ae8317b9f0e1fb98b06607e93 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetProjectCreate1.png differ diff --git a/en/application-dev/application-models/figures/WidgetProjectCreate2.png b/en/application-dev/application-models/figures/WidgetProjectCreate2.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf742e04e2f30febb05f2d8638193dc10532863 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetProjectCreate2.png differ diff --git a/en/application-dev/application-models/figures/WidgetProjectCreate3.png b/en/application-dev/application-models/figures/WidgetProjectCreate3.png new file mode 100644 index 0000000000000000000000000000000000000000..98429567ad24b1a83c67118173bf6cb504bea25d Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetProjectCreate3.png differ diff --git a/en/application-dev/application-models/figures/WidgetProjectView.png b/en/application-dev/application-models/figures/WidgetProjectView.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1c06e47502131983b0b7cd56e66269b5be6d88 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetProjectView.png differ diff --git a/en/application-dev/application-models/figures/WidgetRender.png b/en/application-dev/application-models/figures/WidgetRender.png new file mode 100644 index 0000000000000000000000000000000000000000..228128b143995fec75c71c4172e3d90ca15177f6 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetRender.png differ diff --git a/en/application-dev/application-models/figures/WidgetSupportApi.png b/en/application-dev/application-models/figures/WidgetSupportApi.png new file mode 100644 index 0000000000000000000000000000000000000000..1ac3d68c19683c69a16f5ebc305f3b79cb8c6566 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetSupportApi.png differ diff --git a/en/application-dev/application-models/figures/WidgetUpdatePage.png b/en/application-dev/application-models/figures/WidgetUpdatePage.png new file mode 100644 index 0000000000000000000000000000000000000000..075c8e97c85386c062a651f3b4f876e6c049171f Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetUpdatePage.png differ diff --git a/en/application-dev/application-models/figures/WidgetUse.png b/en/application-dev/application-models/figures/WidgetUse.png new file mode 100644 index 0000000000000000000000000000000000000000..9bcc46d9044b04633692171f6a553bf43ce147c3 Binary files /dev/null and b/en/application-dev/application-models/figures/WidgetUse.png differ diff --git a/en/application-dev/application-models/inputmethodextentionability.md b/en/application-dev/application-models/inputmethodextentionability.md index 8a7856f402bf30b1610521e3cf05dda7145c3509..2b3910707ecdb6f964822380a85b14857ec8fd29 100644 --- a/en/application-dev/application-models/inputmethodextentionability.md +++ b/en/application-dev/application-models/inputmethodextentionability.md @@ -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, } ] } diff --git a/en/application-dev/application-models/widget-development-stage.md b/en/application-dev/application-models/js-ui-widget-development.md similarity index 77% rename from en/application-dev/application-models/widget-development-stage.md rename to en/application-dev/application-models/js-ui-widget-development.md index 5003015d4109cdedbb3c1603a9f31a5d7ce4038d..cb8a2287992a55fb960672b078e6d0d20f6ec1b1 100644 --- a/en/application-dev/application-models/widget-development-stage.md +++ b/en/application-dev/application-models/js-ui-widget-development.md @@ -1,27 +1,16 @@ -# FormExtensionAbility (Widget) +# Developing a JS Widget -## Widget Overview - -FormExtensionAbility provides a service widget (also called widget), which 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) and provides basic interactive features such as opening a UI page or sending a message. - -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. - -- Widget Manager: a resident agent that provides widget management features such as periodic widget updates. - -- Widget provider: an atomic service that provides the widget content to display and controls how widget components are laid out and how they interact with users. +The following describes how to develop JS widgets based on the web-like development paradigm. ## Working Principles -Figure 1 shows the working principles of the widget framework. +Below shows the working principles of the widget framework. -**Figure 1** Widget framework working principles in the stage model -![form-extension](figures/form-extension.png) +**Figure 1** Widget framework working principles in the stage model + +![JSCardPrinciple](figures/JSCardPrinciple.png) The widget host consists of the following modules: @@ -50,7 +39,6 @@ The widget provider consists of the following modules: - Communication adapter: provided by the OpenHarmony SDK for communication with the Widget Manager. It pushes update data to the Widget Manager. > **NOTE** -> > You only need to develop the widget provider. The system automatically handles the work of the widget host and Widget Manager. @@ -58,38 +46,31 @@ The widget provider consists of the following modules: The **FormExtensionAbility** class has the following APIs. For details, see [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). -| API| Description| +| Name| Description| | -------- | -------- | | onAddForm(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a widget has been created.| | onCastToNormalForm(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| | onUpdateForm(formId: string): void | Called to notify the widget provider that a widget has been updated.| | onChangeFormVisibility(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility.| | onFormEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event.| -| onRemoveForm(formId: string): void| Called to notify the widget provider that a widget has been destroyed.| +| onRemoveForm(formId: string): void | Called to notify the widget provider that a widget has been destroyed.| | onConfigurationUpdate(config: Configuration): void | Called when the configuration of the environment where the widget is running is updated.| -| onShareForm?(formId: string): { [key: string]: any }| Called by the widget provider to receive shared widget data.| - -The **FormExtensionAbility** class also has a member context, that is, the FormExtensionContext class. For details, see [FormExtensionContext](../reference/apis/js-apis-inner-application-formExtensionContext.md). - -| API| Description| -| -------- | -------- | -| startAbility(want: Want, callback: AsyncCallback<void>): void | Starts UIAbility of the application to which a widget belongs. This API uses an asynchronous callback to return the result. (This is a system API and cannot be called by third-party applications. You must apply for the permission to use the API.)| -| startAbility(want: Want): Promise<void> | Starts UIAbility of the application to which a widget belongs. This API uses a promise to return the result. (This is a system API and cannot be called by third-party applications. You must apply for the permission to use the API.)| +| onShareForm?(formId: string): { [key: string]: any } | Called by the widget provider to receive shared widget data.| The **FormProvider** class has the following APIs. For details, see [FormProvider](../reference/apis/js-apis-app-form-formProvider.md). -| API| Description| +| Name| Description| | -------- | -------- | | setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result.| | setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | Sets the next refresh time for a widget. This API uses a promise to return the result.| | updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | Updates a widget. This API uses an asynchronous callback to return the result.| -| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>;| Updates a widget. This API uses a promise to return the result.| +| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | Updates a widget. This API uses a promise to return the result.| The **FormBindingData** class has the following APIs. For details, see [FormBindingData](../reference/apis/js-apis-app-form-formBindingData.md). -| API| Description| +| Name| Description| | -------- | -------- | -| createFormBindingData(obj?: Object \ string): FormBindingData| | Creates a **FormBindingData** object.| +| createFormBindingData(obj?: Object \| string): FormBindingData | Creates a **FormBindingData** object.| ## How to Develop @@ -98,7 +79,7 @@ The widget provider development based on the [stage model](stage-model-developme - [Creating a FormExtensionAbility Instance](#creating-a-formextensionability-instance): Develop the lifecycle callback functions of FormExtensionAbility. -- [Configuring the Widget Configuration File](#configuring-the-widget-configuration-file): Configure the application configuration file **module.json5** and profile configuration file. +- [Configuring the Widget Configuration Files](#configuring-the-widget-configuration-files): Configure the application configuration file **module.json5** and profile configuration file. - [Persistently Storing Widget Data](#persistently-storing-widget-data): This operation is a form of widget data exchange. @@ -114,9 +95,10 @@ The widget provider development based on the [stage model](stage-model-developme To create a widget in the stage model, implement the lifecycle callbacks of **FormExtensionAbility**. Generate a widget template by referring to [Developing a Service Widget](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-development-service-widget-0000001263280425). 1. Import related modules to **EntryFormAbility.ts**. + ```ts - import FormExtension from '@ohos.app.form.FormExtensionAbility'; + import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'; import formBindingData from '@ohos.app.form.formBindingData'; import formInfo from '@ohos.app.form.formInfo'; import formProvider from '@ohos.app.form.formProvider'; @@ -124,9 +106,10 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ``` 2. Implement the FormExtension lifecycle callbacks in **EntryFormAbility.ts**. + ```ts - export default class EntryFormAbility extends FormExtension { + export default class EntryFormAbility extends FormExtensionAbility { onAddForm(want) { console.info('[EntryFormAbility] onAddForm'); // Called when the widget is created. The widget provider should return the widget data binding class. @@ -175,10 +158,10 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ``` > **NOTE** -> > FormExtensionAbility cannot reside in the background. Therefore, continuous tasks cannot be processed in the widget lifecycle callbacks. -### Configuring the Widget Configuration File + +### Configuring the Widget Configuration Files 1. Configure ExtensionAbility information under **extensionAbilities** in the [module.json5 file](../quick-start/module-configuration-file.md). For a FormExtensionAbility, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information. Example configuration: @@ -187,11 +170,11 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ```json { "module": { - // ... + ... "extensionAbilities": [ { "name": "EntryFormAbility", - "srcEntrance": "./ets/entryformability/EntryFormAbility.ts", + "srcEntry": "./ets/entryformability/EntryFormAbility.ts", "label": "$string:EntryFormAbility_label", "description": "$string:EntryFormAbility_desc", "type": "form", @@ -208,19 +191,20 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo ``` 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** Widget profile configuration file - - | Field| Description| Data Type| Initial Value Allowed| + + **Table 1** Widget profile configuration file + + | Field| Description| Data Type| Default Value Allowed| | -------- | -------- | -------- | -------- | - | name | Class name of a widget. The value is a string with a maximum of 127 bytes.| String| No| + | name | Class name of the widget. The value is a string with a maximum of 127 bytes.| String| No| | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String| Yes (initial value: left empty)| | src | Full path of the UI code corresponding to the widget.| String| No| | window | Window-related configurations.| Object| Yes| - | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean| No| - | colorMode | Color mode of the widget.
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String| Yes (initial value: **auto**)| - | supportDimensions | Grid styles supported by the widget.
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No| + | isDefault | Whether the widget is a default one. Each UIAbility has only one default widget.
- **true**: The widget is the default one.
- **false**: The widget is not the default one.| Boolean| No| + | colorMode | Color mode of the widget.
- **auto**: auto-adaptive color mode
- **dark**: dark color mode
- **light**: light color mode| String| Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget.
- **1 * 2**: indicates a grid with one row and two columns.
- **2 * 2**: indicates a grid with two rows and two columns.
- **2 * 4**: indicates a grid with two rows and four columns.
- **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.
**true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.
**false**: The widget cannot be updated periodically.| Boolean| No| + | updateEnabled | Whether the widget can be updated periodically.
- **true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.
- **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.
**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| String| Yes (initial value: **0:0**)| | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.
If the value is **0**, this field does not take effect.
If the value is a positive integer *N*, the interval is calculated by multiplying *N* and 30 minutes.
**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)| @@ -228,13 +212,14 @@ To create a widget in the stage model, implement the lifecycle callbacks of **Fo | 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 widget.", + "description": "This is a service widget.", "src": "./js/widget/pages/index/index", "window": { "designWidth": 720, @@ -271,7 +256,7 @@ async function storeFormInfo(formId: string, formName: string, tempFlag: boolean }; try { const storage = await dataStorage.getStorage(DATA_STORAGE_PATH); - // Put the widget information. + // put form info await storage.put(formId, JSON.stringify(formInfo)); console.info(`[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`); await storage.flush(); @@ -281,7 +266,7 @@ async function storeFormInfo(formId: string, formName: string, tempFlag: boolean } export default class EntryFormAbility extends FormExtension { - // ... + ... onAddForm(want) { console.info('[EntryFormAbility] onAddForm'); @@ -310,7 +295,7 @@ const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store"; async function deleteFormInfo(formId: string) { try { const storage = await dataStorage.getStorage(DATA_STORAGE_PATH); - // Delete the widget information. + // del form info await storage.delete(formId); console.info(`[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`); await storage.flush(); @@ -319,10 +304,10 @@ async function deleteFormInfo(formId: string) { } } -// ... +... export default class EntryFormAbility extends FormExtension { - // ... + ... onRemoveForm(formId) { console.info('[EntryFormAbility] onRemoveForm'); // Delete the persistent widget instance data. @@ -369,13 +354,10 @@ onUpdateForm(formId) { You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. This section describes how to develop a page shown below. -![widget-development-stage](figures/widget-development-stage.png) - -> **NOTE** -> -> Only the JavaScript-based web-like development paradigm is supported when developing the widget UI. +![WidgetCardPage](figures/WidgetCardPage.png) - HML: uses web-like paradigm components to describe the widget page information. + ```html
@@ -392,6 +374,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi ``` - CSS: defines style information about the web-like paradigm components in HML. + ```css .container { @@ -433,6 +416,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi ``` - JSON: defines data and event interaction on the widget UI page. + ```json { @@ -455,24 +439,27 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi ### Developing Widget Events -You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. +You can set router and message events for components on a widget. The router event applies to UIAbility redirection, and the message event applies to custom click events. The key steps are as follows: 1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. 2. Set the router event. + - **action**: **"router"**, which indicates a router event. - - **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name of the stage model created by DevEco Studio is EntryAbility. - - **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field. + - **abilityName**: name of the UIAbility to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name of the stage model created by DevEco Studio is EntryAbility. + - **params**: custom parameters passed to the target UIAbility. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target UIAbility. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field. 3. Set the message event. + - **action**: **"message"**, which indicates a message event. - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onFormEvent()**. The following is an example: - HML file: + ```html
@@ -489,6 +476,7 @@ The following is an example: ``` - CSS file: + ```css .container { @@ -530,6 +518,7 @@ The following is an example: ``` - JSON file: + ```json { @@ -558,52 +547,44 @@ The following is an example: - Receive the router event and obtain parameters in UIAbility. + ```ts import UIAbility from '@ohos.app.ability.UIAbility' export default class EntryAbility extends UIAbility { onCreate(want, launchParam) { + let params = JSON.parse(want.parameters.params); // Obtain the info parameter passed in the router event. - if (want.parameters.info === "router info") { - // Do something. - // console.log("router info:" + want.parameters.info) + if (params.info === "router info") { + // do something + // console.info("router info:" + params.info) } // Obtain the message parameter passed in the router event. - if (want.parameters.message === "router message") { - // Do something. - // console.log("router message:" + want.parameters.message) + if (params.message === "router message") { + // do something + // console.info("router message:" + params.message) } } - // ... + ... }; ``` - Receive the message event in FormExtensionAbility and obtain parameters. + ```ts import FormExtension from '@ohos.app.form.FormExtensionAbility'; export default class FormAbility extends FormExtension { - // ... + ... onFormEvent(formId, message) { // Obtain the detail parameter passed in the message event. let msg = JSON.parse(message) - if (msg.params.detail === "message detail") { - // Do something. - // console.log("message info:" + msg.params.detail) + if (msg.detail === "message detail") { + // do something + // console.info("message info:" + msg.detail) } } - // ... + ... }; ``` - -## Restrictions - -To minimize the abuse of **FormExtensionAbility** by third-party applications, the following APIs cannot be invoked in **FormExtensionAbility**: - -- @ohos.ability.particleAbility.d.ts -- @ohos.backgroundTaskManager.d.ts -- @ohos.resourceschedule.backgroundTaskManager.d.ts -- @ohos.multimedia.camera.d.ts -- @ohos.multimedia.audio.d.ts -- @ohos.multimedia.media.d.ts diff --git a/en/application-dev/application-models/service-widget-overview.md b/en/application-dev/application-models/service-widget-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..3739129f2a07765b2ebe015910d1d6e3d8d721d0 --- /dev/null +++ b/en/application-dev/application-models/service-widget-overview.md @@ -0,0 +1,58 @@ +# 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. diff --git a/en/application-dev/connectivity/http-request.md b/en/application-dev/connectivity/http-request.md index 223e40a97ecddcfa6b1613106d94ba942ee22006..45a20ef6a48d0746a1c82a0e1b577d7354e8938d 100644 --- a/en/application-dev/connectivity/http-request.md +++ b/en/application-dev/connectivity/http-request.md @@ -158,5 +158,4 @@ httpRequest.request2( httpRequest.destroy(); } ); - ``` \ No newline at end of file diff --git a/en/application-dev/connectivity/net-connection-manager.md b/en/application-dev/connectivity/net-connection-manager.md index 69ce20a372c60c2bf0443db2697c5a65352bf34c..5ee75a717882c3344612e741b2e197fa6e57509d 100644 --- a/en/application-dev/connectivity/net-connection-manager.md +++ b/en/application-dev/connectivity/net-connection-manager.md @@ -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**. diff --git a/en/application-dev/connectivity/net-ethernet.md b/en/application-dev/connectivity/net-ethernet.md index f1891594166c9ecf3688b93d78cdece890796d35..18f20a7fd7e1a4c9516386c543c9521522df5f66 100644 --- a/en/application-dev/connectivity/net-ethernet.md +++ b/en/application-dev/connectivity/net-ethernet.md @@ -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'); diff --git a/en/application-dev/connectivity/net-sharing.md b/en/application-dev/connectivity/net-sharing.md index 331ffec3b1a1e0047c39e2fe416ad5c05e913b61..4072217d9ced5d99b2052b5db8ccb8333fcb7023 100644 --- a/en/application-dev/connectivity/net-sharing.md +++ b/en/application-dev/connectivity/net-sharing.md @@ -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. diff --git a/en/application-dev/connectivity/socket-connection.md b/en/application-dev/connectivity/socket-connection.md index ea2a3ba6dcfb849ea64971503e246e94b16f34a1..109b63fdb5fdcae98e23882b32018d4a03435f55 100644 --- a/en/application-dev/connectivity/socket-connection.md +++ b/en/application-dev/connectivity/socket-connection.md @@ -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) diff --git a/en/application-dev/connectivity/websocket-connection.md b/en/application-dev/connectivity/websocket-connection.md index dfcc9bd7f877393bf1bf8d868046d5d12e896678..4c373011c45be18183e4c622c3e7e35b97198a24 100644 --- a/en/application-dev/connectivity/websocket-connection.md +++ b/en/application-dev/connectivity/websocket-connection.md @@ -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) diff --git a/en/application-dev/database/data-persistence-by-kv-store.md b/en/application-dev/database/data-persistence-by-kv-store.md index 804fb6b12764b95cec9566bdc165234284d32a8d..2337702fb79b1d2c53154181362b393211f90f50 100644 --- a/en/application-dev/database/data-persistence-by-kv-store.md +++ b/en/application-dev/database/data-persistence-by-kv-store.md @@ -21,13 +21,13 @@ The key-value (KV) database stores data in the form of KV pairs. You can use KV The following table lists the APIs used for KV 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 [Distributed KV Store](../reference/apis/js-apis-distributedKVStore.md). -| API| Description| +| API| Description| | -------- | -------- | -| createKVManager(config: KVManagerConfig): KVManager | Creates a **KvManager** instance to manage database objects.| -| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | Creates and obtains a KV store of the specified type.| -| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | Adds a KV pair of the specified type to this KV store.| -| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void | Obtains the value of the specified key.| -| delete(key: string, callback: AsyncCallback<void>): void | Deletes a KV pair based on the specified key.| +| createKVManager(config: KVManagerConfig): KVManager | Creates a **KvManager** instance to manage database objects.| +| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | Creates and obtains a KV store of the specified type.| +| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | Adds a KV pair of the specified type to this KV store.| +| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void | Obtains the value of the specified key.| +| delete(key: string, callback: AsyncCallback<void>): void | Deletes a KV pair based on the specified key.| ## How to Develop @@ -35,10 +35,9 @@ The following table lists the APIs used for KV data persistence. Most of the API 1. Create a **KvManager** instance to manage database objects. Example: - Stage model: - + ```js // Import the module. import distributedKVStore from '@ohos.data.distributedKVStore'; @@ -69,7 +68,7 @@ The following table lists the APIs used for KV data persistence. Most of the API FA model: - + ```js // Import the module. import distributedKVStore from '@ohos.data.distributedKVStore'; @@ -93,14 +92,13 @@ The following table lists the APIs used for KV data persistence. Most of the API ``` 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. @@ -121,9 +119,8 @@ 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: - ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -145,9 +142,8 @@ 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: - ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -172,9 +168,8 @@ 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: - ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; diff --git a/en/application-dev/database/data-sync-of-kv-store.md b/en/application-dev/database/data-sync-of-kv-store.md index e9b4fff51f15ca2339715c626c9e4e4bba7e4d45..eb8994570f04b0d6690c2b91b1b1745602e980fb 100644 --- a/en/application-dev/database/data-sync-of-kv-store.md +++ b/en/application-dev/database/data-sync-of-kv-store.md @@ -79,14 +79,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 the single KV store. 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 [Distributed KV Store](../reference/apis/js-apis-distributedKVStore.md). -| API| Description| +| API| Description| | -------- | -------- | -| createKVManager(config: KVManagerConfig): KVManager | Creates a **KvManager** instance to manage database objects.| -| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | Creates and obtains a KV store of the specified type.| -| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | Inserts and updates data.| -| on(event: 'dataChange', type: SubscribeType, listener: Callback<ChangeNotification>): void | Subscribes to data changes in the KV store.| -| get(key: string, callback: AsyncCallback<boolean \| string \| number \| Uint8Array>): void | Queries the value of the specified key.| -| sync(deviceIds: string[], mode: SyncMode, delayMs?: number): void | Triggers a manual synchronization of the KV store.| +| createKVManager(config: KVManagerConfig): KVManager | Creates a **KvManager** instance to manage database objects.| +| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | Creates and obtains a KV store of the specified type.| +| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | Inserts and updates data.| +| on(event: 'dataChange', type: SubscribeType, listener: Callback<ChangeNotification>): void | Subscribes to data changes in the KV store.| +| get(key: string, callback: AsyncCallback<boolean \| string \| number \| Uint8Array>): void | Queries the value of the specified key.| +| sync(deviceIds: string[], mode: SyncMode, delayMs?: number): void | Triggers a manual synchronization of the KV store.| ## How to Develop @@ -100,7 +100,7 @@ The following uses a single KV store as an example to describe how to implement > 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 distributedKVStore from '@ohos.data.distributedKVStore'; ``` @@ -115,7 +115,7 @@ The following uses a single KV store as an example to describe how to implement 1. Create a **kvManagerConfig** object based on the application context. 2. Create a **KvManager** instance. - + ```js // Obtain the context of the stage model. import UIAbility from '@ohos.app.ability.UIAbility'; @@ -152,7 +152,7 @@ The following uses a single KV store as an example to describe how to implement 1. Declare the ID of the distributed KV store to create. 2. Disable the auto synchronization function (**autoSync:false**) to facilitate subsequent verification of the synchronization function. If synchronization is required, call the **sync()** interface. - + ```js try { const options = { @@ -179,7 +179,7 @@ The following uses a single KV store as an example to describe how to implement ``` 5. Subscribe to changes of distributed data. - + ```js try { kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => { @@ -195,7 +195,7 @@ The following uses a single KV store as an example to describe how to implement 1. Construct the key and value to be written to the single KV store. 2. Write KV pairs to the single KV store. - + ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -217,7 +217,7 @@ The following uses a single KV store as an example to describe how to implement 1. Construct the key to be queried from the single KV store. 2. Query data from the single KV store. - + ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -249,7 +249,7 @@ The following uses a single KV store as an example to describe how to implement > > If manual synchronization is used, **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 import deviceManager from '@ohos.distributedHardware.deviceManager'; diff --git a/en/application-dev/database/data-sync-of-rdb-store.md b/en/application-dev/database/data-sync-of-rdb-store.md index c47d95a7969d44a96396e2e6e77dd4c958468748..2d6d5a73e0cf7cfae28d7d6296039e28994477a8 100644 --- a/en/application-dev/database/data-sync-of-rdb-store.md +++ b/en/application-dev/database/data-sync-of-rdb-store.md @@ -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<string>, callback: AsyncCallback<void>): void | Sets the distributed tables to be synchronized.| -| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback<Array<[string, number]>>): void | Synchronizes data across devices.| -| on(event: 'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Subscribes to changes in the distributed data.| -| off(event:'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Unsubscribe from changes in the distributed data.| -| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback<string>): void; | Obtains the table name on the specified device based on the local table name.| -| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string> , callback: AsyncCallback<ResultSet>): void | Queries data from the RDB store of a remote device based on specified conditions.| +| setDistributedTables(tables: Array<string>, callback: AsyncCallback<void>): void | Sets the distributed tables to be synchronized.| +| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback<Array<[string, number]>>): void | Synchronizes data across devices.| +| on(event: 'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Subscribes to changes in the distributed data.| +| off(event:'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Unsubscribe from changes in the distributed data.| +| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback<string>): void; | Obtains the table name on the specified device based on the local table name.| +| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string> , callback: AsyncCallback<ResultSet>): 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'; diff --git a/en/application-dev/database/sync-app-data-across-devices-overview.md b/en/application-dev/database/sync-app-data-across-devices-overview.md index 875b70fef7d4b3bcd6b78a2102ec40c80d7da5f9..c2f6361786325ccd753aa8fa4afa3446d37b6e89 100644 --- a/en/application-dev/database/sync-app-data-across-devices-overview.md +++ b/en/application-dev/database/sync-app-data-across-devices-overview.md @@ -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). diff --git a/en/application-dev/dfx/Readme-EN.md b/en/application-dev/dfx/Readme-EN.md index c6b449f197ba66d8bd6f4021abffe6ce31a69028..b5990650c61eae7ed57a0b1dbc35489947de8bc8 100644 --- a/en/application-dev/dfx/Readme-EN.md +++ b/en/application-dev/dfx/Readme-EN.md @@ -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) diff --git a/en/application-dev/dfx/appfreeze-guidelines.md b/en/application-dev/dfx/appfreeze-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..05b52c4d8070386ec350701cefb2c6b63ef67d55 --- /dev/null +++ b/en/application-dev/dfx/appfreeze-guidelines.md @@ -0,0 +1,200 @@ +# 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. diff --git a/en/application-dev/dfx/apprecovery-guidelines.md b/en/application-dev/dfx/apprecovery-guidelines.md index e5e7b5274361a25009d33b694943b59ef2d9d8a1..284de5ca6d5f6027f2cce975a29b3259b2778021 100644 --- a/en/application-dev/dfx/apprecovery-guidelines.md +++ b/en/application-dev/dfx/apprecovery-guidelines.md @@ -5,48 +5,29 @@ During application running, some unexpected behaviors are inevitable. For example, unprocessed exceptions and errors are thrown, and the call or running constraints of the recovery framework are violated. Process exit is treated as the default exception handling method. However, if user data is generated during application use, process exit may interrupt user operations and cause data loss. -Application recovery helps to restore the application state and save temporary data upon next startup in the case of an abnormal process exit, thus providing more consistent user experience. The application state includes two parts, namely, the page stack of the and the data saved in **onSaveState**. +In this way, application recovery APIs may help you save temporary data, restart an application after it exits, and restore its status and data, which deliver a better user experience. -In API version 9, application recovery is supported only for a single ability of the application developed using the stage model. Application state saving and automatic restart are performed when a JsError occurs. - -In API version 10, application recovery is applicable to multiple abilities of an application developed using the stage model. Application state storage and restore are performed when an AppFreeze occurs. If an application is killed in control mode, the application state will be restored upon next startup. +Currently, the APIs support only the development of an application that adopts the stage model, single process, and single ability. ## Available APIs -The application recovery APIs are provided by the **appRecovery** module, which can be imported via **import**. For details, see [Development Example](#development-example). +The application recovery APIs are provided by the **appRecovery** module, which can be imported via **import**. For details, see [Development Example](#development-example). This document describes behaviors of APIs in API version 9, and the content will update with changes. ### Available APIs | API | Description | | ------------------------------------------------------------ | ---------------------------------------------------- | -| enableAppRecovery(restart?: RestartFlag, saveOccasion?: SaveOccasionFlag, saveMode?: SaveModeFlag) : void;9+ | Enables application recovery. After this API is called, the first ability that is displayed when the application is started from the initiator can be restored.| -| saveAppState(): boolean;9+ | Saves the state of the ability that supports recovery in the current application.| -| restartApp(): void;9+ | Restarts the current process and starts the ability specified by **setRestartWant**. If no ability is specified, a foreground ability that supports recovery is restarted.| -| saveAppState(context?: UIAbilityContext): boolean;10+ | Saves the ability state specified by **Context**.| -| setRestartWant(want: Want): void;10+ | Sets the abilities to restart when **restartApp** is actively called and **RestartFlag** is not **NO_RESTART**. The abilities must be under the same bundle name and must be a **UiAbility**.| +| enableAppRecovery(restart?: RestartFlag, saveOccasion?: SaveOccasionFlag, saveMode?: SaveModeFlag) : void; | Enables the application recovery function.| +| saveAppState(): boolean; | Saves the ability status of an application. | +| restartApp(): void; | Restarts the current process. If there is saved ability status, it will be passed to the **want** parameter's **wantParam** attribute of the **onCreate** lifecycle callback of the ability.| -No error will be thrown if the preceding APIs are used in the troubleshooting scenario. The following are some notes on API usage: +The APIs are used for troubleshooting and do not return any exception. Therefore, you need to be familiar with when they are used. **enableAppRecovery**: This API should be called during application initialization. For example, you can call this API in **onCreate** of **AbilityStage**. For details, see [Parameter Description](../reference/apis/js-apis-app-ability-appRecovery.md). -**saveAppState**: After this API is called, the recovery framework invokes **onSaveState** for all abilities that support recovery in the current process. If you choose to save data in **onSaveState**, the related data and ability page stack are persistently stored in the local cache of the application. To save data of the specified ability, you need to specify the context corresponding to that ability. - -**setRestartWant**: This API specifies the ability to be restarted by **appRecovery**. - -**restartApp**: After this API is called, the recovery framework kills the current process and restarts the ability specified by **setRestartWant**, with **APP_RECOVERY** set as the startup cause. In API version 9 and scenarios where an ability is not specified by **setRestartWant**, the last foreground ability that supports recovery is started. If the no foreground ability supports recovery, the application crashes. If a saved state is available for the restarted ability, the saved state is passed as the **wantParam** attribute in the **want** parameter of the ability's **onCreate** callback. - -### Application State Management -Since API version 10, application recovery is not limited to automatic restart in the case of an exception. Therefore, you need to understand when the application will load the saved state. -If the last exit of an application is not initiated by a user and a saved state is available for recovery, the startup reason is set to **APP_RECOVERY** when the application is started by the user next time, and the recovery state of the application is cleared. -The application recovery status flag is set when **saveAppState** is actively or passively called. The flag is cleared when the application exits normally or the saved state is consumed. (A normal exit is usually triggered by pressing the back key or clearing recent tasks.) - -![Application recovery status management](./figures/application_recovery_status_management.png) - -### Application State Saving and Restore -API version 10 or later supports saving of the application state when an application is suspended. If a JsError occurs, **onSaveState** is called in the main thread. If an AppFreeze occurs, however, the main thread may be suspended, and therefore **onSaveState** is called in a non-main thread. The following figure shows the main service flow. +**saveAppState**: After this API is called, the framework calls back **onSaveState** of the ability. If data saving is accepted in this API, relevant data and the page stack of the ability are persisted to the local cache of the application. -![Application recovery from the freezing state](./figures/application_recovery_from_freezing.png) -When the application is suspended, the callback is not executed in the JS thread. Therefore, you are advised not to use the imported dynamic Native library or access the **thread_local** object created by the main thread in the code of the **onSaveState** callback. +**restartApp**: After this API is called, the framework kills the current application process and restarts the ability in the foreground, with **APP_RECOVERY** specified as the startup cause. ### Framework Fault Management @@ -59,7 +40,9 @@ Fault management is an important way for applications to deliver a better user e - Fault query is the process of calling APIs of [faultLogger](../reference/apis/js-apis-faultLogger.md) to obtain the fault information. The figure below does not illustrate the time when [faultLogger](../reference/apis/js-apis-faultLogger.md) is called. You can refer to the [LastExitReason](../reference/apis/js-apis-app-ability-abilityConstant.md#abilityconstantlastexitreason) passed during application initialization to determine whether to call [faultLogger](../reference/apis/js-apis-faultLogger.md) to query information about the previous fault. + ![Fault rectification process](./figures/fault_rectification.png) + It is recommended that you call [errorManager](../reference/apis/js-apis-app-ability-errorManager.md) to handle the exception. After the processing is complete, you can call the **saveAppState** API and restart the application. If you do not register [ErrorObserver](../reference/apis/js-apis-inner-application-errorObserver.md) or enable application recovery, the application process will exit according to the default processing logic of the system. Users can restart the application from the home screen. If you have enabled application recovery, the recovery framework first checks whether application state saving is supported and whether the application state saving is enabled. If so, the recovery framework invokes [onSaveState](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonsavestate) of the [Ability](../reference/apis/js-apis-app-ability-uiAbility.md). Finally, the application is restarted. @@ -71,7 +54,7 @@ Common fault types include JavaScript application crash, application freezing, a | Fault | Fault Listening | State Saving| Automatic Restart| Log Query| | ----------|--------- |--------- |--------- |--------- | | [JS_CRASH](../reference/apis/js-apis-faultLogger.md#faulttype) | Supported|Supported|Supported|Supported| -| [APP_FREEZE](../reference/apis/js-apis-faultLogger.md#faulttype) | Not supported|Supported|Supported|Supported| +| [APP_FREEZE](../reference/apis/js-apis-faultLogger.md#faulttype) | Not supported|Not supported|Supported|Supported| | [CPP_CRASH](../reference/apis/js-apis-faultLogger.md#faulttype) | Not supported|Not supported|Not supported|Supported| **State Saving** in the table header means saving of the application state when a fault occurs. To protect user data as much as possible when an AppFreeze occurs, you can adopt either the periodic or automatic way, and the latter will save user data when an ability is switched to the background. @@ -96,31 +79,19 @@ export default class MyAbilityStage extends AbilityStage { appRecovery.SaveModeFlag.SAVE_WITH_FILE); } } -``` -### Enabling Application Recovery for the Specified Abilities -Generally, the ability configuration list is named **module.json5**. -```json -{ - "abilities": [ - { - "name": "EntryAbility", - "recoverable": true, - }] -} - ``` ### Saving and Restoring Data After enabling **appRecovery**, you can use this function by either actively or passively saving the application state and restoring data in the ability. -The following is an example of **EntryAbility**: +The following is an example of **MainAbility**: #### Importing the Service Package ```ts -import errorManager from '@ohos.app.ability.errorManager'; -import appRecovery from '@ohos.app.ability.appRecovery'; -import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import errorManager from '@ohos.app.ability.errorManager' +import appRecovery from '@ohos.app.ability.appRecovery' +import AbilityConstant from '@ohos.app.ability.AbilityConstant' ``` #### Actively Saving the Application State and Restoring Data @@ -139,7 +110,7 @@ import AbilityConstant from '@ohos.app.ability.AbilityConstant'; onWindowStageCreate(windowStage) { // Main window is created, set main page for this ability - console.log("[Demo] EntryAbility onWindowStageCreate") + console.log("[Demo] MainAbility onWindowStageCreate") globalThis.registerObserver = (() => { registerId = errorManager.on('error', callback); @@ -151,12 +122,12 @@ import AbilityConstant from '@ohos.app.ability.AbilityConstant'; - Save data. -After the callback triggers **appRecovery.saveAppState()**, **onSaveState(state, wantParams)** of **EntryAbility** is triggered. +After the callback triggers **appRecovery.saveAppState()**, **onSaveState(state, wantParams)** of **MainAbility** is triggered. ```ts onSaveState(state, wantParams) { // Ability has called to save app data - console.log("[Demo] EntryAbility onSaveState") + console.log("[Demo] MainAbility onSaveState") wantParams["myData"] = "my1234567"; return AbilityConstant.OnSaveResult.ALL_AGREE; } @@ -164,12 +135,12 @@ After the callback triggers **appRecovery.saveAppState()**, **onSaveState(state, - Restore data. -After the callback triggers **appRecovery.restartApp()**, the application is restarted. After the restart, **onCreate(want, launchParam)** of **EntryAbility** is called, and the saved data is stored in **parameters** of **want**. +After the callback triggers **appRecovery.restartApp()**, the application is restarted. After the restart, **onCreate(want, launchParam)** of **MainAbility** is called, and the saved data is in **parameters** of **want**. ```ts storage: LocalStorage onCreate(want, launchParam) { - console.log("[Demo] EntryAbility onCreate") + console.log("[Demo] MainAbility onCreate") globalThis.abilityWant = want; if (launchParam.launchReason == AbilityConstant.LaunchReason.APP_RECOVERY) { this.storage = new LocalStorage(); @@ -185,7 +156,7 @@ onCreate(want, launchParam) { ```ts onWindowStageDestroy() { // Main window is destroyed, release UI related resources - console.log("[Demo] EntryAbility onWindowStageDestroy") + console.log("[Demo] MainAbility onWindowStageDestroy") globalThis.unRegisterObserver = (() => { errorManager.off('error', registerId, (err) => { @@ -200,10 +171,10 @@ onWindowStageDestroy() { This is triggered by the recovery framework. You do not need to register an **ErrorObserver** callback. You only need to implement **onSaveState** for application state saving and **onCreate** for data restore. ```ts -export default class EntryAbility extends Ability { +export default class MainAbility extends Ability { storage: LocalStorage onCreate(want, launchParam) { - console.log("[Demo] EntryAbility onCreate") + console.log("[Demo] MainAbility onCreate") globalThis.abilityWant = want; if (launchParam.launchReason == AbilityConstant.LaunchReason.APP_RECOVERY) { this.storage = new LocalStorage(); @@ -215,26 +186,9 @@ export default class EntryAbility extends Ability { onSaveState(state, wantParams) { // Ability has called to save app data - console.log("[Demo] EntryAbility onSaveState") + console.log("[Demo] MainAbility onSaveState") wantParams["myData"] = "my1234567"; return AbilityConstant.OnSaveResult.ALL_AGREE; } } ``` - -#### Restart Flag for the Failed Ability - -If the failed ability is restarted again, the [ABILITY_RECOVERY_RESTART](../reference/apis/js-apis-app-ability-wantConstant.md#wantconstantparams) flag will be added as a **parameters** member for the **want** parameter in **onCreate** and its value is **true**. - -```ts -import UIAbility from '@ohos.app.ability.UIAbility'; -import wantConstant from '@ohos.app.ability.wantConstant'; -export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { - if (want.parameters[wantConstant.Params.ABILITY_RECOVERY_RESTART] != undefined && - want.parameters[wantConstant.Params.ABILITY_RECOVERY_RESTART] == true) { - console.log("This ability need to recovery"); - } - } -} -``` diff --git a/en/application-dev/dfx/cppcrash-guidelines.md b/en/application-dev/dfx/cppcrash-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..4454422fe4f3aec6c781090a2e833ee103488dab --- /dev/null +++ b/en/application-dev/dfx/cppcrash-guidelines.md @@ -0,0 +1,110 @@ +# cppcrash Log Analysis + +## Introduction + +A process crash refers to a C/C++ runtime crash. The FaultLogger module of OpenHarmony provides capabilities such as process crash detection, log collection, log storage, and log reporting, helping you to locate faults more effectively. + +In this document, you'll be guided through how to implement process crash detection, crash log collection, and crash log analysis. Before getting started, make sure you have basic knowledge about C/C++ program stacks. + +## Process Crash Detection + +Process crash detection is implemented based on the Linux signal mechanism. Currently, C/C++ crash exception signals listed in the following table are supported. + +| Signal Value| Signal| Description| Trigger Cause| +| ------ | --------- | --------------- | ------------------------------------------- | +| 4 | SIGILL | Invalid instruction | An invalid, incorrectly formatted, unknown, or privileged instruction is executed.| +| 5 | SIGTRAP | Breakpoint or trap | An exception occurs or a trap instruction is executed.| +| 6 | SIGABRT | Process abort | The process is aborted abnormally. Generally, this problem occurs if the process calls the `abort()` function of the standard function library.| +| 7 | SIGBUS | Illegal memory access | The process accesses an aligned or nonexistent physical address.| +| 8 | SIGFPE | Floating-point exception | The process performs an incorrect arithmetic operation, for example, a 0 divisor, floating point overflow, or integer overflow.| +| 11 | SIGSEGV | Invalid memory access | The process accesses an invalid memory reference.| +| 16 | SIGSTKFLT | Stack error | The processor performs an incorrect stack operation, such as a pop when the stack is empty or a push when the stack is full.| +| 31 | SIGSYS | Incorrect system call | An incorrect or invalid parameter is used in a system call.| + +## Crash Log Collection + +Process crash log is the fault log managed together with the app freeze and JS application crash logs by the FaultLogger module. You can collect process crash logs in any of the following ways: + +### Collecting Logs by Using Shell + +- Fault logs in the `/data/log/faultlog/faultlogger/` directory of the device. The log files are named in the format of `cppcrash-process name-process UID-time (seconds level)`. They contain only information such as the device name, system version, and process crash call stack. + + ![cppcrash-faultlogger-log](figures/20230407112159.png) + +- Fault logs in the `/data/log/faultlog/temp/` directory of the device. The log files are named in the format of `cppcrash-process name-process PID-system timestamp (seconds level)`. In addition to basic information, they also contain information such as the stack memory and process maps at the time of process crash. + + ![cppcrash-temp-log](figures/20230407111853.png) + +### Collecting Logs by Using DevEco Studio + +DevEco Studio collects process crash logs from `/data/log/faultlog/faultlogger/` to FaultLog, where logs are displayed by process name, fault, and time. + +![DevEco Studio cppcrash](figures/20230407112620.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). + +## Process Crash Log Analysis + +### Log Format + +The following is an example process crash log archived by DevEco Studio in FaultLog: + +``` +Generated by HiviewDFX@OpenHarmony +================================================================== +Device info:OpenHarmony 3.2 <- Device information +Build info:OpenHarmony 4.0.5.5 <- Version information +Module name:crasher_c <- Module name +Pid:1205 <- Process ID +Uid:0 <- User ID +Reason:Signal:SIGSEGV(SEGV_ACCERR)@0x0042d33d <- Exception information +Thread name:crasher <- Abnormal thread +#00 pc 0000332c /data/crasher(TriggerSegmentFaultException+15)(8bc37ceb8d6169e919d178fdc7f5449e) <- Call stack +#01 pc 000035c7 /data/crasher(ParseAndDoCrash+277)(8bc37ceb8d6169e919d178fdc7f5449e) +#02 pc 00003689 /data/crasher(main+39)(8bc37ceb8d6169e919d178fdc7f5449e) +#03 pc 000c3b08 /system/lib/ld-musl-arm.so.1(__libc_start_main+116) +#04 pc 000032f8 /data/crasher(_start_c+112)(8bc37ceb8d6169e919d178fdc7f5449e) +#05 pc 00003284 /data/crasher(_start+32)(8bc37ceb8d6169e919d178fdc7f5449e) +... +``` + +### Locating Faults Through Logs + +1. Determine the faulty module and fault type based on fault logs. + + Generally, you can identify the faulty module based on the crash process name and identify the crash cause based on the signal. Besides, you can restore the function call chain of the crash stack based on the method name in the stack. + + In the example, **SIGSEGV** is thrown by the Linux kernel because of access to an invalid memory address. The problem occurs in the **TriggerSegmentFaultException** function. + + In most scenarios, a crash is caused by the top layer of the crash stack, such as null pointer access and proactive program abort. + + If the cause cannot be located through the call stack, you need to check for other faults, for example, memory corruption or stack overflow. + +2. Use the addr2line tool of Linux to parse the code line number to restore the call stack at the time of process crash. + + When using the addr2line tool to parse the code line number of the crash stack, make sure that binary files with debugging information is used. Generally, such files are generated during version build or application build. + + Application binary files are located in DevEco Studio's temporary directory for application build, for example, `build/default/intermediates/libs`. + + System binary files are stored in the directories listed below. For versions that are directly obtained, the binary files are archived in the image package. + ``` + \code root directory\out\product\lib.unstripped + \code root directory\out\product\exe.unstripped + ``` + + You can run `apt-get install addr2line` to install the addr2line tool on Linux. + + On On DevEco Studio, you can also use the llvm-addr2line tool archived in the SDK to parse code line numbers. The usage method is the same. + + The following example shows how to use the addr2line tool to parse the code line number based on the offset address: + + ``` + root:~/OpenHarmony/out/rk3568/exe.unstripped/hiviewdfx/faultloggerd$ addr2line -e crasher 0000332c + base/hiviewdfx/faultloggerd/tools/crasher/dfx_crasher.c:57 + ``` + + In this example, the crash is caused by assignment of a value to an unwritable area. It is in code line 57 in the **dfx_crasher.c** file. You can modify it to avoid the crash. + + If the obtained code line number is seemingly incorrect, you can fine-tune the address (for example, subtract the address by 1) or disable some compilation optimization items. It is known that the obtained code line number may be incorrect when Link Time Optimization (LTO) is enabled. diff --git a/en/application-dev/dfx/errormanager-guidelines.md b/en/application-dev/dfx/errormanager-guidelines.md index 8509fff09e51cd31665e80fab6dce0f2472ab08d..4679cfcfc78893590fe73eab770e49fc68a1a828 100644 --- a/en/application-dev/dfx/errormanager-guidelines.md +++ b/en/application-dev/dfx/errormanager-guidelines.md @@ -23,8 +23,7 @@ When an asynchronous callback is used, the return value can be processed directl | API | Description | | ------------------------------ | ------------------------------------------------------------ | -| onUnhandledException(errMsg: string): void | Called when an uncaught exception is reported after the application is registered.| -| onException?(errObject: Error): void | Called when an application exception is reported to the JavaScript layer after the application is registered.| +| onUnhandledException(errMsg: string): void | Called when an application generates an uncaught exception after being registered.| ### Result Codes for Unregistering an Observer @@ -44,13 +43,6 @@ let registerId = -1; let callback = { onUnhandledException: function (errMsg) { console.log(errMsg); - }, - onException: function (errorObj) { - console.log('onException, name: ', errorObj.name); - console.log('onException, message: ', errorObj.message); - if (typeof(errorObj.stack) === 'string') { - console.log('onException, stack: ', errorObj.stack); - } } } diff --git a/en/application-dev/dfx/figures/20230407111853.png b/en/application-dev/dfx/figures/20230407111853.png new file mode 100644 index 0000000000000000000000000000000000000000..cedfb46aecd8a3a1a9482619e4b0ea5f18eccc4a Binary files /dev/null and b/en/application-dev/dfx/figures/20230407111853.png differ diff --git a/en/application-dev/dfx/figures/20230407112159.png b/en/application-dev/dfx/figures/20230407112159.png new file mode 100644 index 0000000000000000000000000000000000000000..c2bce4198850fc25bdb2a4328c1b600d99d39e88 Binary files /dev/null and b/en/application-dev/dfx/figures/20230407112159.png differ diff --git a/en/application-dev/dfx/figures/20230407112620.png b/en/application-dev/dfx/figures/20230407112620.png new file mode 100644 index 0000000000000000000000000000000000000000..59a25256717ee791e0a3c40ec1d46c78d889a60f Binary files /dev/null and b/en/application-dev/dfx/figures/20230407112620.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230308145160.png b/en/application-dev/dfx/figures/appfreeze_20230308145160.png new file mode 100644 index 0000000000000000000000000000000000000000..2be8a97cf7b2518a0361cb0f8965642731282350 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230308145160.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230308145161.png b/en/application-dev/dfx/figures/appfreeze_20230308145161.png new file mode 100644 index 0000000000000000000000000000000000000000..92c236037b7c75f6480b3781ee6b1aa15e44cc51 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230308145161.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230308145162.png b/en/application-dev/dfx/figures/appfreeze_20230308145162.png new file mode 100644 index 0000000000000000000000000000000000000000..9169db911499f350a302eb060300d2c83c9fae19 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230308145162.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230308145163.png b/en/application-dev/dfx/figures/appfreeze_20230308145163.png new file mode 100644 index 0000000000000000000000000000000000000000..14c42dc9159174e7ddb283b1454963d40c6871f1 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230308145163.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230308145164.png b/en/application-dev/dfx/figures/appfreeze_20230308145164.png new file mode 100644 index 0000000000000000000000000000000000000000..7311f26bd906fa24331eaa10b66643eb09cf266f Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230308145164.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105865.png b/en/application-dev/dfx/figures/appfreeze_20230310105865.png new file mode 100644 index 0000000000000000000000000000000000000000..0082b4a012d79e2a407934abc6b3e45e580e20dd Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105865.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105866.png b/en/application-dev/dfx/figures/appfreeze_20230310105866.png new file mode 100644 index 0000000000000000000000000000000000000000..87e25e01d01d5e039c1089ee7604d2e14403efee Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105866.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105867.png b/en/application-dev/dfx/figures/appfreeze_20230310105867.png new file mode 100644 index 0000000000000000000000000000000000000000..c77c4686a66c56dc051aaa3a1d7996a3cb93985b Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105867.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105868.png b/en/application-dev/dfx/figures/appfreeze_20230310105868.png new file mode 100644 index 0000000000000000000000000000000000000000..7c1f36e709e4b07908567a7124df5e45fbd9bad1 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105868.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105869.png b/en/application-dev/dfx/figures/appfreeze_20230310105869.png new file mode 100644 index 0000000000000000000000000000000000000000..a55b3373405f2f4db972507e2f35102021c7f92a Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105869.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105870.png b/en/application-dev/dfx/figures/appfreeze_20230310105870.png new file mode 100644 index 0000000000000000000000000000000000000000..73c0549142e49e233b3ea38f8e1b6e44c642a30e Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105870.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105871.png b/en/application-dev/dfx/figures/appfreeze_20230310105871.png new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6bb1156255571e45e4e22d69cea70ae474f Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105871.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105872.png b/en/application-dev/dfx/figures/appfreeze_20230310105872.png new file mode 100644 index 0000000000000000000000000000000000000000..43406b804f9c981e636f4ad6099ce1abd69fb3d1 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105872.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105873.png b/en/application-dev/dfx/figures/appfreeze_20230310105873.png new file mode 100644 index 0000000000000000000000000000000000000000..71457fa6a49bf657a3b4527c7a000818c824ba94 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105873.png differ diff --git a/en/application-dev/dfx/figures/appfreeze_20230310105874.png b/en/application-dev/dfx/figures/appfreeze_20230310105874.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4fc75b47b439fe131121586f13bdbf41408082 Binary files /dev/null and b/en/application-dev/dfx/figures/appfreeze_20230310105874.png differ diff --git a/en/application-dev/dfx/figures/application_recovery_from_freezing.png b/en/application-dev/dfx/figures/application_recovery_from_freezing.png deleted file mode 100644 index 968b4cefc5e898209cdae117c7f9f667bc9fbd64..0000000000000000000000000000000000000000 Binary files a/en/application-dev/dfx/figures/application_recovery_from_freezing.png and /dev/null differ diff --git a/en/application-dev/dfx/figures/application_recovery_status_management.png b/en/application-dev/dfx/figures/application_recovery_status_management.png deleted file mode 100644 index 762504c1d1027be87233e589988be2091640191b..0000000000000000000000000000000000000000 Binary files a/en/application-dev/dfx/figures/application_recovery_status_management.png and /dev/null differ diff --git a/en/application-dev/dfx/figures/fault_rectification.png b/en/application-dev/dfx/figures/fault_rectification.png index a178b2691616d406d2668806ffcd4f89c8ca82a3..67aa40592f7bcad23e216222e898c1f1327a4efb 100644 Binary files a/en/application-dev/dfx/figures/fault_rectification.png and b/en/application-dev/dfx/figures/fault_rectification.png differ diff --git a/en/application-dev/dfx/hiappevent-guidelines.md b/en/application-dev/dfx/hiappevent-guidelines.md index 569b16d587af811d32e425a534ab4dc0df6a4be6..d21d4e3fa9e0fa0b795c82e7157cd6215eab5e0c 100644 --- a/en/application-dev/dfx/hiappevent-guidelines.md +++ b/en/application-dev/dfx/hiappevent-guidelines.md @@ -49,11 +49,11 @@ The following example illustrates how to log and subscribe to button click event ```js import hilog from '@ohos.hilog'; - import UIAbility from '@ohos.app.ability.UIAbility'; + import Ability from '@ohos.application.Ability' import Window from '@ohos.window' import hiAppEvent from '@ohos.hiviewdfx.hiAppEvent' - export default class EntryAbility extends UIAbility { + export default class EntryAbility extends Ability { onCreate(want, launchParam) { hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); diff --git a/en/application-dev/dfx/hilog-guidelines.md b/en/application-dev/dfx/hilog-guidelines.md index ef09dabc109c1797949d928bce98564ad9ad76ba..a399a520ba96aa3a64eea8968ed359c05da5440b 100644 --- a/en/application-dev/dfx/hilog-guidelines.md +++ b/en/application-dev/dfx/hilog-guidelines.md @@ -1,30 +1,30 @@ -# HiLog Development - -## Overview +# HiLog Development (Native) + +## Introduction HiLog is the log system of OpenHarmony that provides logging for the system framework, services, and applications to record information on user operations and system running status. > **NOTE** > -> This development guide is applicable only when you use Native APIs for application development. For details about the APIs, see [HiLog Native API Reference](https://gitee.com/openharmony-sig/interface_native_header/blob/master/en/native_sdk/dfx/log.h). +> This development guide is applicable only when you use Native APIs for application development. For details about the APIs, see [HiLog Native API Reference](../reference/native-apis/_hi_log.md). ## Available APIs | API/Macro| Description| | -------- | -------- | -| int OH_LOG_Print(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) | Outputs logs based on the specified log type, log level, service domain, log tag, and variable parameters determined by the format specifier and privacy identifier in the printf format.
Input parameters: See [Parameter Description](#parameter-description).
Output parameters: None
Return value: total number of bytes if log printing is successful; **-1** otherwise.| +| int OH_LOG_Print(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) | Outputs logs based on the specified log type, log level, service domain, log tag, and variable parameters determined by the format specifier and privacy identifier in the printf format.
Input arguments: See [Parameter Description](#parameter-description).
Output arguments: None
Return value: total number of bytes if log printing is successful; **-1** otherwise.| | #define OH_LOG_DEBUG(type, ...) ((void)OH_LOG_Print((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, \_*VA*ARGS__))| Outputs DEBUG logs. This is a function-like macro.| | #define OH_LOG_INFO(type, ...) ((void)OH_LOG_Print((type), LOG_INFO, LOG_DOMAIN, LOG_TAG, \_*VA*ARGS__)) | Outputs INFO logs. This is a function-like macro.| | #define OH_LOG_WARN(type, ...) ((void)OH_LOG_Print((type), LOG_WARN, LOG_DOMAIN, LOG_TAG, \_*VA*ARGS__)) | Outputs WARN logs. This is a function-like macro.| | #define OH_LOG_ERROR(type, ...) ((void)OH_LOG_Print((type), LOG_ERROR, LOG_DOMAIN, LOG_TAG, \_*VA*ARGS__)) | Outputs ERROR logs. This is a function-like macro.| | #define OH_LOG_FATAL(type, ...) ((void)OH_LOG_Print((type), LOG_FATAL, LOG_DOMAIN, LOG_TAG, \_*VA*ARGS__)) | Outputs FATAL logs. This is a function-like macro.| -| bool OH_LOG_IsLoggable(unsigned int domain, const char *tag, LogLevel level) | Checks whether logs of the specified service domain, tag, and level can be printed.
Input parameters: See [Parameter Description](#parameter-description).
Output arguments: none
Return value: **true** if the specified logs can be printed; **false** otherwise.| +| bool OH_LOG_IsLoggable(unsigned int domain, const char *tag, LogLevel level) | Checks whether logs of the specified service domain, tag, and level can be printed.
Input arguments: See [Parameter Description](#parameter-description).
Output arguments: none
Return value: **true** if the specified logs can be printed; **false** otherwise.| ## Parameter Description | Name| Type | Mandatory| Description | | ------ | ------ | ---- | ------------------------------------------------------------ | -| type | enum | Yes | Enum of log printing types. The default value is **LOG_APP** for application logs.| +| type | enum | Yes | Log printing type. The default value is **LOG_APP** for application logs.| | level | enum | Yes | Log printing level. For details, see [Log Level](#loglevel).| | domain | number | Yes | Service domain of logs. The value ranges from **0x0** to **0xFFFF**.
You can define the value as required. | | tag | string | Yes | Log tag in the string format. You are advised to use this parameter to identify a particular service behavior or the class holding the ongoing method.| @@ -43,7 +43,7 @@ Log level. | ERROR | 6 | Log level used to record program or functional errors that affect the normal running or use of the functionality and can be fixed at a high cost, for example, by resetting data.| | FATAL | 7 | Log level used to record program or functionality crashes that cannot be rectified. -## Development Examples +## Development Example 1. Add the link of **libhilog_ndk.z.so** to **CMakeLists.txt**: ``` diff --git a/en/application-dev/dfx/hitracechain-guidelines.md b/en/application-dev/dfx/hitracechain-guidelines.md index 37ca65ece66a124eb8a72f1fd865f30d26024627..affd260b0503f3c4f4c4b748d5911d94f7fef9e3 100644 --- a/en/application-dev/dfx/hitracechain-guidelines.md +++ b/en/application-dev/dfx/hitracechain-guidelines.md @@ -2,7 +2,9 @@ ## Introduction -hiTraceChain is a lightweight implementation of the cloud-based distributed call chain tracing. It allows applications to trace cross-thread, cross-process, and cross-device service calls. The hiTraceChain module generates a unique **chainId** for a service process and passes it to various information (including application events, system time, and logs) specific to the service process. During debugging and fault locating, you can use the unique **chainId** to quickly correlate various information related to the service process. The hiTraceChain module provides APIs to implement call chain tracing throughout a service process. This can help you quickly obtain the run log for the call chain of a specified service process and locate faults in inter-device, inter-process, or inter-thread communications. +The hiTraceChain module provides APIs to implement call chain tracing throughout a service process. This can help you quickly obtain the run log for the call chain of a specified service process and locate faults in inter-device, inter-process, or inter-thread communications. + +hiTraceChain is a lightweight implementation of the cloud-based distributed call chain tracing. It allows applications to trace cross-thread, cross-process, and cross-device service calls. The hiTraceChain module generates a unique **chainId** for a service process and passes it to various information (including application events, system time, and logs) specific to the service process. During debugging and fault locating, you can use the unique **chainId** to quickly correlate various information related to the service process. ## Basic Concepts @@ -16,106 +18,47 @@ The APIs for distributed call chain tracing are provided by the **hiTraceChain** **APIs for distributed call chain tracing** -| API | Return Value | Description | -| ------------------------------------------------------------------------------------------------------------------- | -------------- | ------------ | -| hiTraceChain.begin(name: string, flags: number = HiTraceFlag.DEFAULT) | HiTraceId | Starts call chain tracing. | -| hiTraceChain.end(id: HiTraceId) | void | Stops call chain tracing. | +| API| Return Value| Description| +| ------------------------------------------------------------------------------------------------------------------- | -------------- | ------------ | +| hiTraceChain.begin(name: string, flags: number = HiTraceFlag.DEFAULT) | HiTraceId | Starts call chain tracing.| +| hiTraceChain.tracepoint(mode: HiTraceCommunicationMode, type: HiTraceTracepointType, id: HiTraceId, msg?: string) | void | Creates a trace point.| +| hiTraceChain.end(id: HiTraceId) | void | Stops call chain tracing.| ## How to Develop -The following example illustrates how to simulate one-time [system event logging](../reference/apis/js-apis-hisysevent.md) to implement cross-thread distributed call chain tracing in a single HAP service. - -1. Create an eTS application project. In the displayed **Project** window, choose **entry** > **src** > **main** > **ets** > **pages** > **index.ets**, and double-click **index.ets**. Then, add a button to trigger system event logging. - - ```ts - import hiTraceChain from '@ohos.hiTraceChain'; - import hiSysEvent from '@ohos.hiSysEvent'; - - @Entry - @Component - struct Index { - @State message: string = 'Start writing system event'; - - build() { - Row() { - Column() { - Button(this.message) - .fontSize(20) - .margin(5) - .width(350) - .height(60) - .fontWeight(FontWeight.Bold) - .onClick(() => { - try { - // Enable distributed call chain tracing before the service starts. - let traceId = hiTraceChain.begin("Write a new system event", hiTraceChain.HiTraceFlag.INCLUDE_ASYNC); - // Implement one-time system event logging when the service starts. - hiSysEvent.write({ - domain: "RELIABILITY", - name: "STACK", - eventType: hiSysEvent.EventType.FAULT, - params: { - PID: 1, - UID: 1, - PACKAGE_NAME: "com.demo.hitracechain", - PROCESS_NAME: "hitracechaindemo", - MSG: "no msg." - } - }).then((val) => { - console.info(`write result is ${val}`); - // Disable distributed call chain tracing when the service ends. - hiTraceChain.end(traceId); - }).catch((err) => { - console.error(`error message is ${err.message}`); - }); - } catch (err) { - console.error(`error message is ${err.message}`); - } - }) - } - .width('100%') - } - .height('100%') - } - } - ``` - -2. Touch the run button on the IDE to run the project. Then, touch the **Start writing system event** button on the application UI to trigger system event logging. - -3. View the information printed in the **Log** window. You can use **.*: \[([0-9a-zA-Z]{15}),.*].*** to access distributed call chain tracing information specific to the HAP service. The process ID of the HAP service is **8801**. Two threads, whose IDs are **8801** and **8819**, are involved in the system event logging. Based on the chain ID **edcfa53017a88e3**, you can then effectively trace the log information of the two threads. - ```text - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain I C02d03/HiTraceC: [edcfa53017a88e3, 0, 0] HiTraceBegin name:Write a new system event flags:0x01. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 0, 0] Native2Js: chainId is edcfa53017a88e3. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 0, 0] Native2Js: spanId is 0. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 0, 0] Native2Js: parentSpanId is 0. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 0, 0] Native2Js: flags is 1. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] domain is RELIABILITY. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] name is STACK. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] eventType is 1. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain E C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] napi value type not match: valueType=3, typeName=6. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain E C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] napi value type not match: valueType=3, typeName=6. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain E C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] napi value type not match: valueType=4, typeName=6. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain E C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] napi value type not match: valueType=4, typeName=6. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain E C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] napi value type not match: valueType=4, typeName=6. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] create napi value of string type, value is JSHiSysEventWrite. - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain I C03900/Ace: [edcfa53017a88e3, 0, 0] [flutter_ace_view.cpp(operator())-(0)] Mark 0 id Touch Event Processed - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02800/ClientMsgHandler: [edcfa53017a88e3, 0, 0] in OnDispatchEventProcessed, enter - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02800/ANRHandler: [edcfa53017a88e3, 0, 0] in SetLastProcessedEventId, enter - 07-05 19:50:47.690 8801-8819/com.demo.hitracechain D C02d08/HISYSEVENT: [edcfa53017a88e3, 0, 0] size=312, sysevent={"domain_":"RELIABILITY","name_":"STACK","type_":1,"time_":47591447690,"tz_":"+0000","pid_":8801,"tid_":8819,"uid_":20010045,"traceid_":"edcfa53017a88e3","spanid_":"0","pspanid_":"0","trace_flag_":1,"UID":1,"PID":1,"MSG":"no msg.","PROCESS_NAME":"hitracechaindemo","PACKAGE_NAME":"com.demo.hitracechain"} - 07-05 19:50:47.690 8801-8801/com.demo.hitracechain D C02800/ANRHandler: [edcfa53017a88e3, 0, 0] in SetLastProcessedEventId, Processed event type:0, id:831, actionTime:6694499314, currentTime:6694501330, timeoutTime:4997984 - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02800/ANRHandler: [edcfa53017a88e3, 0, 0] in SetLastProcessedEventId, leave - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02800/ClientMsgHandler: [edcfa53017a88e3, 0, 0] in OnDispatchEventProcessed, leave - 07-05 19:50:47.691 8801-8819/com.demo.hitracechain D C02d08/HISYSEVENT: [edcfa53017a88e3, 0, 0] reset send buffer size old=245760, new=524288 - 07-05 19:50:47.691 8801-8819/com.demo.hitracechain D C02d08/HISYSEVENT: [edcfa53017a88e3, 0, 0] HiSysEvent send data successful - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02d08/NAPI_HISYSEVENT_UTIL: [edcfa53017a88e3, 0, 0] create napi value of int32 type, value is 0. - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain E A0fefe/JsApp: [edcfa53017a88e3, 399db38, 0] write result is 0 - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 399db38, 0] Js2Native: chainId is edcfa53017a88e3. - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 399db38, 0] Js2Native: spanId is 0. - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 399db38, 0] Js2Native: parentSpanId is 0. - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain D C02d03/HITRACE_UTIL_NAPI: [edcfa53017a88e3, 399db38, 0] Js2Native: flags is 1. - 07-05 19:50:47.691 8801-8801/com.demo.hitracechain I C02d03/HiTraceC: [edcfa53017a88e3, 399db38, 0] HiTraceEnd. - ``` +In this example, distributed call chain tracing begins when the application startup execution page is loaded and stops when the service usage is completed. + +1. Create a JS application project. In the displayed **Project** window, choose **entry** > **src** > **main** > **js** > **default** > **pages** > **index**, and double-click **index.js**. Add the code to implement call chain tracing upon page loading. The sample code is as follows: -## About Cross-Process/Cross-Device Distributed Call Chain Tracing + ``` + import hiTraceChain from '@ohos.hiTraceChain' + + export default { + data: { + title: "" + }, + onInit() { + this.title = this.$t('strings.world'); + + // 1. Enable distributed call chain tracing. + let asyncTraceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.INCLUDE_ASYNC | hiTraceChain.HiTraceFlag.DONOT_CREATE_SPAN); + + // 2. Start the service process. + console.log(`business start`); + + // 3. Add a trace point. + hiTraceChain.tracepoint(hiTraceChain.HiTraceCommunicationMode.THREAD, hiTraceChain.HiTraceTracepointType.SS, asyncTraceId, "Just an example"); + + // 4. Keep the service process running. + console.log(`business running`); + + // 5. End the service process. + console.log(`business end`); + + // 6. Stop call chain tracing. + hiTraceChain.end(asyncTraceId); + } + } + ``` -Cross-process/cross-device distributed call chain tracing depends on the NAPI implementation of the corresponding service APIs of each OpenHarmony module. For details, see the [HiTraceChain Development](../../device-dev/subsystems/subsys-dfx-hitracechain.md). +2. Click the run button on the application page. Then, you'll obtain the log information for service analysis. diff --git a/en/application-dev/dfx/hitracemeter-guidelines.md b/en/application-dev/dfx/hitracemeter-guidelines.md index 1547ba195a49da7891ba7184a0b716c66c500046..3adf91286aaf410d7862c60320878e57acb359e8 100644 --- a/en/application-dev/dfx/hitracemeter-guidelines.md +++ b/en/application-dev/dfx/hitracemeter-guidelines.md @@ -17,7 +17,7 @@ hiTraceMeter provides APIs for system performance tracing. You can call the APIs ## Constraints -- Due to the asynchronous I/O feature of JS, the hiTraceMeter module provides only asynchronous APIs. +Due to the asynchronous I/O feature of JS, the hiTraceMeter module provides only asynchronous APIs. ## Available APIs diff --git a/en/application-dev/faqs/Readme-EN.md b/en/application-dev/faqs/Readme-EN.md index e76f1f1205949c45dcea65c19878e16cc77b7bf8..c8989927e1f804c14effdfe071082ed15410ea80 100644 --- a/en/application-dev/faqs/Readme-EN.md +++ b/en/application-dev/faqs/Readme-EN.md @@ -1,18 +1,19 @@ # FAQs -- [Programming Languages](faqs-language.md) -- [Ability Framework Development](faqs-ability.md) +- [Ability Development](faqs-ability.md) +- [Bundle Management Development](faqs-bundle-management.md) - [Resource Manager Development](faqs-globalization.md) -- [ArkUI (ArkTS) Development](faqs-ui-ets.md) -- [ArkUI Web Component (ArkTS) Development](faqs-web-arkts.md) -- [ArkUI (JavaScript) Development](faqs-ui-js.md) - [Common Event and Notification Development](faqs-event-notification.md) -- [Graphics and Image Development](faqs-graphics.md) +- [Graphics Development](faqs-graphics.md) +- [Window Management Development](faqs-window-manager.md) +- [Multimedia Development](faqs-multimedia.md) +- [Basic Security Capability Development](faqs-security.md) +- [Ability Access Control Development](faqs-ability-access-control.md) +- [Data Management Development](faqs-distributed-data-management.md) - [File Management Development](faqs-file-management.md) -- [Media Development](faqs-media.md) - [Network Management Development](faqs-network-management.md) - [DFX Development](faqs-dfx.md) -- [Native API Usage](faqs-native.md) +- [Pan-Sensor Development](faqs-sensor.md) - [Startup Development](faqs-startup.md) -- [Usage of Third- and Fourth-Party Libraries](faqs-third-party-library.md) -- [IDE Usage](faqs-ide.md) +- [Distributed Device Development](faqs-distributed-device-profile.md) +- [Usage of Third- and Fourth-Party Libraries](faqs-third-fourth-party-library.md) \ No newline at end of file diff --git a/en/application-dev/faqs/faqs-ability-access-control.md b/en/application-dev/faqs/faqs-ability-access-control.md new file mode 100644 index 0000000000000000000000000000000000000000..51b3310de190a521b47471d607134c014a79be8c --- /dev/null +++ b/en/application-dev/faqs/faqs-ability-access-control.md @@ -0,0 +1,7 @@ +# Ability Access Control Development + +## Can the app listen for the permission change after its permission is modified in Settings? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +Third-party apps cannot listen for the permission change. diff --git a/en/application-dev/faqs/faqs-ability.md b/en/application-dev/faqs/faqs-ability.md index aab3ecc19aff704dbc34b9f7aa4d174344735453..b6901e40e6d84c622c41e487e30c62ba87a28ff4 100644 --- a/en/application-dev/faqs/faqs-ability.md +++ b/en/application-dev/faqs/faqs-ability.md @@ -1,68 +1,124 @@ -# Ability Framework Development +# Ability Development -## Is a guide similar to the Data ability development in the FA model available for the stage model? +## How do I obtain a notification when the device orientation changes? -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -A guide is available for the **DataShareExtensionAbility** class, which provides APIs for sharing data with other applications and managing the data, in the stage model. +**Solution** -Reference: [DataShare Development](../database/database-datashare-guidelines.md) +Use the **UIAbility.onConfigurationUpdate\(\)** callback to subscribe to system environment variable changes (including the language, color mode, and screen orientation). -## What should I do if the UI does not respond when an ability is started? +**Reference** -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +[Subscribing to System Environment Variable Changes](../application-models/subscribe-system-environment-variable-changes.md#using-uiability-for-subscription) -1. If the ability is started using **startAbility**, check whether the **abilityName** field in **want** uses the bundle name as the prefix. If yes, delete the bundle name. +## How do I redirect a user to a specified page after they touch a service widget? -2. Make sure the ability's home page file configured by **onWindowStageCreate** in the **MainAbility.ts** file is defined in the **main_pages.json** file. +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -3. You are advised to use the SDK and OpenHarmony SDK versions released on the same day. +**Solution** -Reference: [Release Testing Version](https://gitee.com/openharmony-sig/oh-inner-release-management/blob/master/Release-Testing-Version.md) +Configure a widget event with the redirected-to UIAbility specified, and call **loadContent** in the **onWindowStageCreate\(\)** callback of the target UIAbility to redirect to the specified page. -## How do I set the UI of an ability to transparent? +**Reference** -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +[Developing Widget Events](../application-models/arkts-ui-widget-configuration.md) -Set the background color of the top container component to transparent, and then set the **opacity** attribute of the XComponent to **0.01**. +## How do I create a background service in the stage model? -Example: +Applicable to: OpenHarmony 3.2 Beta5 -``` -build() { - Stack() { - XComponent({ - id: 'componentId', - type: 'surface', - }) - .width('100%') - .height('100%') - .opacity(0.01) - // Page content - } - .width('100%') - .height('100%') - .backgroundColor('rgba(255,255,255, 0)') -} -``` +**Symptom** + +**ServiceExtensionAbility** in the stage model is a system API. Therefore, third-party applications cannot use it to create a background service. + +**Solution** + +Create a background task to provide the background service. + +**Reference** + +[Background Task](../task-management/background-task-overview.md) + +## Can I create a UIAbility and specify the process to run the UIAbility in the FA and Stage models? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Yes. + +- FA model + + The FA model supports multiple processes. By default, all components of an application run in the same process. This default scenario is suitable for most applications. To run a specific component in an independent process, configure the **process** tag under **ability** in the configuration file. Note that this tag is available only for system applications. + +- Stage model + + The stage model supports multiple processes. The process model is defined by the system, and third-party applications cannot be configured with multiple processes. To customize an independent process, you must request special permissions, and then specify the **process** tag under **module** in the configuration file. This tag specifies the process in which all the abilities in an HAP run. If this tag is not set, the bundle name is used as the process name by default. + + +## What are the differences between the stage model and the FA model in intra-process object sharing? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +- In the stage model, multiple application components share the same ArkTS engine instance. Therefore, they can easily share objects and state with each other. This also reduces the memory usage of complex applications. +- In the FA model, each application component exclusively uses an ArkTS engine instance. Therefore, you are advised to use the stage model when developing complex applications in distributed scenarios. + +**Reference** + +[Data Synchronization Between UIAbility and UI](../application-models/uiability-data-sync-with-ui.md) + +## How do I use the lifecycle functions of AbilityStage? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Add the field **"srcEntry": "./ets/myabilitystage/MyAbilityStage.ts"** under **module** in the **module.json5** file. + +**Reference** + +[AbilityStage Component Container](../application-models/abilitystage.md) + + +## How do I delete the mission snapshot in Recents after terminateself is called in the multiton scenario? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +You can set **removeMissionAfterTerminate** to **true** in the **module.json5** file. + +## Why can't I start a UIAbility instance by using startAbility\(\)? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +- If the UIAbility is started using **startAbility**, check whether the **abilityName** field in **want** uses the bundle name as the prefix. If yes, delete the bundle name. +- Make sure the UIAbility's home page file configured by **onWindowStageCreate** in the **MainAbility.ts** file is defined in the **main\_pages.json** file. You are advised to use the SDK and OpenHarmony SDK versions released on the same day. ## How do I prevent "this" in a method from changing to "undefined" when the method is called? -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** -Method 1: Add **.bind(this)** when calling the method. +Method 1: Add **.bind\(this\)** when calling the method. Method 2: Use the arrow function. -## What should I do when the message "must have required property 'startWindowIcon'" is displayed? +## What should I do when the error message "must have required property 'startWindowIcon'" is displayed during the UIAbility startup? -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -Configure the **startWindowIcon** attribute under **abilities** in the **module.json5** file. +**Solution** -Reference: [Application Package Structure (Stage Model)](../quick-start/module-configuration-file.md) +Configure the **startWindowIcon** attribute under **abilities** in the **module.json5** file. -Example: +**Example** ``` { @@ -77,138 +133,226 @@ Example: } ``` -## How do I obtain a notification when the device orientation changes? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +**Reference** -Implement the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the orientation and density) change. +[module.json5 Configuration File](../quick-start/module-configuration-file.md) ## Can I obtain the context through globalThis in the stage model? -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +Do not use **globalThis** to obtain the context in the stage model. + +This is because all the processes of an application share a JS VM instance in the stage model. Multiple abilities can run on these processes and share the same global object. If **globalThis** is used, the context of different abilities of the same JS VM instance may be returned. + +**Reference** + +[Data Synchronization Between UIAbility and UI](../application-models/uiability-data-sync-with-ui.md) -Do not use **globalThis** to obtain the context in the stage model. This is because all the processes of an application share a JS VM instance in the stage model. Multiple abilities can run on these processes and share the same global object. If **globalThis** is used, the context of different abilities of the same JS VM instance may be returned. +## What should I do when an error indicating too large size is reported during HAP deployment? -Reference of the recommended operation: [Context (Stage Model)](../application-models/application-context-stage.md) +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -## How do I obtain the HAP installation path of application B from application A? +**Symptom** -Applicable to: OpenHarmony SDK 3.0 or later, stage model of API version 9 +During HAP deployment, the following error message is displayed: -First, request the system permission. For details, see [Having Your App Automatically Signed](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-auto-configuring-signature-information-0000001271659465). Then, import the **bundle** module, and call **bundle.getApplicationInfo()** to obtain application information based on the bundle name. Finally, use **application.moduleSourceDirs** to obtain the application storage path. +Failure\[INSTALL\_FAILED\_SIZE\_TOO\_LARGE\] error while deploying hap? + +**Solution** + +You can split the HAP into multiple HAPs. ## How is data returned when startAbilityForResult is called? -Applicable to: OpenHarmony SDK3.0, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -The callee uses **AbilityContext.terminateSelfWithResult** to destroy its ability and pass parameters to **startAbilityForResult**. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextterminateselfwithresult). +**Solution** -## Can the lifecycle callback of a released FA widget be triggered when the widget is displayed in the service center so that the user login information can be obtained without opening the FA application? +The target UIAbilities uses **AbilityContext.terminateSelfWithResult** to terminate itselef and pass the result to **startAbilityForResult**. -Applicable to: OpenHarmony SDK 3.2.5.5, FA model of API version 8 +**Reference** -After a widget is added, the **oncreate()** lifecycle is triggered so that related user information (silent login) can be displayed even when the application is not started. However, users must manually add the widget after the application is installed. +[Starting UIAbility in the Same Application and Obtaining the Return Result](../application-models/uiability-intra-device-interaction.md) -## How do I obtain the context? -Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 +## How do I obtain the system timestamp? -You can use **this.context** to obtain the context in the **MainAbility.ts** file or call **getContext(this)** to obtain the context on the component page. +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -## What should I do when undefined is displayed for the calling of **abilityAccessCtrl.grantUserGrantedPermission** during API version 8 syntax verification? +**Solution** -Applicable to: OpenHarmony SDK 3.0, FA model of API version 8 +Use **getCurrentTime** of **@ohos.systemDateTime** to obtain the system time and time zone. -**abilityAccessCtrl.grantUserGrantedPermission** is a system API. It is not available in the public SDK, which is provided as default on DevEco Studio. To use system APIs, switch to the full SDK. For details, see [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md). +**Example** -## Which of the following Extension abilities are available in the public SDK: ServiceExtensionAbility, FormExtensionAbility, and DataShareExtensionAbility? +Use the **@ohos.systemDateTime** API as follows: -Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + ``` + try { + systemDateTime.getCurrentTime(true, (error, time) => { + if (error) { + console.info(`Failed to get currentTime. message: ${error.message}, code: ${error.code}`); + return; + } + console.info(`Succeeded in getting currentTime : ${time}`); + }); + } catch(e) { + console.info(`Failed to get currentTime. message: ${e.message}, code: ${e.code}`); + } + ``` -Among the aforementioned Extension abilities, only **FormExtensionAbility** is available in the public SDK. **ServiceExtensionAbility** and **DataShareExtensionAbility** are system APIs and available only in the full SDK. -Public SDK: intended for application developers and does not contain system APIs that require system permissions. +**Reference** -Full SDK: intended for original equipment manufacturers (OEMs) and contains system APIs that require system permissions. +[System time and time zone] (../reference/apis/js-apis-system-date-time.md#systemdatetimegetcurrenttime) -## Why can't I play GIF images cyclically on the widget? +## How do I obtain the cache directory of the current application? -Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -The system does not support the display of GIF images on the widget. +**Solution** -## How do I implement service login by touching a widget? +Use **Context.cacheDir** to obtain the cache directory of the application. -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 +**Reference** -You can start an ability upon the touch and implement service login in the ability. +[Obtaining the Application Development Path](../application-models/application-context-stage.md#obtaining-the-application-development-path) -## How do I redirect to the application details page in Settings? +## In which JS file is the service widget lifecycle callback invoked? -Applicable to: OpenHarmony SDK 3.2.6.5 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -Refer to the following code: +**Solution** -``` -this.context.startAbility( -{ - action: "action.settings.app.info", - parameters: { "settingsParamBundleName": "your app bundlename" } -}) -``` +When a widget is created, a **FormAblity.ts** file is generated, which contains the widget lifecycle. -## How do I listen for screen rotation events? +**Reference** -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 +[FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) -Refer to the following code: +## What should I do when the compilation on DevEco Studio fails while ServiceExtensionAbility and DataShareExtensionAbility APIs are used? -``` -let listener = mediaquery.matchMediaSync('(orientation: landscape)') -onPortrait(mediaQueryResult) { -if (mediaQueryResult.matches) { -// Do something here. - } else { -// Do something here. - } -} -listener.on('change', onPortrait) -``` +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +After the **ServiceExtensionAbility** and **DataShareExtensionAbility** APIs are used, DevEco Studio reports an error indicating that the compilation fails. + +**Cause** + +The following types of SDKs are provided: + +- Public SDK: intended for application developers and does not contain system APIs that require system permissions. +- Full SDK: intended for original equipment manufacturers (OEMs) and contains system APIs that require system permissions. + +The SDK downloaded using DevEco Studio is the public SDK. + +**Solution** + +Third-party application cannot use **ServiceExtensionAbility** and **DataShareExtensionAbility**. To develop a system application, first [download the full SDK](../quick-start/full-sdk-switch-guide.md). + +## How do I obtain the temp and files paths at the application level? + +Applicable to: OpenHarmony 3.2 Beta5 + +**Solution** + +Obtain them from the application context. Specifically, use **this.context.getApplicationContext.tempDir** i to obtain the **temp** path, and use **this.context.getApplicationContext.filesDir** to obtain the **files** path. + +**Reference** + +[Obtaining the Application Development Path](../application-models/application-context-stage.md#obtaining-the-application-development-path) + + +## Can the lifecycle callback of a released FA widget be triggered when the widget is displayed in the service center so that the user login information can be obtained without opening the FA application? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -## How do I control the shadow background size during checkbox selection? +**Solution** -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 +After a widget is added, the **onCreate()** lifecycle is triggered so that related user information (silent login) can be displayed even when the application is not started. However, users must manually add the widget after the application is installed. -Set the **padding** attribute of the **\** component to control the shadow size. +## How do I implement service login by touching a widget? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +To create a service widget in the FA model, perform the following steps: + +1. Implement lifecycle callbacks for the widget. + +2. Configure the widget configuration file. + +3. Persistently store widget data. -## How do I set the widget background to transparent? +4. Update widget data. -Applicable to: OpenHarmony SDK 3.2.5.5 +5. Develop the widget UI page. -1. Create the **widget/resources/styles/default.json** file in the root directory of the widget. +6. Develop a widget event. You can start a UIAbility upon the touch and implement service login in the UIAbility. -2. Add the following code to the **default.json** file: +**Reference** + +[Widget Development in the FA Model](../application-models/widget-development-fa.md) + +## How do I redirect to the application details page in Settings? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Refer to the following code: ``` -{ - "style": { - "app_background": "#00000000" - } -} +this.context.startAbility( +{ + action: "action.settings.app.info", + parameters: { "settingsParamBundleName": "your app bundlename" } +}) ``` -## How do I pass parameters for FA widgets? - -Applicable to: OpenHarmony SDK 3.2.5.5 +## How do I get UIAbilityContext within the @Component component in the stage model? -Use **featureAbility.getWant()** and **featureAbility.getContext()** to send data through **router** in the JSON file and use **featureAbility** to receive data in the JS file. +Applicable to: OpenHarmony 3.2 Beta5 (API version 9) -## How do I trigger router.disableAlertBeforeBackPage and router.enableAlertBeforeBackPage? +**Solution** -Applicable to: OpenHarmony SDK 3.2.5.5 +You can use **UIAbility.Context** to obtain the context. -The following conditions must be met: +**Example** -1. Before the redirection to the previous page, a confirm dialog box will be displayed. Note that **router.disableAlertBeforeBackPage** is used to disable the display of a confirm dialog box before returning to the previous page (default), and **router.enableAlertBeforeBackPage** is used to enable the display. +``` +import UIAbility from '@ohos.app.ability.UIAbility'; + +let UIAbilityContext = UIAbility.context; +let ApplicationContext = UIAbility.context.getApplicationContext(); +@Entry +@Component +struct AbilityContextTest { + // abilityContext + @State UIabilityInfo: string = 'Obtaining abilityInfo' + UIabilityContext: UIAbilityContext + + aboutToAppear() { + // Use getContext to obtain the context and convert it to abilityContext. + this.UIabilityContext = getContext(this) as UIAbilityContext + } -2. The system return key is used. + build() { + Row() { + Column({ space: 20 }) { + Text(this.abilityInfo) + .fontSize(20) + .onClick(()=>{ + this.UIabilityInfo = JSON.stringify(this.UIabilityContext.UIabilityInfo) + console.log(`ContextDemo abilityInfo= ${this.UIabilityInfo}`) + }) + } + .width('100%') + } + .height('100%') + } +} +``` diff --git a/en/application-dev/faqs/faqs-bundle-management.md b/en/application-dev/faqs/faqs-bundle-management.md new file mode 100644 index 0000000000000000000000000000000000000000..71b1e01ffcffea415266fb90213fc722e4f5b628 --- /dev/null +++ b/en/application-dev/faqs/faqs-bundle-management.md @@ -0,0 +1,126 @@ +# Bundle Management Development + +## How do I determine whether an application is a system application? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Use **bundleManager.getApplicationInfo** (available only for system applications) to obtain application information, and check the value of **systemApp** in the information. The application is a system application if the value is **true**. + +**Reference** + +[bundleManager](../reference/apis/js-apis-bundleManager.md) + +## How do I obtain the version code and version name of an application? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Use **bundleManager.getBundleInfoForSelf\(\)** to obtain the bundle information, which contains the version code (specified by **BundleInfo.versionCode**) and version name (specified by **BundleInfo.versionName**) . + +**Example** + +``` +import bundleManager from '@ohos.bundle.bundleManager'; +import hilog from '@ohos.hilog'; +let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT; +try { + bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => { + const versionCode = data.versionCode; + const versionName = data.versionName; + hilog.info(0x0000, 'testTag', `successfully. versionCode: ${versionCode}, versionName: ${versionName}`); + }).catch(err => { + hilog.error(0x0000, 'testTag', 'failed. Cause: %{public}s', err.message); + }); +} catch (err) { + hilog.error(0x0000, 'testTag', 'failed: %{public}s', err.message); +} +``` + +**Reference** + +[getBundleInfoForSelf](../reference/apis/js-apis-bundleManager.md#bundlemanagergetbundleinfoforself) + +## How do I obtain the bundle name of the current application? + +Applicable to: OpenHarmony 3.2 Beta5 (API version 9) + +**Solution** + +Obtain the bundle name from **UIAbilityContext.abilityInfo.bundleName**. + +**Example** + +``` +import common from '@ohos.app.ability.common'; +const context = getContext(this) as common.UIAbilityContext +console.log(`bundleName: ${context.abilityInfo.bundleName}`) +``` + +**Reference** + +[UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontext) and [AbilityInfo](../reference/apis/js-apis-bundleManager-abilityInfo.md#abilityinfo) + +## How do I obtain the application version number, version name, and screen resolution? + +Applicable to: OpenHarmony 3.2 Beta5 + +**Solution** + +1. Obtain the bundle information from the **@ohos.bundle.bundleManager** module. + + The bundle information contains the application version number and version name. + + ``` + import bundleManager from '@ohos.bundle.bundleManager'; + ... + bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION).then((bundleInfo)=>{ + let versionName = bundleInfo.versionName; // Application version name. + let versionNo = bundleInfo.versionCode; // Application version number. + }).catch((error)=>{ + console.error("get bundleInfo failed,error is "+error) + }) + ``` + +2. Obtain **screenDensity** from the **@ohos.app.ability.Configuration** module. **screenDensity** contains the screen resolution information. + + ``` + import common from '@ohos.app.ability.common'; + ... + let context = getContext(this) as common.UIAbilityContext; + let screenDensity = context.config.screenDensity; + ``` + + +## How do I obtain the source file path of the current application? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +- Method 1: Use the application context to obtain the source file path. + + ``` + this.uiAbilityContext.abilityInfo.applicationInfo.codePath + ``` + +- Method 2: Use **@ohos.bundle.bundleManager** to obtain the source file path. + + 1. Import the **@ohos.bundle.bundleManager** module and use **bundleManager.getBundleInfoForSelf\(\)** to obtain the bundle information. + 2. Obtain the source file path from **bundleInfo.appInfo.codePath**. + + ``` + import bundleManager from '@ohos.bundle.bundleManager'; + bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION).then((bundleInfo)=>{ + this.sourcePath = bundleInfo.appInfo.codePath; + }) + ``` + + +## Can I obtain the HAP information of other applications from the current application? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +According to the OpenHarmony security design specifications, the SDK does not provide APIs for third-party applications to obtain bundle information (including but not limited to the application name and version number) of other applications. diff --git a/en/application-dev/faqs/faqs-bundle.md b/en/application-dev/faqs/faqs-bundle.md deleted file mode 100644 index fda41c42bccc357d6b8800ce3f5401e1e2abbceb..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-bundle.md +++ /dev/null @@ -1,31 +0,0 @@ -# Bundle Management Development - -## How do I obtain the version code and version name of an application? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Use **bundle.getBundleInfo()** to obtain the bundle information, which contains the version code and version name. - -Reference: [Bundle](../reference/apis/js-apis-Bundle.md#bundlegetbundleinfo) - -## How do I obtain the bundle name of an application? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Obtain the bundle name through **context.abilityInfo.bundleName**. - -Reference: [AbilityInfo](../reference/apis/js-apis-bundle-AbilityInfo.md) - -## How do I obtain an application icon? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Use **bundle.getAbilityIcon** to obtain the application icon. To use this API, you must configure the permission **ohos.permission.GET_BUNDLE_INFO**. - -Reference: [Bundle](../reference/apis/js-apis-Bundle.md#bundlegetbundleinfo) - -## How do I determine whether an application is a system application? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Use **bundle.getApplicationInfo** to obtain the application information, and then check the value of **systemApp** in the information. The application is a system application if the value is **true**. diff --git a/en/application-dev/faqs/faqs-distributed-data-management.md b/en/application-dev/faqs/faqs-distributed-data-management.md new file mode 100644 index 0000000000000000000000000000000000000000..c44b7b254ae85280e00430621845dd82d7e2fca6 --- /dev/null +++ b/en/application-dev/faqs/faqs-distributed-data-management.md @@ -0,0 +1,101 @@ +# Data Management Development + + +## How do I encrypt an RDB store? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Solution** + +To encrypt an RDB store, set **encrypt** in **StoreConfig** to **true** when creating the RDB store. + +**Reference** + +[RDB Store](../reference/apis/js-apis-data-relationalStore.md#storeconfig) + +## What if I failed to clear a table in an RDB store using TRUNCATE TABLE? + +Applicable to: OpenHarmony SDK 3.2.9.2 (API version 9) + +**Symptom** + +An error is reported when the **TRUNCATE TABLE** statement is used to clear table data. + +**Solution** + +The RDB store uses SQLite and does not support the **TRUNCATE TABLE** statement. To clear a table in an RDB store, use the **DELETE** statement, for example, **DELETE FROM sqlite\_sequence WHERE name = 'table\_name'**. + + + +## What data types does an RDB store support? + +Applicable to: OpenHarmony SDK 3.0 or later, API version 9 stage model + +**Solution** + +An RDB store supports data of the number, string, and Boolean types. The number type supports data of the Double, Long, Float, Int, or Int64 type, with a maximum precision of 17 decimal digits. + +## How do I save pixel map data to a database? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +Pixel map data fails to be stored. + +**Solution** + +Convert the pixel map data into an **ArrayBuffer** and save the **ArrayBuffer** to your database. + +**Reference** + +[readPixelsToBuffer](../reference/apis/js-apis-image.md#readpixelstobuffer7-1) + +## How do I obtain RDB store files? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +The RDB store files are stored in **/data/app/el2/100/database/*Bundle_name*/entry/rdb/**. You can use the hdc command to copy the file from the directory and use a SQLite tool to open the file. + +Example: + +``` + hdc file recv /data/app/el2/100/database//entry/db/ ./ +``` + +## Do the OpenHarmony databases have a lock mechanism? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +The distributed data service (DDS), RDB store, and preferences provided OpenHarmony have a lock mechanism. You do not need to bother with the lock mechanism during the development. + +## What if I failed to use get() to obtain the data saved by @ohos.data.storage put()? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +After @ohos.data.storage **put()** is called to save data, **get()** is called to obtain the data. However, the data fails to be obtained. + +**Solution** + +The **put()** method provided by **@ohos.data.storage** saves data in the memory. When the application exits, the data in the memory will be cleared. If you want to persist the data, you need to call **flush()** or **flushSync()** after **put()**. After data is persisted, you can use **get()** to obtain the data after the application is restarted. + + +## What if a large text file fails to be saved in an RDB store? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +In API version 8, large text files cannot be saved in RDB stores. + +**Solution** + +In versions earlier than API version 9, the maximum length of a text file is 1024 bytes. If the text file exceeds 1024 bytes, it cannot be saved. + +The limit on the text file size has been removed since API9 version. diff --git a/en/application-dev/faqs/faqs-distributed-device-profile.md b/en/application-dev/faqs/faqs-distributed-device-profile.md new file mode 100644 index 0000000000000000000000000000000000000000..8473e3d4bfcb36c02d3260312cf5379cb436d8a6 --- /dev/null +++ b/en/application-dev/faqs/faqs-distributed-device-profile.md @@ -0,0 +1,9 @@ +# Distributed Device Development + +## How do I view the IMEI of an OpenHarmony device? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Obtain the device IMEI from the **HUKS\_TAG\_ATTESTATION\_ID\_IMEI** parameter of the **HuksTag** API. [Reference](../reference/apis/js-apis-huks.md) diff --git a/en/application-dev/faqs/faqs-file-management.md b/en/application-dev/faqs/faqs-file-management.md index 6214cbc6b61aadc0e7501fbf3166d050b46500cb..85763b7eb00f9b8805786e80c208ea4059e8bb0e 100644 --- a/en/application-dev/faqs/faqs-file-management.md +++ b/en/application-dev/faqs/faqs-file-management.md @@ -1,107 +1,21 @@ # File Management Development -## Does fileio.rmdir Delete Files Recursively? +## How do I obtain the path of system screenshots? -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -Yes. **fileio.rmdir** deletes files recursively. +**Solution** -## How Do I Create a File That Does Not Exist? +The screenshots are stored in **/storage/media/100/local/files/Pictures/Screenshots/**. -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 +## How do I change the permissions on a directory to read/write on a device? -You can use **fileio.open(filePath, 0o100, 0o666)**. The second parameter **0o100** means to create a file if it does not exist. The third parameter **mode** must also be specified. +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) -## What If "call fail callback fail, code: 202, data: json arguments illegal" Is Displayed? +**Symptom** -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 +When the hdc command is used to send a file to a device, "permission denied" is displayed. -When the **fileio** module is used to copy files, the file path cannot start with "file:///". +**Solution** -## How Do I Read Files Outside the App Sandbox? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -If the input parameter of the **fileio** API is **path**, only the sandbox directory of the current app obtained from the context can be accessed. To access data in other directories such as the user data, images, and videos, open the file as the data owner and operate with the file descriptor (FD) returned. - -For example, to read or write a file in Media Library, perform the following steps: - -1. Use **getFileAssets()** to obtain the **fileAsset** object. - -2. Use **fileAsset.open()** to obtain the FD. - -3. Use the obtained FD as the **fileIo** API parameter to read and write the file. - -## What If the File Contains Garbled Characters? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Read the file content from the buffer, and decode the file content using **util.TextDecoder**. - -Example: - -``` -import util from '@ohos.util' -async function readFile(path) { - let stream = fileio.createStreamSync(path, "r+"); - let readOut = await stream.read(new ArrayBuffer(4096)); - let textDecoder = new util.TextDecoder("utf-8", { ignoreBOM: true }); - let buffer = new Uint8Array(readOut.buffer) - let readString = textDecoder.decode(buffer, { stream: false }); - console.log ("[Demo] File content read: "+ readString); -} -``` - -## What Should I Do If There Is No Return Value or Error Captured After getAlbums Is Called? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -The **ohos.permission.READ_MEDIA** is required for using **getAlbums()**. In addition, this permission needs user authorization. For details, see [OpenHarmony Permission List](../security/permission-list.md). - -1. Configure the required permission in the **module.json5** file. - - ``` - "requestPermissions": [ - { - "name": "ohos.permission.READ_MEDIA" - } - ] - ``` - -2. Add the code for user authorization before the **MainAbility.ts -> onWindowStageCreate** page is loaded. - - ``` - import abilityAccessCtrl from '@ohos.abilityAccessCtrl.d.ts'; - - private requestPermissions() { - let permissionList: Array = [ - "ohos.permission.READ_MEDIA" - ]; - let atManager = abilityAccessCtrl.createAtManager(); - atManager.requestPermissionsFromUser(this.context, permissionList) - .then(data => { - console.info(`request permission data result = ${data.authResults}`) - }) - .catch(err => { - console.error(`fail to request permission error:${err}`) - }) - } - ``` - -## What Do I Do If the App Crashes When FetchFileResult() Is Called Multiple Times? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Each time after the **FetchFileResult** object is called, call **FetchFileResult.close()** to release and invalidate the **FetchFileResult** object . - -## What If An Error Is Reported by IDE When mediaLibrary.getMediaLibrary() Is Called in the Stage Model? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -In the stage model, use **mediaLibrary.getMediaLibrary(context: Context)** to obtain the media library instance. - -## How Do I Sort the Data Returned by mediaLibrary.getFileAssets()? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Use the **order** attribute in **[MediaFetchOptions](../reference/apis/js-apis-medialibrary.md#mediafetchoptions7)** to sort the data returned. +Run the **hdc shell mount -o remount,rw /** command to grant the read/write permissions. diff --git a/en/application-dev/faqs/faqs-graphics.md b/en/application-dev/faqs/faqs-graphics.md index 7eeba0644721dbf77174680f3c6c6d0ac0db05cf..9469a35736ef859342d2c24bdcb9780e94445bf8 100644 --- a/en/application-dev/faqs/faqs-graphics.md +++ b/en/application-dev/faqs/faqs-graphics.md @@ -1,90 +1,92 @@ -# Graphics and Image Development +# Graphics Development -## Why do the isStatusBarLightIcon and isNavigationBarLightIcon attributes not take effect when window.setSystemBarProperties() is called? +## How do I obtain the DPI of a device? -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +Applicable to: OpenHarmony 3.2 Beta5 (API version 9, stage model) -In effect, the **isStatusBarLightIcon** and **isNavigationBarLightIcon** attributes turn the font white when set to **true**. If **statusBarContentColor** is also set in **window.setSystemBarProperties()**, the **isStatusBarLightIcon** attribute does not take effect. Similarly, if **navigationBarContentColor** is set, the **isNavigationBarLightIcon** attribute does not take effect. +**Solution** -## How do I set the style of the system bar? +Import the **@ohos.display** module and call the **getDefaultDisplaySync\(\)** API. -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +**Example** -Import the **\@ohos.window** module, and call **window.setSystemBarProperties()**. +``` +import display from '@ohos.display'; +let displayClass = null; +try { + displayClass = display.getDefaultDisplaySync(); + console.info('Test densityDPI:' + JSON.stringify(displayClass.densityDPI)); +} catch (exception) { + console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception)); +} +``` ## How do I hide the status bar to get the immersive effect? -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 - -1. Use the **onWindowStageCreate** to obtain a **windowClass** object. - - ```ts - onWindowStageCreate(windowStage) { - // When the main window is created, set the main page for this ability. - console.log("[Demo] EntryAbility onWindowStageCreate") - windowStage.getMainWindow((err, data) => { - if (err.code) { - console.error('Failed to obtain the main window.') - return; - } - // Obtain a windowClass object. - globalThis.windowClass = data; - }) - } - ``` - -2. Enable the full-screen mode for the window and hide the status bar. - - ```ts - globalThis.windowClass.setFullScreen(isFullScreen, (err, data) => { - if (err.code) { - console.error('Failed to enable the full-screen mode. Cause:' + JSON.stringify(err)); - return; - } - console.info('Succeeded in enabling the full-screen mode. Data: ' + JSON.stringify(data)); - }); - ``` +Applicable to: OpenHarmony 3.2 Beta5 (API version 9, stage model) + +**Solution** + +1. Use **onWindowStageCreate** to obtain a **windowClass** object. + + ``` + onWindowStageCreate(windowStage) { + // When the main window is created, set the main page for this ability. + console.log("[Demo] MainAbility onWindowStageCreate") + windowStage.getMainWindow((err, data) => { + if (err.code) { + console.error('Failed to obtain the main window.') + return; + } + // Obtain a windowClass object. + globalThis.windowClass = data; + }) + } + ``` + +2. Enable the full-screen mode for the window and hide the status bar. + + ``` + globalThis.windowClass.setFullScreen(isFullScreen, (err, data) => { + if (err.code) { + console.error('Failed to enable the full-screen mode. Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in enabling the full-screen mode. Data: ' + JSON.stringify(data)); + }); + ``` + ## How do I obtain the window width and height? -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 +Applicable to: OpenHarmony SDK 3.2 Beta5 (API version 9, stage model) -Use **window.getProperties()** to obtain the window properties. The **windowRect** field in the properties specifies the window width and height. +**Solution** -Example: +Import the **@ohos.window** module, obtain a **Window** object, and use **getWindowProperties\(\)** of the object to obtain the window properties. The **windowRect** field in the properties specifies the window width and height. +**Example** -```ts -let promise = windowClass.getProperties(); -promise.then((data)=> { - console.info('Succeeded in obtaining the window properties. Data: ' + JSON.stringify(data.windowRect)); -}).catch((err)=>{ - console.error('Failed to obtain the window properties. Cause: ' + JSON.stringify(err)); -}); ``` - -## How do I set the color of the system bar? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Refer to the following code: - - -```ts -window.getTopWindow(globalThis.mainContext).then(win => { - var systemBarProperties = { - statusBarColor: '#19B6FF', // Set the background color of the status bar. - navigationBarColor: '#19B6FF', // Set the background color of the navigation bar. - isStatusBarLightIcon: false, // Set the icon on the status bar not to be highlighted. - isNavigationBarLightIcon: true, // Set the icon on the navigation bar to be highlighted. - statusBarContentColor: '#0D0500', // Set the text color of the status bar. - navigationBarContentColor: '#FFA500' // Set the text color of the navigation bar. - }; - win.setSystemBarProperties(systemBarProperties).catch(err => { - INDEX_LOGGER.info(`set System Bar Properties failed:${err}`) - }) -}) -.catch(err => { - INDEX_LOGGER.info(`get top window failed:${err}`) -}) +import window from '@ohos.window'; +let windowClass = null; +try { + let promise = window.getLastWindow(this.context); + promise.then((data)=> { + // Obtain a Window object. + windowClass = data; + try { + // Obtain the window properties. + let properties = windowClass.getWindowProperties(); + let rect = properties.windowRect; + // rect.width: window width; rect.height: window height. + } catch (exception) { + console.error('Failed to obtain the window properties. Cause: ' + JSON.stringify(exception)); + } + console.info('Succeeded in obtaining the top window. Data: ' + JSON.stringify(data)); + }).catch((err)=>{ + console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(err)); + });} catch (exception) { + console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(exception)); +} ``` diff --git a/en/application-dev/faqs/faqs-ide.md b/en/application-dev/faqs/faqs-ide.md deleted file mode 100644 index a9bbf987a8f098a5016278609cb7d9ebfdd632b8..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-ide.md +++ /dev/null @@ -1,79 +0,0 @@ -# IDE Usage - -## What should I do if the error message "npm ERR! code SELF_SIGNED_CERT_IN_CHAIN" is displayed? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -1. Run **npm config set strict-ssl=false** on the DevEco Studio terminal. - -2. Run **npm install** on the DevEco Studio terminal. - -## After manual updating of a DevEco Studio SDK, the error message "Cannot find module 'xxx\ets\x.x.x.x\build-tools\ArkTS-loader\node_modules\webpack\bin\webpack.js'" is displayed during HAP building. What should I do? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -1. Run **npm install** in the **ets\x.x.x.x\build-tools\ets-loader** directory of the SDK. - -2. Run **npm install** in the **js\x.x.x.x\build-tools\ace-loader** directory of the SDK. Perform HAP building again. - -## How do I pack a HAP file through the command line? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Method 1: Run **hvigor assembleHap**. - -Method 2: In **scripts** of the project **package.json** file, define the build task script and run **npm buildOhosHaps**. The **buildOhosHaps** field can be customized. - - -``` -"scripts": { - "buildOhosHaps": "hvigor assembleHap" -}, -``` - -## How do I select API version 9 when creating a project in DevEco Studio? - -Applicable to: DevEco Studio 3.0 Beta4 3.0.0.993(B06) - -When creating a project in DevEco Studio, make sure you are on the **OpenHarmony** tab page. - -## What should I do if no callback is received and no error code is returned for downloads? - -Applicable to: all versions - -1. Re-install hdc_std and set up the device connection again. -2. Run **hdc_std shell hilog -Q pidoff** to disable log log flow control. - -## What should I do if the "error: unknow option. usage: aa start \" message is displayed after I click Run in DevEco Studio? - -Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 - -This issue occurs when the parameter in the **aa** command is invalid and therefore the target application fails to be opened. - -To fix this issue, use either of the following methods: - -1. Make sure the SDK version and the OS version are the same. - -2. Touch the application icon on the device to manually open the application. - -## What should I do if "The hdc_std version of the SDK does not match the hdcd version of the device." message is displayed when I run an application in DevEco Studio? - -Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 - -This issue occurs when the hdc and hdcd versions do not match. Update Dev Eco Studio to 3.0.1.993 or later. - -After the update, Dev Eco Studio will still indicate the version mismatch, but will not block the running. - -## How do I add a custom .d.ts file to the OpenHarmony SDK? - -Applicable to: OpenHarmony SDK 3.1.7.7, FA model of API version 8 - -Name the .d.ts file **@ohos.xxxx.d.ts**, save it to the SDK path, and restart Dev Eco Studio. - -A code notification is displayed when the file is imported. - -## How do I switch to the full SDK? - -Applicable to: OpenHarmony SDK 3.2.7.5 - -Follow the instructions in [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md). diff --git a/en/application-dev/faqs/faqs-language.md b/en/application-dev/faqs/faqs-language.md deleted file mode 100644 index 686283d7f8b41fa7abc4f4c78f74eed1240014d8..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-language.md +++ /dev/null @@ -1,288 +0,0 @@ -# Programming Languages - -## What are the restrictions on using generator functions in TypeScript? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -Below are the restrictions on using generator functions in TypeScript: - -- Expressions can be used only in character strings (in the ${expression} format), **if** conditions, **ForEach** parameters, and component parameters. - -- No expressions should cause any application state variables (including **@State**, **@Link**, and **@Prop**) to change. Otherwise, undefined and potentially unstable framework behavior may occur. - -- The generator function cannot contain local variables. - -None of the above restrictions apply to anonymous function implementations of event handlers (such as **onClick**). - -Negative example: - -``` -build() { - let a: number = 1 // invalid: variable declaration not allowed - Column() { - Text('Hello ${this.myName.toUpperCase()}') // ok. - ForEach(this.arr.reverse(), ..., ...) // invalid: Array.reverse modifies the @State array variable in place - } - buildSpecial() // invalid: no function calls - Text(this.calcTextValue()) // this function call is ok. -} -``` - -## How do I dynamically replace the %s placeholder in a resource file? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -In an application, you can replace the %s placeholder by using the second parameter in **$r('app.string.xx')**, which is used to reference application resources. - -Example: - -``` -build() { - //do something - // The second parameter indicates the referenced string resource, which can be used to replace the %s placeholder. - Text($r('app.string.entry_desc','aaa')) - .fontSize(100) - .fontColor(Color.Black) - //do something -} -``` - -## How do I read an XML file in Resource and convert data in it to the string type? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -1. Obtain Uint8Array data by calling the **RawFile** API of **resourceManager**. - -2. Convert the Uint8Array data to strings by calling the **String.fromCharCode** API. - -Reference: [Resource Manager](../reference/apis/js-apis-resource-manager.md) - -Example: - - -``` -resourceManager.getRawFile(path, (error, value) => { - if (error != null) { - console.log("error is " + error); - } else { - let rawFile = value; - let xml = String.fromCharCode.apply(null, rawFile) - } -}); -``` - -## How do I convert a Resource object to the string type? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Use the **resourceManager.getString()** API of the **@ohos.resourceManager** module. - -Reference: [Resource Manager](../reference/apis/js-apis-resource-manager.md#getstring) - -## What should I do if the global static variables of a class do not work? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Objects imported to abilities and pages are packaged into two different closures, that is, two global objects. In this case, a static variable referenced by the abilities is not the same object as that referenced by the pages. Therefore, global variables cannot be defined by defining static variables in the class. You are advised to use AppStorage to manage global variables. - -## How do I obtain resources in the stage model? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -The stage model allows an application to obtain a **ResourceManager** object based on **context** and call its resource management APIs without first importing the required bundle. This method, however, is not applicable to the FA model. - -Example: - - -``` -const context = getContext(this) as any -context - .resourceManager - .getString($r('app.string.entry_desc').id) - .then(value => { - this.message = value.toString() -}) -``` - -## How do I obtain data through an API before page loading? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -In the **aboutToAppear** function, use an asynchronous API to obtain page data and **@State** to decorate related variables. After the data is obtained, the page is automatically refreshed based on the variables. - - -``` -@Entry -@Component -struct Test6Page { - // After the data is obtained, the page is automatically refreshed. - @State message: string = 'loading.....' - aboutToAppear(){ - // Simulate an asynchronous API to obtain data. - setTimeout(()=>{ - this.message = 'new msg' - },3000) - } - build() { - Row() { - Column() { - Text(this.message) - .fontSize(50) - .fontWeight(FontWeight.Bold) - } - .width('100%') - } - .height('100%') - } -} -``` - -## Do the worker thread and the main thread run in the same global context? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -No. The worker thread and the main thread are not in the same global context. They interact with each other in data communication mode. - -## Which API is used for URL encoding in OpenHarmony? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -The global function **encodeURI** is used for URI encoding, and **decodeURI** is used for URI decoding. For example, a space character is encoded as %20. - -## Does OpenHarmony provide any API for parsing XML files? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Yes. The **convert** API of the **convertxml** module can be used to convert XML text into JavaScript objects. - -Reference: [@ohos.convertxml](../reference/apis/js-apis-convertxml.md) - -## How do I configure application icons to be used across devices? - -Applicable to: OpenHarmony SDK 3.0, stage model of API version 9 - -Use resource qualifiers to configure application icons to be used across devices. - -## Can placeholders be configured in the string.json file of the stage model? - -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 - -The **string.json** file does not support placeholders. As an alternative, you can define variables on the target page and combine these variables and **Resource** objects. - -## Is there any difference between the OpenHarmony API systemTime.getCurrentTime() and the JS API new Date().getTime() API? - -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 - -Similar to **new Date().getTime()**, **systemTime.getCurrentTime(false)** returns the number of milliseconds that have elapsed since the Unix epoch. **systemTime.getCurrentTime(true)** returns the number of nanoseconds that have elapsed since the Unix epoch. The system time is used in both APIs. - -## How do I define @BuilderParam decorated attributes based on the value assigned to them? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -If no parameter is passed when assigning a value to the **@BuilderParam** decorated attribute (for example, **content: this.specificParam**), define the type of the attribute as a function without a return value (for example, **@BuilderParam content: () => voi**). If any parameter is passed when assigning a value to the **@BuilderParam** decorated attribute (for example, **callContent: this.specificParam1("111")**), define the type of the attribute as **any** (for example, **@BuilderParam callContent: any**). - -## How does ArkTS convert a string into a byte array? - -Applicable to: all versions - -Refer to the following code: - - -``` -function stringToByte(str) { - var bytes = new Array(); - var len,c; - len = str.length; - for(var i = 0;i= 0x010000 && c<= 0x10FFFF) { - bytes.push(((c>>18) & 0x07) | 0xf0); - bytes.push(((c>>12) & 0x3F) | 0x80); - bytes.push(((c>>6) & 0x3f) | 0x80); - bytes.push((c & 0x3F) | 0x80); - } else if(c >= 0x000800 && c<= 0x00FFF){ - bytes.push(((c>>12) & 0x07) | 0xf0); - bytes.push(((c>>6) & 0x3F) | 0x80); - bytes.push((c & 0x3F) | 0x80); - } else if(c >= 0x000800 && c<= 0x0007FF) { - bytes.push(((c>>6) & 0x3F) | 0x80); - bytes.push((c & 0x3F) | 0x80); - } else { - bytes.push(c & 0xFF) - } - } - return bytes; -} -``` - -## What do I do if the "Too many wokers, the number of worker exceeds the maximum" message is displayed during worker creation? - -Applicable to: OpenHarmony SDK 3.2.6.5 - -An application allows for a maximum of seven workers. Therefore, use the **termiate** API to release workers when they are not needed. - -Reference: [@ohos.worker](../reference/apis/js-apis-worker.md#terminate) - -## What is the recommended multithreading solution on OpenHarmony? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -OpenHarmony recommends that worker threads be used for multithreading. - -Reference: [@ohos.worker](../reference/apis/js-apis-worker.md) - -## What is the difference between a @Builder decorated method and other methods? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -If the **@Builder** decorated method uses a custom component, this component is re-created each time the method is called. - -## Why is the callback registered through @Watch not triggered when the object attributes of an array change? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -As with **@State**, the callback registered through **@Watch** can be used to listen for only one layer of data changes. If the object attributes of the array changes at the inner layer, the callback will not be triggered. - -## How do I listen for in-depth changes of @State decorated variables? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -To listen for in-depth changes of **@State** decorated variables, you can use **@Observed** and **@ObjectLink** decorators. - -## How do I implement character string encoding and decoding? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -You can use **TextEncoder** and **TextDecoder** provided by the **util** module. - -Reference: [TextEncoder](../reference/apis/js-apis-util.md#textencoder) and [TextDecoder](../reference/apis/js-apis-util.md#textdecoder) - -## How do i import and export namespaces? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -- Exporting namespaces - - ``` - namespace Util{ - export function getTime(){ - return Date.now() - } - } - export default Util - ``` - -- Importing namespaces - - ``` - import Util from './util' - Util.getTime() - ``` - -## Can relational database operations be performed in the worker thread? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -No. Relational database operations cannot be performed in the worker thread. - - \ No newline at end of file diff --git a/en/application-dev/faqs/faqs-media.md b/en/application-dev/faqs/faqs-media.md deleted file mode 100644 index 0e88cf4e94aafa20e47a6ebd8fe3688d26a5e52a..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-media.md +++ /dev/null @@ -1,132 +0,0 @@ -# Media Development - -## How do I set a front camera? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -1. Set the camera position to **camera.CameraPosition.CAMERA_POSITION_FRONT**. - -2. Create a **CameraInput** instance based on the camera position and type. - -Reference: [Camera Management](../reference/apis/js-apis-camera.md) - -Example: - -``` -// The rear camera is set by default. You can use **isFrontCamera** to switch to the rear camera. -let cameraId -let cameraInput -for(let cameraIndex = 0; cameraIndex < this.cameraArray.length; cameraIndex++) { - let faceType = this.cameraArray[cameraIndex].cameraPosition - switch(faceType) { - case camera.CameraPosition.CAMERA_POSITION_FRONT: // Front camera - if(this.isFrontCamera){ - cameraId = this.cameraArray[cameraIndex].cameraId - } - break - case camera.CameraPosition.CAMERA_POSITION_BACK: // Rear camera - if(!this.isFrontCamera){ - cameraId = this.cameraArray[cameraIndex].cameraId - } - break - case camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED: - default: - break - } -} -cameraInput = await this.cameraManager.createCameraInput(cameraId) -``` - -## How do I crop an image? - -Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 - -1. Create an **ImageSource** instance based on the input URI. - - ``` - let path = this.context.getApplicationContext().fileDirs + "test.jpg"; - const imageSourceApi = image.createImageSource(path); - ``` - -2. Set decoding parameters and decode the image to obtain a **PixelMap** object. Image processing is supported during decoding. - - Set **desiredSize** to specify the target size after scaling. If the values are all set to **0**, scaling will not be performed. - - Set **desiredRegion** to specify the target rectangular area after cropping. If the values are all set to **0**, cropping will not be performed. - - Set **rotateDegrees** to specify the rotation angle. The image will be rotated clockwise at the center. - - ``` - const decodingOptions = { - desiredSize: { - height:0, - width:0 - }, - // Crop a rectangular area. - desiredRegion: { - size: { - height:100, - width:100 - }, - x:0, - y:0 - }, - // Rotate the image by 90 degrees. - rotate:90 - } - imageSourceApi.createPixelMap(decodingOptions).then(pixelMap => { - this.handlePixelMap(pixelMap) - }) - ``` - -3. Process the obtained **PixelMap** object. For example, render and display the image. - -## How do I apply for the media read/write permission on a device? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -1. Configure the permissions **ohos.permission.READ_MEDIA** and **ohos.permission.WRITE_MEDIA** in the **module.json5** file. - Example: - - - ``` - { - "module" : { - "requestPermissions":[ - { - "name" : "ohos.permission.READ_MEDIA", - "reason": "$string:reason" - }, - { - "name" : "ohos.permission.WRITE_MEDIA", - "reason": "$string:reason" - } - ] - } - } - ``` - -2. Call **requestPermissionsFromUser** to request the permissions from end users in the form of a dialog box. This operation is required because the grant mode of both permissions is **user_grant**. - - ``` - import abilityAccessCtrl from '@ohos.abilityAccessCtrl.d.ts'; - - let permissions: Array = ['ohos.permission.READ_MEDIA','ohos.permission.WRITE_MEDIA'] - let atManager = abilityAccessCtrl.createAtManager(); - // context is the ability-level context of the initiator UIAbility. - atManager.requestPermissionsFromUser(context, permissions).then((data) => { - console.log("Succeed to request permission from user with data: " + JSON.stringify(data)) - }).catch((error) => { - console.log("Failed to request permission from user with error: " + JSON.stringify(error)) - }) - ``` - -## Why can't I play MP4 videos? - -Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 - -Currently, the system does not support the playback of MP4 videos in H.265 format. - - -## Why can't I play a new video or even encounters a crash after creating more than 10 videos? - -Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 - -A maximum of 13 media player instances can be created. diff --git a/en/application-dev/faqs/faqs-multimedia.md b/en/application-dev/faqs/faqs-multimedia.md new file mode 100644 index 0000000000000000000000000000000000000000..080860a9a5ca913d1d40d9de049f9220a66118da --- /dev/null +++ b/en/application-dev/faqs/faqs-multimedia.md @@ -0,0 +1,135 @@ +# Multimedia Development + +## How do I obtain the frame data of a camera when using the XComponent to display the preview output stream of the camera? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Symptom** + +Currently, the API does not support real-time preview of the camera frame data. To obtain the frame data, you must bind an action, for example, photographing. + +**Solution** + +Create a dual-channel preview to obtain the frame data. + +1. Use the XComponent to create a preview stream. + + ``` + // Obtain a PreviewOutput instance. + const surfaceId = globalThis.mxXComponentController.getXComponentSurfaceld(); + this.mPreviewOutput = await Camera.createPreviewOutput(surfaceld) ; + ``` + +2. Use imageReceiver to listen for image information. + + ``` + // Add dual-channel preview. + const fullWidth = this.mFullScreenSize.width; + const fullHeight = this.mFullScreenSize.height; + const imageReceiver = await image.createImageReceiver(fullwidth, fullHeight, + formatImage, capacityImage) ; + const photoSurfaceId = await imageReceiver.getReceivingSurfaceld(); + this.mPreviewOutputDouble = await Camera.createPreviewOutput ( photoSurfaceld) + ``` + + +## How do I obtain the preview image of the front camera? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Solution** + +1. Use the **@ohos.multimedia.camera** module to obtain the physical camera information. + + ``` + let cameraManager = await camera.getCameraManager(context); + let camerasInfo = await cameraManager.getSupportedCameras(); + let cameraDevice = this.camerasInfo[0]; + ``` + +2. Create and start the input stream channel of the physical camera. + + ``` + let cameraInput = await cameraManager.createCameraInput(cameraDevice); + await this.cameraInput.open(); + ``` + +3. Obtain the output formats supported by the camera, and create a preview output channel based on the surface ID provided by the XComponent. + + ``` + let outputCapability = await this.cameraManager.getSupportedOutputCapability(cameraDevice); + let previewProfile = this.outputCapability.previewProfiles[0]; + let previewOutput = await cameraManager.createPreviewOutput(previewProfile, previewId); + ``` + +4. Create a camera session, add the camera input stream and preview output stream to the session, and start the session. The preview image is displayed on the XComponent. + + ``` + let captureSession = await cameraManager.createCaptureSession(); + await captureSession.beginConfig(); + await captureSession.addInput(cameraInput); + await captureSession.addOutput(previewOutput); + await this.captureSession.commitConfig() + await this.captureSession.start(); + ``` + + +## How do I set the camera focal length? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Solution** + +1. Check whether the camera is a front camera. A front camera does not support focal length setting. +2. Use **captureSession.getZoomRatioRange\(\)** to obtain the focal length range supported by the device. +3. Check whether the target focal length is within the range obtained. If yes, call **captureSession.setZoomRatio\(\)** to set the focal length. + +## How do I play music in the background? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Symptom** + +Music cannot be played in the background. + +**Solution** + +**AVSession** controls media playback. When a third-party application switches to the background or encounters a screen lock event, media playback is forcibly paused and the application is unaware of the pause. To enable the application to continue the playback in the background, request a continuous task and access the AVSession capability, which allows Control Panel to control the playback behavior of third-party applications. + +**Reference** + +[Continuous Task Development](../task-management/continuous-task-dev-guide.md) + +[AVSession Development](../media/using-avsession-developer.md) + + +## What should I do when multiple video components cannot be used for playback? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Symptom** + +A large number of video components are created. They cannot play media normally or even crash. + +**Solution** + +A maximum of 13 media player instances can be created. + + +## How do I invoke the image library directly? + +Applicable to: OpenHarmony 3.2 (API version 9, stage model) + +**Solution** + +``` +let want = { + bundleName: 'com.ohos.photos', + abilityName: 'com.ohos.photos.MainAbility', + parameters: { + uri: 'detail' + } +}; +let context = getContext(this) as common.UIAbilityContext; +context.startAbility(want); +``` diff --git a/en/application-dev/faqs/faqs-native.md b/en/application-dev/faqs/faqs-native.md deleted file mode 100644 index ef5700bb0ec1e3c903fd758d644779856f0ce681..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-native.md +++ /dev/null @@ -1,79 +0,0 @@ -# Native API Usage - -## Is there a native API that provides functions similar to Canvas? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -Yes. The native API **Drawing** provides similar functions. It can be used for 2D drawing. - -## When a native HAP is running, the error message "Obj is not a valid object" is displayed for the imported namespace. What should I do? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -Check the **abiFilters** parameter value in the **build-profile.json5** file in the root directory of the module (not the root directory of the project). If the device is 32-bit, the value must be **armeabi-v7a**. If the device is 64-bit, the value must be **arm64-v8a**. - -## What should I do when the error message "install parse profile prop check error" is displayed during the running of a native HAP? - -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 - -Check the **abiFilters** parameter value in the **build-profile.json5** file in the root directory of the module (not the root directory of the project). If the device is 32-bit, the value must be **armeabi-v7a**. If the device is 64-bit, the value must be **arm64-v8a**. - -## What should I do when the error message "undefined symbol: OH_LOG_Print" is displayed during log printing by **OH_LOG_Print**? - -Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 - -Modify the **CMakeLists.txt** file by adding **libhilog_ndk.z.so** to the end of **target_link_libraries**. - -## How do I obtain the value of version in the package.json file of a module? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -1. In the script file **hvigorfile.js** of Hvigor, use **subModule.getPackageJsonPath** to obtain the location of the **package.json** file in the module. - -2. Use Node.js to read the **version** field in the **package.json** file and write the value to the **buildOption.cppFlags** field in the **build-profile.json5** file. - -Example - - -``` -// Module-level hvigorfile.js -const subModule = require('@ohos/hvigor')(__filename) - -const fs = require("fs-extra") -const path = require("path") - -const packageJsonPath = subModule.getPackageJsonPath() -const buildProfilePath = path.resolve(packageJsonPath, '../build-profile.json5') -const packageJsonData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) -let buildProfileData = fs.readFileSync(buildProfilePath, 'utf8') -buildProfileData = buildProfileData.replace(/\"cppFlags\"\:(.*)\,/, `"cppFlags": "-D NWEBEX_VERSION=${packageJsonData.version}",`) -fs.writeFileSync(buildProfilePath, buildProfileData, 'utf8') - -const ohosPlugin = require('@ohos/hvigor-ohos-plugin').hapTasks(subModule) // The plug-in executes the C++ build task and reads the build-profile.json5 file. - -module.exports = { - ohos: ohosPlugin -} -``` - - -``` -// Read the hello.cpp file. -#define _NWEBEX_VERSION(v) #v -#define _NWEBEX_VER2STR(v) _NWEBEX_VERSION(v) - -static napi_value Add(napi_env env, napi_callback_info info) -{ - - napi_value fixed_version_value = nullptr; - napi_create_string_utf8(env, _NWEBEX_VER2STR(NWEBEX_VERSION), NAPI_AUTO_LENGTH, &fixed_version_value); - - return fixed_version_value; -} -``` - -## How do I traverse files in rawfile? - -Applicable to: OpenHarmony SDK 3.2 or later, stage model of API version 9 - -Use the native API **OH_ResourceManager_OpenRawDir()** to obtain the root directory of **rawfile** and traverse the root directory. diff --git a/en/application-dev/faqs/faqs-security.md b/en/application-dev/faqs/faqs-security.md new file mode 100644 index 0000000000000000000000000000000000000000..691739a0c288a3315e27e1f54700ba4e2637ddb3 --- /dev/null +++ b/en/application-dev/faqs/faqs-security.md @@ -0,0 +1,41 @@ +# Basic Security Capability Development + +## What is the maximum number of bytes that can be encrypted at a time in AES GCM mode in HUKS? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Solution** + +In HUKS, a maximum of 64 bytes can be encrypted at a time in AES GCM mode. + +**Example** + +``` +/* Encrypt the key. */ +await huks.init(srcKeyAlias, encryptOptions).then((data) => { + console.info(`test init data: ${JSON.stringify(data)}`); + handle = data.handle; +}).catch((err) => { + console.info('test init err information: ' + JSON.stringify(err)); +}); +encryptOptions.inData = aesCipherStringToUint8Array(cipherInData.slice (0,64)); // Take 64 bytes. +await huks.update(handle, encryptOptions).then(async (data) => { + console.info(`test update data ${JSON.stringify(data)}`); + encryptUpdateResult = Array.from(data.outData); +}).catch((err) => { + console.info('test update err information: ' + err); +}); +encryptOptions.inData = aesCipherStringToUint8Array(cipherInData.slice (64,80)); // Remaining data +``` + +## What if garbled characters are returned by **digest()** of **Md** in Crypto framework? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Symptom** + +In the CryptoFramework, garbled characters are returned by **digest()** of **Md**. + +**Solution** + +The DataBlob returned by **digest()** is of the Uint8Array type and needs to be converted into a hexadecimal string before being printed. You can use the online MD5 encryption tool to verify the result. diff --git a/en/application-dev/faqs/faqs-sensor.md b/en/application-dev/faqs/faqs-sensor.md new file mode 100644 index 0000000000000000000000000000000000000000..3932b223fb5c6af755c9eae019851e37edfa6ef4 --- /dev/null +++ b/en/application-dev/faqs/faqs-sensor.md @@ -0,0 +1,7 @@ +# Pan-Sensor Development + +## Are the APIs used for obtaining PPG and ECG sensor data open to individual developers? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +Data collected by the PPG and ECG sensors of wearable devices is personal privacy data. Therefore, relative APIs are not open to individual developers. diff --git a/en/application-dev/faqs/faqs-third-fourth-party-library.md b/en/application-dev/faqs/faqs-third-fourth-party-library.md new file mode 100644 index 0000000000000000000000000000000000000000..045a3f5efe77b0ad16b64960bbf015b62b07d46f --- /dev/null +++ b/en/application-dev/faqs/faqs-third-fourth-party-library.md @@ -0,0 +1,69 @@ +# Usage of Third- and Fourth-Party Libraries + +## How do I obtain available third-party libraries? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +The three-party and four-party libraries that can be obtained through ohpm are summarized in the [OpenHarmony-TPC/tpc_resource repository](https://gitee.com/openharmony-tpc/tpc_resource). You can access this repository, and find the desired component based on the directory index. + +## Which third-party libraries are related to network requests? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +The following third-party libraries are related to network requests: [Axios](https://gitee.com/openharmony-sig/axios), httpclient, and okdownload. For details, see the [OpenHarmony-TPC/tpc_resource repository](https://gitee.com/openharmony-tpc/tpc_resource). + +## How do I use ohpm to import third- and fourth-party libraries? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Solution** + +- Method 1: + 1. Open the **Terminal** window and run the following command to go to the **entry** directory: + + ``` + cd entry + ``` + + 2. Run the following command to install a third-party library, for example, **dayjs**: + + ``` + ohpm install dayjs + ``` + + 3. Add the following statement in the .js file to import the third-party library: + + ``` + import dayjs from 'dayjs'; + ``` + + +- Method 2: + 1. Enter the **entry** directory of the project and open the **oh-package.json5** file. + 2. Write the third-party library to be installed (for example, **dayjs**) in the **oh-package.json5** file. + + ``` + { + "dependencies": { + "dayjs": "^1.10.4", + } + } + ``` + + 3. Open the **Terminal** window and run the following command to go to the **entry** directory: + + ``` + cd entry + ``` + + 4. Run the following command to install the third-party library: + + ``` + ohpm install + ``` + + 5. Add the following statement in the .js file to import the third-party library: + + ``` + import dayjs from 'dayjs'; + ``` diff --git a/en/application-dev/faqs/faqs-third-party-library.md b/en/application-dev/faqs/faqs-third-party-library.md deleted file mode 100644 index 898055cd200805d8df549b33bb2c5f3b4b05bca6..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-third-party-library.md +++ /dev/null @@ -1,74 +0,0 @@ -# Usage of Third- and Fourth-Party Libraries - -## What does the following error message mean: "Stage model module... does not support including OpenHarmony npm packages or modules in FA model. OpenHarmony build tasks will not be executed, and OpenHarmony resources will not be packed." - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -The third- and fourth-party libraries are not yet compatible with the stage model of API version 9 and cannot be used. - -## Can I transfer project-level dependencies? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -For example, if project A depends on project B and project B depends on project C, can project A directly use the APIs provided by project C? - -No. Project A cannot directly use the APIs provided by project C. The project packing tool NPM does not support dependency transfer. To use the APIs provided by project C, you can add the dependency of project C to project A. - -## How do I obtain available third-party libraries? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -For details, see [Third-Party Components That Can Be Directly Used on OpenHarmony](https://gitee.com/openharmony-sig/third_party_app_libs). - -## Which third-party libraries are related to network requests? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -The [Axios](https://gitee.com/openharmony-sig/axios) library is related to network requests. - -## How do I use NPM to import third- and fourth-party libraries? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 -- Method 1: - 1. Open the **Terminal** window and run the following command to go to the **entry** directory: - - ``` - cd entry - ``` - 2. Run the following command to install a third-party package, for example, **dayjs**: - - ``` - npm install dayjs --save - ``` - 3. Add the following statement in the .js file to import the package: - - ``` - import dayjs from 'dayjs'; - ``` - -- Method 2: - 1. Enter the **entry** directory of the project and open the **package.json** file. - 2. Write the third-party NPM package to be installed (for example, **dayjs**) in the **package.json** file. - - ``` - { - "dependencies": { - "dayjs": "^1.10.4", - } - } - ``` - 3. Open the **Terminal** window and run the following command to go to the **entry** directory: - - ``` - cd entry - ``` - 4. Run the following command to install NPM: - - ``` - npm install - ``` - 5. Add the following statement in the .js file to import the package: - - ``` - import dayjs from 'dayjs'; - ``` diff --git a/en/application-dev/faqs/faqs-ui-ets.md b/en/application-dev/faqs/faqs-ui-ets.md deleted file mode 100644 index 8564d2f0969a2cf6eac9bb2d9ac521e62045d162..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-ui-ets.md +++ /dev/null @@ -1,656 +0,0 @@ -# ArkUI (ArkTS) Development - -## How do I use router to implement page redirection in the stage model? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -1. To implement page redirection through **router**, add all redirected-to pages to the pages list in the **main_pages.json** file. - -2. Page routing APIs in **router** can be invoked only after page rendering is complete. Do not call these APIs in **onInit** or **onReady** when the page is still in the rendering phase. - -Reference: [Page Routing](../reference/apis/js-apis-router.md) - -## Will a page pushed into the stack through router.push be reclaimed? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -After being pushed to the stack through **router.push**, a page can be reclaimed only when it is popped from the stack through **router.back**. - -## How do I position a container component to the bottom of the screen? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Create a **** component, and set the target container at the bottom of the **** component. - -Example: - -``` -build() { - Stack({alignContent : Alignment.Bottom}) { - // The container is at the bottom. - Stack() { - Column() - .width('100%') - .height('100%') - .backgroundColor(Color.Yellow) - } - .width('100%') - .height('10%') - } - .width('100%') - .height('100%') - .backgroundColor('rgba(255,255,255, 0)') -} -``` - -## Can CustomDialog be used in TypeScript files? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -No. **CustomDialog** can be used only on ArkTS pages. - -Reference: [Custom Dialog Box](../reference/arkui-ts/ts-methods-custom-dialog-box.md) - -## How do I transfer variables in CustomDialog to variables on pages? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -Use a custom callback so that when the confirm button in the custom dialog box is clicked, the value of **data** is transferred from the dialog box to the current page. - -Example: - - -``` -// Dialog box component -@CustomDialog -struct MyDialog { - controller: CustomDialogController - title: string - confirm: (data: string) => void - data: string = '' - - build() { - Row() { - Column({ space: 10 }) { - Text(this.title) - .fontSize(30) - .fontColor(Color.Blue) - TextInput({ placeholder: "Enter content", text: this.data }) - .onChange((data) => { - this.data = data // Obtain the data in the text box. - }) - Button('confirm') - .onClick(() => { - this.confirm(this.data) // Transfer the data in the text box to the main page through the callback. - this.controller.close() - }).backgroundColor(0xffffff).fontColor(Color.Red) - }.width("50%") - }.height("50%") - } -} - -// Main page -@Entry -@Component -struct DialogTest { - @State dialogTitle: string = '' - @State dialogData: string = '' - dialogController: CustomDialogController = new CustomDialogController({ - builder: MyDialog({ - title: this.dialogTitle, // Bind data. - data: this.dialogData, - confirm: this.confirm.bind(this) // Bind the custom callback. Change the direction of this here. - }) - }) - - confirm(data: string) { - this.dialogData = data - console.info(`recv dialog data: ${data}`) // Obtain the information entered in the dialog box. - } - - build() { - Row() { - Column({ space: 10 }) { - Button ('Open Dialog Box') - .onClick(() => { - this.dialogTitle ='Dialog Box' - this.dialogController.open() - }) - Text(`Accept pop-up window data:`) - .fontSize(20) - TextInput ({ placeholder: "Input", text: this.dialogData }) - .width("50%") - .onChange((data) => { - this.dialogData = data //Obtain the data in the text box. - }) - }.width("100%") - }.height("100%") - } -} -``` - -## What should I do if the \ component cannot be dragged to the bottom after it has a \ component added? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -The **\** component is a scrollable container. By default, it takes up the entire screen height. When any component with a fixed height takes up part of the screen height, you need to explicitly specify **layoutWeight(1)** for the parent container of the **\** component to take up the remaining height instead of the entire screen height. - -## How do I center child components in a grid container? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -By default, child components in a **\** are horizontally aligned to the left. To center them, perform the following steps: - -Nest a **\** component and set it to **justifyContent(FlexAlign.Center)**. For details, see [Grid Layout](../reference/arkui-ts/ts-container-gridcontainer.md). - -Example: - -``` -GridContainer({ sizeType: SizeType.SM, columns: 12 }) { - Row() { - Text('1') - .useSizeType({ - sm: { span: 4, offset: 0 }, - }) - .backgroundColor(0x46F2B4) - }.justifyContent(FlexAlign.Center) // Center child components. -} -``` - -## How do I obtain the height of the status bar and navigation bar? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -Before the window content is loaded, enable listening for the **systemAvoidAreaChange** event. - -Example: - -```ts -import Window from '@ohos.window'; -import UIAbility from '@ohos.app.ability.UIAbility'; - -/** - * Set the immersive window and obtain the height of the status bar and navigation bar. - * @param mainWindow Indicates the main window. - */ -async function enterImmersion(mainWindow: window.Window) { - mainWindow.on("systemAvoidAreaChange", (area: window.AvoidArea) => { - AppStorage.SetOrCreate("topHeight", area.topRect.height); - AppStorage.SetOrCreate("bottomHeight", area.bottomRect.height); - }) - await mainWindow.setFullScreen(true) - await mainWindow.setSystemBarEnable(["status", "navigation"]) - await mainWindow.sArkTSystemBarProperties({ - navigationBarColor: "#00000000", - statusBarColor: "#00000000", - navigationBarContentColor: "#FF0000", - statusBarContentColor: "#FF0000" - }) -} -export default class EntryAbility extends UIAbility { - // do something - async onWindowStageCreate(windowStage: window.WindowStage) { - let mainWindow = await windowStage.getMainWindow() - await enterImmersion(mainWindow) - windowStage.loadContent('pages/index') - } - // do something -} -``` - -## How do I fix misidentification of the pan gesture where container nesting is involved? - -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 - -Set the **distance** attribute to **1** for the gesture. By default, this attribute is set to **5**. - -## How do I obtain the height of a component? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -You can obtain the changes in the width and height of a component through **onAreaChange**. - -Example: - - -```ts -Column() { - Text(this.value) - .backgroundColor(Color.Green).margin(30).fontSize(20) - .onClick(() => { - this.value = this.value + 'Text' - }) - .onAreaChange((oldValue: Area, newValue: Area) => { - console.info(`Ace: on area change, oldValue is ${JSON.stringify(oldValue)} value is ${JSON.stringify(newValue)}`) - this.size = JSON.stringify(newValue) - }) -``` - -## How do I obtain the offset of the \ component? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -Bind the **\** component to a **Scoller** object and obtain the offset through **currentOffset**. - -Example: - - -```ts -Column() { - List({ space: 20, initialIndex: 0,scroller: this.scroller}) { - ForEach(this.arr, (item) => { - ListItem() { - Text('' + item) - .width('100%').height(100).fontSize(16) - .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF) - }.editable(true) - }, item => item) - } - .listDirection(Axis.Vertical) // Arrangement direction - .editMode(this.editFlag) - .onScroll((xOffset: number, yOffset: number) => { - console.info("yOffset======="+this.scroller.currentOffset().yOffset) - }) -}.width('100%') -``` - -## How do I obtain the value of param for the target page of redirection implemented using router? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - - -```ts -// In versions earlier than 3.1.5.5, obtain the value through router.getParams().key. -private value: string = router.getParams().value; -// In 3.1.6.5 and later versions, obtain the value through router.getParams()['key']. -private value: string = router.getParams()['value']; -``` - -## Does the \ component support redirection to a local page? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -No. This feature is not supported. - -## How do I disable the transition effect for pages switched using router or navigator? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -1. Define the **pageTransition** method for the current and target pages, by following instructions in [Example](../reference/arkui-ts/ts-page-transition-animation.md#example). - -2. Set the **duration** parameter of both **PageTransitionEnter** and **PageTransitionExit** to **0**. - -## How do I select the pixel unit during UI development? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -It depends. - -The vp unit ensures consistency of visual effects across resolutions. For example, it ensures that an icon is displayed consistently under different resolutions. - -The lpx unit produces a visual effect where items are zoomed in or out proportionally. - -If you are concerned about visual effect consistency of items, for example, buttons, texts, and lists, use the vp unit. If your focus is on the layout, for example, 1/2 grid, the lpx is a better choice. - -## What color formats are used in ArkTS? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -The color can be represented in two formats, for example, 0x7F000000 or '\#7F000000'. The first two digits indicate opacity, and the last six digits indicate RGB. - - -```ts -fontColor(0x7F000000) -fontColor( '#7F000000' ) -``` - -## How do I listen for the return operation on a page? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -When a return operation is performed on a page, the system calls the **onBackPress()** callback of the **@Entry** decorated custom component. You can implement related service logic in the callback. - -Reference: [Custom Component Lifecycle Callbacks](../ui/ui-ts-custom-component-lifecycle-callbacks.md) - -## Can I customize the eye icon for the \ component in password mode? - -Applicable to: OpenHarmony SDK 3.0, stage model of API version 9 - -No. The eye icon can be shown or hidden through **showPasswordIcon** when **type** of the **\** component is set to **InputType.Password**. It cannot be customized. - -Reference: [TextInput](../reference/arkui-ts/ts-basic-components-textinput.md) - -## Why can't images be loaded over HTTP? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -HTTP is insecure and HTTP sources will be filtered out by the trustlist. For security purposes, use HTTPS. - -## What should I do if the spacing set for the TextView layout does not fit the UI? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -By default, the **align** attribute of **TextView** is set to **Center**. To display the text from left to right, set the **align** attribute to **Start**. - -## Why do the constraintSize settings fail to take effect? - -Applicable to: OpenHarmony SDK 3.0, stage model of API version 9 - -If **constraintSize** is set for a component and the width of its child component is set to a percentage, for example, **width('100%')**, **constraintSize** takes effect by multiplying the maximum width by the percentage. As a result, the child component may overflow, in which case it looks like the **constraintSize** settings fail to take effect. - -## How do I set the background color to transparent? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Set **backgroundColor** to **'\#00000000'**. - -## What should I do if the \ component cannot scroll to the bottom? - -Applicable to: OpenHarmony SDK 3.0, stage model of API version 9 - -Unless otherwise specified, the height of the **\** component is equal to the window height. In this case, the component's bottom area will be blocked by components (if any) outside of it. To fix this issue, set the height of the **\** component or use the flex layout to limit this height. - -## How do I use the onSubmit event of the \ component? - -Applicable to: OpenHarmony SDK 3.0, stage model of API version 9 - -The **onSubmit** event is triggered when the Enter key is pressed and accepts the current Enter key type as its input parameter. You can set the Enter key type for the **\** component through the **enterKeyType** attribute. The Enter key style of the soft keyboard requires the support of the input method. - -Reference: [TextInput](../reference/arkui-ts/ts-basic-components-textinput.md) - -## What is the maximum number of pages allowed during page routing? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -The maximum number of pages supported by the page stack is 32. When this limit is reached, the **router.push** API cannot be used for page redirection. - -## Does ArkUI allow components to be dynamically created in code? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -Yes. You can dynamically creaete components using [conditional rendering](../quick-start/arkts-rendering-control.md#conditional-rendering) and [loop rendering](../quick-start/arkts-rendering-control.md#loop-rendering). - -## What should I do if the PixelMap object carried in page routing cannot be obtained from the target page? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -Page routing supports only the common object type and common JSON data structure. To pass a **PixelMap** object to the target page, store it in the **localStorage**. - -## How do I use .caretPosition(0) to move the caret to the start of the text area when onEditChange is triggered for the \ component? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -The **onEditChange** event is triggered when the input box gains focus. Under this scenario, the caret position is related to the position where the gesture is when the event is triggered, and **caretPosition** cannot be used to change the caret position. Call **setTimeout** for asynchronous processing first. - -## Is there any method for selecting all items in the \ component? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -No. This feature is not supported yet. - -## Why can't I select a date when the type attribute of the input text box is set to date? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -Setting the **type** attribute of the input component to **date** means that the component accepts dates as input and the user will be notified of the valid input format. It does not display a date picker. To display a date picker, use the **\** component. - -## What should I do if the displayed input keyboard gets squeezed when using the **\** component? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -This issue may occur when the flex layout is used. To fix it, switch to the column layout. - -## How does the parent component pass values to a @Link decorated member variable in its child component? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -To pass a value from the parent component to the **@Link** decorated member variable in a child component, add **"$"** in front of the value. - -Example: - - -``` -@Component -struct FoodImageDisplay { - @Link imageSrc: Resource - - build() { - Stack({ alignContent: Alignment.BottomStart }) { - Image(this.imageSrc) - .objectFit(ImageFit.Contain) - Text('Tomato') - .fontSize(26) - .fontWeight(500) - .margin({ left: 26, bottom: 17.4 }) - } - .backgroundColor('#FFedf2f5') - .height(357) - } -} - -@Entry -@Component -struct FoodDetail { - - @State imageSrc: Resource = $r('app.media.Tomato') - - build() { - Column() { - FoodImageDisplay({imageSrc:$imageSrc}) - } - .alignItems(HorizontalAlign.Center) - } -} -``` - -## How do I share variables between Page abilities? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -1. Use a lightweight database. - -2. Use persistent data management. - -3. Use the emitter event communication mechanism. - - -## How do I customize the control bar style of the \