diff --git a/en/application-dev/Readme-EN.md b/en/application-dev/Readme-EN.md index d854b82e015d4bbf670b773670fd41ed1b856d03..95504e593a1ae40a3f8853ca28f3067c71729315 100644 --- a/en/application-dev/Readme-EN.md +++ b/en/application-dev/Readme-EN.md @@ -41,18 +41,46 @@ - [Resource Categories and Access](quick-start/resource-categories-and-access.md) - Learning ArkTS - [Getting Started with ArkTS](quick-start/arkts-get-started.md) - - ArkTS Syntax (Declarative UI) - - [Basic UI Description](quick-start/arkts-basic-ui-description.md) - - State Management - - [Basic Concepts](quick-start/arkts-state-mgmt-concepts.md) - - [State Management with Page-level Variables](quick-start/arkts-state-mgmt-page-level.md) - - [State Management with Application-level Variables](quick-start/arkts-state-mgmt-application-level.md) - - [Dynamic UI Element Building](quick-start/arkts-dynamic-ui-elememt-building.md) - - [Rendering Control](quick-start/arkts-rendering-control.md) - - [Restrictions and Extensions](quick-start/arkts-restrictions-and-extensions.md) + - Basic Syntax + - [Basic Syntax Overview](quick-start/arkts-basic-syntax-overview.md) + - [Declarative UI Description](quick-start/arkts-declarative-ui-description.md) + - Custom Component + - [Creating a Custom Component](quick-start/arkts-create-custom-components.md) + - [Page and Custom Component Lifecycle](quick-start/arkts-page-custom-components-lifecycle.md) + - [\@Builder: Custom Builder Function](quick-start/arkts-builder.md) + - [\@BuilderParam: @Builder Function Reference](quick-start/arkts-builderparam.md) + - [\@Styles: Definition of Resusable Styles](quick-start/arkts-style.md) + - [\@Extend: Extension of Built-in Components](quick-start/arkts-extend.md) + - [stateStyles: Polymorphic Style](quick-start/arkts-statestyles.md) + - State Management + - [State Management Overview](quick-start/arkts-state-management-overview.md) + - Component State Management + - [\@State: State Owned by Component](quick-start/arkts-state.md) + - [\@Prop: One-Way Synchronization from Parent to Child Components](quick-start/arkts-prop.md) + - [\@Link: Two-Way Synchronization Between Parent and Child Components](quick-start/arkts-link.md) + - [\@Provide and \@Consume: Two-Way Synchronization with Descendant Components](quick-start/arkts-provide-and-consume.md) + - [\@Observed and \@ObjectLink: Observing Attribute Changes in Nested Class Objects](quick-start/arkts-observed-and-objectlink.md) + - Application State Management + - [Application State Management Overview](quick-start/arkts-application-state-management-overview.md) + - [LocalStorage: UI State Storage](quick-start/arkts-localstorage.md) + - [AppStorage: Application-wide UI State Storage](quick-start/arkts-appstorage.md) + - [PersistentStorage: Application State Persistence](quick-start/arkts-persiststorage.md) + - [Environment: Device Environment Query](quick-start/arkts-environment.md) + - Other State Management Features + - [Overview of Other State Management Features](quick-start/arkts-other-state-mgmt-functions-overview.md) + - [\@Watch: Getting Notified of State Variable Changes](quick-start/arkts-watch.md) + - [$$ Syntax: Two-Way Synchronization of Built-in Components](quick-start/arkts-two-way-sync.md) + - Rendering Control + - [Rendering Control Overview](quick-start/arkts-rendering-control-overview.md) + - [if/else: Conditional Rendering](quick-start/arkts-rendering-control-ifelse.md) + - [ForEach: Rendering of Repeated Content](quick-start/arkts-rendering-control-foreach.md) + - [LazyForEach: Lazy Data Loading](quick-start/arkts-rendering-control-lazyforeach.md) + + - Development - [Application Models](application-models/Readme-EN.md) - [UI Development](ui/Readme-EN.md) + - [Web](web/Readme-EN.md) - [Notification](notification/Readme-EN.md) - [Window Manager](windowmanager/Readme-EN.md) - [WebGL](webgl/Readme-EN.md) @@ -86,6 +114,7 @@ - [ArkTS and JS APIs](reference/apis/Readme-EN.md) - [Error Codes](reference/errorcodes/Readme-EN.md) - Native APIs + - [Native APIs](reference/native-apis/Readme-EN.md) - [Standard Libraries](reference/native-lib/third_party_libc/musl.md) - [Node_API](reference/native-lib/third_party_napi/napi.md) - [FAQs](faqs/Readme-EN.md) diff --git a/en/application-dev/application-models/Readme-EN.md b/en/application-dev/application-models/Readme-EN.md index 2d70222630a25f38b0f66367e46fcfdef2487091..b5dd76aea6715dc3bc2e7ad1b8f7cae974343d7c 100644 --- a/en/application-dev/application-models/Readme-EN.md +++ b/en/application-dev/application-models/Readme-EN.md @@ -22,6 +22,31 @@ - [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 diff --git a/en/application-dev/application-models/abilitystage.md b/en/application-dev/application-models/abilitystage.md index 4e0a273f850b4919d0964580ebed89c053c273f7..2f44f69d5810bbddf8128777f63360a1cb196fa3 100644 --- a/en/application-dev/application-models/abilitystage.md +++ b/en/application-dev/application-models/abilitystage.md @@ -12,7 +12,7 @@ AbilityStage is not automatically generated in the default project of DevEco Stu 1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **myabilitystage**. -2. In the **myabilitystage** directory, right-click and choose **New > ts File** to create a file named **MyAbilityStage.ts**. +2. In the **myabilitystage** directory, right-click and choose **New > TypeScript File** to create a file named **MyAbilityStage.ts**. 3. Open the **MyAbilityStage.ts** file, and import the dependency package of AbilityStage. Customize a class that inherits from AbilityStage, and add the required lifecycle callbacks. The following code snippet adds the **onCreate()** lifecycle callback. @@ -20,16 +20,27 @@ AbilityStage is not automatically generated in the default project of DevEco Stu import AbilityStage from '@ohos.app.ability.AbilityStage'; export default class MyAbilityStage extends AbilityStage { - onCreate() { - // When the HAP of the application is loaded for the first time, initialize the module. - } - onAcceptWant(want) { - // Triggered only for the ability with the specified launch type. - return "MyAbilityStage"; - } + onCreate() { + // When the HAP of the application is loaded for the first time, initialize the module. + } + onAcceptWant(want) { + // Triggered only for the ability with the specified launch type. + return "MyAbilityStage"; + } + } + ``` + +4. Set **srcEntry** in the [module.json5 file](../quick-start/module-configuration-file.md) to the code path of the module. + ```json + { + "module": { + "name": "entry", + "type": "entry", + "srcEntry": "./ets/myabilitystage/MyAbilityStage.ts", + // ... + } } ``` - [AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md) has the lifecycle callback [onCreate()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageoncreate) and the event callbacks [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant), [onConfigurationUpdated()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonconfigurationupdate), and [onMemoryLevel()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonmemorylevel). @@ -49,9 +60,8 @@ When an application is switched to the background, it is cached in the backgroun import AbilityStage from '@ohos.app.ability.AbilityStage'; export default class MyAbilityStage extends AbilityStage { - onMemoryLevel(level) { - // Release unnecessary memory based on the change of available system memory. - } + onMemoryLevel(level) { + // Release unnecessary memory based on the change of available system memory. + } } ``` - 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/application-context-stage.md b/en/application-dev/application-models/application-context-stage.md index aa40d3aedf9dbb3db775a634dbd81f60f22fed51..84188352e2b224ba24e9121dce147e39553ce61c 100644 --- a/en/application-dev/application-models/application-context-stage.md +++ b/en/application-dev/application-models/application-context-stage.md @@ -187,13 +187,13 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../ > **NOTE** > > To obtain the context of another application: - > + > > - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). - > + > > - This is a system API and cannot be called by third-party applications. For example, application information displayed on the home screen includes the application name and icon. The home screen application calls the foregoing method to obtain the context information, so as to obtain the resource information including the application name and icon. - + ```ts import UIAbility from '@ohos.app.ability.UIAbility'; @@ -248,7 +248,7 @@ The base class **Context** provides [createBundleContext(bundleName:string)](../ In the DFX statistics scenario of an application, if you need to collect statistics on the stay duration and access frequency of a page, you can subscribe to UIAbility lifecycle changes in a process. -[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example. +[ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext.md) provides APIs for subscribing to UIAbility lifecycle changes in a process. When the UIAbility lifecycle changes in a process, for example, being created or destroyed, becoming visible or invisible, or gaining or losing focus, the corresponding callback is triggered. Each time the callback is registered, a listener lifecycle ID is returned, with the value incremented by 1 each time. When the number of listeners exceeds the upper limit (2^63-1), **-1** is returned. The following uses [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) as an example. ```ts @@ -308,7 +308,7 @@ export default class EntryAbility extends UIAbility { // Obtain the application context. let applicationContext = this.context.getApplicationContext(); // Register the application lifecycle callback. - this.lifecycleId = applicationContext.on('Lifecycle', abilityLifecycleCallback); + this.lifecycleId = applicationContext.on('abilityLifecycle', abilityLifecycleCallback); console.log(TAG, `register callback number: ${this.lifecycleId}`); } 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-static-subscription.md b/en/application-dev/application-models/common-event-static-subscription.md index 013d7709e8c1588571e5c53f2a60ea012ee4f1fa..a545f6464b052cb20bd931b21820d623ad13f9c6 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**. @@ -98,5 +96,5 @@ A static subscriber is started once it receives a target event published by the "ohos.extension.staticSubscriber", "xxx" } - ``` + ``` diff --git a/en/application-dev/application-models/context-switch.md b/en/application-dev/application-models/context-switch.md index 2f52158f5d36be8c59f747376195e9e43078d1f9..e1d155c8a60f6ca3e225174aece28738663b8079 100644 --- a/en/application-dev/application-models/context-switch.md +++ b/en/application-dev/application-models/context-switch.md @@ -5,7 +5,7 @@ | -------- | -------- | -------- | | [getOrCreateLocalDir(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetorcreatelocaldir7)
[getOrCreateLocalDir():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetorcreatelocaldir7-1) | There is no corresponding API in the stage model.| Applications developed on the stage model do not have the operation permission in the application root directory. Therefore, no corresponding API is provided.| | [verifyPermission(permission:string,options:PermissionOptions,callback:AsyncCallback<number>):void;](../reference/apis/js-apis-inner-app-context.md#contextverifypermission7)
[verifyPermission(permission:string,callback:AsyncCallback<number>):void;](../reference/apis/js-apis-inner-app-context.md#contextverifypermission7-1)
[verifyPermission(permission:string,options?:PermissionOptions):Promise<number>;](../reference/apis/js-apis-inner-app-context.md#contextverifypermission7-2) | \@ohos.abilityAccessCtrl.d.ts | [verifyAccessTokenSync(tokenID: number, permissionName: Permissions): GrantStatus;](../reference/apis/js-apis-abilityAccessCtrl.md#verifyaccesstokensync9)
[verifyAccessToken(tokenID: number, permissionName: Permissions): Promise<GrantStatus>;](../reference/apis/js-apis-abilityAccessCtrl.md#verifyaccesstoken9) | -| [requestPermissionsFromUser(permissions:Array<string>,requestCode:number,resultCallback:AsyncCallback<PermissionRequestResult>):void;](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7)
[requestPermissionsFromUser(permissions:Array<string>,requestCode:number):Promise<PermissionRequestResult>;](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7-1) | application\UIAbilityContext.d.ts | [requestPermissionsFromUser(permissions: Array<string>, requestCallback: AsyncCallback<PermissionRequestResult>) : void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextrequestpermissionsfromuser)
[requestPermissionsFromUser(permissions: Array<string>) : Promise<PermissionRequestResult>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextrequestpermissionsfromuser-1) | +| [requestPermissionsFromUser(permissions:Array<string>,requestCode:number,resultCallback:AsyncCallback<PermissionRequestResult>):void;](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7)
[requestPermissionsFromUser(permissions:Array<string>,requestCode:number):Promise<PermissionRequestResult>;](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7-1) | \@ohos.abilityAccessCtrl.d.ts | [requestPermissionsFromUser(context: Context, permissionList: Array<Permissions>, requestCallback: AsyncCallback<PermissionRequestResult>) : void;](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)
[requestPermissionsFromUser(context: Context, permissionList: Array<Permissions>) : Promise<PermissionRequestResult>;](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9-1) | | [getApplicationInfo(callback:AsyncCallback<ApplicationInfo>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetapplicationinfo7)
[getApplicationInfo():Promise<ApplicationInfo>;](../reference/apis/js-apis-inner-app-context.md#contextgetapplicationinfo7-1) | application\Context.d.ts | [applicationInfo: ApplicationInfo;](../reference/apis/js-apis-inner-application-context.md#attributes)| | [getBundleName(callback : AsyncCallback<string>): void;](../reference/apis/js-apis-inner-app-context.md#contextgetbundlename7)
[getBundleName(): Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetbundlename7-1) | application\UIAbilityContext.d.ts | [abilityInfo.bundleName: string;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)| | [getDisplayOrientation(callback : AsyncCallback<bundle.DisplayOrientation>): void;](../reference/apis/js-apis-inner-app-context.md#contextgetdisplayorientation7)
[getDisplayOrientation(): Promise<bundle.DisplayOrientation>;](../reference/apis/js-apis-inner-app-context.md#contextgetdisplayorientation7-1) | \@ohos.screen.d.ts | [readonly orientation: Orientation;](../reference/apis/js-apis-screen.md#orientation) | diff --git a/en/application-dev/application-models/datashareextensionability.md b/en/application-dev/application-models/datashareextensionability.md index f671848f890277af92fc23869c5db0d57b02a316..bea3de69c6d7ad375206fb1d53bcc36c2624989d 100644 --- a/en/application-dev/application-models/datashareextensionability.md +++ b/en/application-dev/application-models/datashareextensionability.md @@ -1,4 +1,4 @@ # DataShareExtensionAbility (for System Applications Only) -DataShareExtensionAbility provides the data sharing capability. System applications can implement a DataShareExtensionAbility or access an existing DataShareExtensionAbility in the system. Third-party applications can only access an existing DataShareExtensionAbility. For details, see [DataShare Development](../database/database-datashare-guidelines.md). +DataShareExtensionAbility provides the data sharing capability. System applications can implement a DataShareExtensionAbility or access an existing DataShareExtensionAbility in the system. Third-party applications can only access an existing DataShareExtensionAbility. For details, see [Cross-Application Data Sharing Overview](../database/share-device-data-across-apps-overview.md). diff --git a/en/application-dev/application-models/enterprise-extensionAbility.md b/en/application-dev/application-models/enterprise-extensionAbility.md index 18d5ec828126a2d11b57bf4dd482c4af56fa14bc..da8054e54284cc3a32af5ea6acaafc9eabc01561 100644 --- a/en/application-dev/application-models/enterprise-extensionAbility.md +++ b/en/application-dev/application-models/enterprise-extensionAbility.md @@ -2,12 +2,11 @@ ## Introduction to EnterpriseAdminExtensionAbility -EnterpriseAdminExtensionAbility is a mandatory component for Mobile Device Management (MDM) applications. When developing MDM applications for enterprises, you need to inherit EnterpriseAdminExtensionAbility and implement MDM service logic in the EnterpriseAdminExtensionAbility instance. EnterpriseAdminExtensionAbility implements notifications of system management status changes and defines the callbacks when a device administrator application is enabled or disabled or an application is installed or uninstalled. +EnterpriseAdminExtensionAbility is a mandatory component for Mobile Device Management (MDM) applications. When developing MDM applications for enterprises, you need to inherit EnterpriseAdminExtensionAbility and implement MDM service logic in the EnterpriseAdminExtensionAbility instance. EnterpriseAdminExtensionAbility implements notifications of system management status changes and defines the callbacks for when a device administrator application is enabled or disabled or an application is installed or uninstalled. ## Constraints - EnterpriseAdminExtensionAbility is applicable only to enterprise administrator applications. - +EnterpriseAdminExtensionAbility is applicable only to enterprise administrator applications. ## Observing Activation/Deactivation of a Device Administrator Application and Installation/Removal of an Application @@ -24,59 +23,59 @@ EnterpriseAdminExtensionAbility is a mandatory component for Mobile Device Manag ### Available APIs | Class | API | Description | -| :------------------------------ | ----------------------------------------- | ---------------------------- | +| ------------------------------ | ----------------------------------------- | ---------------------------- | +| EnterpriseAdminExtensionAbility | onAdminEnabled(): void | Called when a device administrator application is activated. | | EnterpriseAdminExtensionAbility | onAdminDisabled(): void | Called when a device administrator application is deactivated.| | EnterpriseAdminExtensionAbility | onBundleAdded(bundleName: string): void | Called when an application is installed on a device. | -| EnterpriseAdminExtensionAbility | onAdminEnabled(): void | Called when a device administrator application is activated. | | EnterpriseAdminExtensionAbility | onBundleRemoved(bundleName: string): void | Called when an application is removed from a device. | ### How to Develop To implement EnterpriseAdminExtensionAbility, you need to activate the device administrator application and create **ExtensionAbility** in the code directory of the device administrator application. The procedure is as follows: -1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **EnterpriseExtAbility**. +1. In the **ets** directory of the target module, right-click and choose **New > Directory** to create a directory named **EnterpriseExtAbility**. 2. Right-click the **EnterpriseExtAbility** directory, and choose **New > TypeScript File** to create a file named **EnterpriseExtAbility.ts**. 3. Open the **EnterpriseExtAbility.ts** file and import the **EnterpriseAdminExtensionAbility** module. Inherit the **EnterpriseAdminExtensionAbility** module to the custom class and add application notification callbacks, such as **onAdminEnabled()** and **onAdminDisabled()**. When the device administrator application is activated or deactivated, the device administrator can receive notifications. -```ts -import EnterpriseAdminExtensionAbility from '@ohos.enterprise.EnterpriseAdminExtensionAbility'; - -export default class EnterpriseAdminAbility extends EnterpriseAdminExtensionAbility { - - onAdminEnabled() { - console.info("onAdminEnabled"); - } - - onAdminDisabled() { - console.info("onAdminDisabled"); - } - - onBundleAdded(bundleName: string) { - console.info("EnterpriseAdminAbility onBundleAdded bundleName:" + bundleName) - } - - onBundleRemoved(bundleName: string) { - console.info("EnterpriseAdminAbility onBundleRemoved bundleName" + bundleName) - } -}; -``` - -​ 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. - -```ts -"extensionAbilities": [ - { - "name": "ohos.samples.enterprise_admin_ext_ability", - "type": "enterpriseAdmin", - "visible": true, - "srcEntrance": "./ets/enterpriseextability/EnterpriseAdminAbility.ts" - } - ] -``` + ```ts + import EnterpriseAdminExtensionAbility from '@ohos.enterprise.EnterpriseAdminExtensionAbility'; + + export default class EnterpriseAdminAbility extends EnterpriseAdminExtensionAbility { + + onAdminEnabled() { + console.info("onAdminEnabled"); + } + + onAdminDisabled() { + console.info("onAdminDisabled"); + } + + onBundleAdded(bundleName: string) { + console.info("EnterpriseAdminAbility onBundleAdded bundleName:" + bundleName) + } + + onBundleRemoved(bundleName: string) { + console.info("EnterpriseAdminAbility onBundleRemoved bundleName" + bundleName) + } + }; + ``` + +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", + "exported": true, + "srcEntry": "./ets/enterpriseextability/EnterpriseAdminAbility.ts" + } + ] + ``` ## Example -Use **subscribeManagedEvent()** and **unsubscribeManagedEvent()** in the @ohos.enterprise.adminManager module to subscribe to application installation and removal events. When an application is installed or removed, the MDM application is notified of the event. Then, the MDM application reports the event in the callback to notify the enterprise administrator. +Use **subscribeManagedEvent** in the **@ohos.enterprise.adminManager** module to subscribe to application installation and removal events. When an application is installed or removed, the MDM application is notified of the event. Then, the MDM application reports the event in the callback to notify the enterprise administrator. To unsubscribe from events, use **unsubscribeManagedEvent**. ```ts @State managedEvents: Array = [0,1] @@ -105,3 +104,4 @@ Use **subscribeManagedEvent()** and **unsubscribeManagedEvent()** in the @ohos.e }) } ``` + diff --git a/en/application-dev/application-models/extensionability-overview.md b/en/application-dev/application-models/extensionability-overview.md index c656b503b5d8c98e79f68c7c4864046244455b10..cbc50b7f1bc439b156644712531da7128409c476 100644 --- a/en/application-dev/application-models/extensionability-overview.md +++ b/en/application-dev/application-models/extensionability-overview.md @@ -25,7 +25,8 @@ An [ExtensionAbilityType](../reference/apis/js-apis-bundleManager.md#extensionab - [EnterpriseAdminExtensionAbility](../reference/apis/js-apis-EnterpriseAdminExtensionAbility.md): ExtensionAbility component of the enterprise_admin type, which provides APIs for processing enterprise management events, such as application installation events on devices and events indicating too many incorrect screen-lock password attempts. -> **NOTE**
+> **NOTE** +> > 1. Third-party applications cannot implement ServiceExtensionAbility, DataShareExtensionAbility, StaticSubscriberExtensionAbility, or WindowExtensionAbility. > > 2. To implement transaction processing in the background for a third-party application, use background tasks rather than ServiceExtensionAbility. For details, see [Background Task](../task-management/background-task-overview.md). @@ -45,7 +46,7 @@ The following uses [InputMethodExtensionAbility](../reference/apis/js-apis-input ## Implementing ExtensionAbility of the Specified Type -The following uses [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) as an example. The widget framework provides the base class [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). You derive this base class to create your own class (such as **MyFormExtensionAbility**), implement the callbacks, such as **onCreate()** and **onUpdateForm()**, to provide specific widget functionalities. For details, see [FormExtensionAbility](Widget-development-stage.md). +The following uses [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md) as an example. The widget framework provides the base class [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). You derive this base class to create your own class (such as **MyFormExtensionAbility**), implement the callbacks, such as **onCreate()** and **onUpdateForm()**, to provide specific widget functionalities. For details, see [FormExtensionAbility](service-widget-overview.md). You do not need to care when to add or delete a widget. The lifecycle of the FormExtensionAbility instance and the lifecycle of the ExtensionAbility process where the FormExtensionAbility instance is located are scheduled and managed by FormManagerService. @@ -63,3 +64,5 @@ You do not need to care when to add or delete a widget. The lifecycle of the For > - The two FormExtensionAbility components run in an independent process. > > - The two ImeExtensionAbility components run in an independent process. + + \ No newline at end of file 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/zh-cn/application-dev/application-models/figures/WidgetCanvasDemo.jpeg b/en/application-dev/application-models/figures/WidgetCanvasDemo.jpeg similarity index 100% rename from zh-cn/application-dev/application-models/figures/WidgetCanvasDemo.jpeg rename to en/application-dev/application-models/figures/WidgetCanvasDemo.jpeg 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/figures/standard-mode.png b/en/application-dev/application-models/figures/standard-mode.png deleted file mode 100644 index fc903e6c1be80d3c00281d00d9ab0a1e334d7724..0000000000000000000000000000000000000000 Binary files a/en/application-dev/application-models/figures/standard-mode.png and /dev/null differ diff --git a/en/application-dev/application-models/figures/uiability-launch-type1.gif b/en/application-dev/application-models/figures/uiability-launch-type1.gif new file mode 100644 index 0000000000000000000000000000000000000000..d31a51a1aa97d32ee0ee7df4803378c1b7124119 Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-launch-type1.gif differ diff --git a/en/application-dev/application-models/figures/uiability-launch-type1.png b/en/application-dev/application-models/figures/uiability-launch-type1.png deleted file mode 100644 index c4f5aa4b9a988d8e7148b504c4dcc163961cb103..0000000000000000000000000000000000000000 Binary files a/en/application-dev/application-models/figures/uiability-launch-type1.png and /dev/null differ diff --git a/en/application-dev/application-models/figures/uiability-launch-type2.gif b/en/application-dev/application-models/figures/uiability-launch-type2.gif new file mode 100644 index 0000000000000000000000000000000000000000..ecb3c413e3af2f92ef6834024d0d413e30c2419f Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-launch-type2.gif differ diff --git a/en/application-dev/application-models/figures/uiability-launch-type2.png b/en/application-dev/application-models/figures/uiability-launch-type2.png deleted file mode 100644 index 6f0e43d24f745aee41601cc48f4bc138572fbeb5..0000000000000000000000000000000000000000 Binary files a/en/application-dev/application-models/figures/uiability-launch-type2.png and /dev/null differ diff --git a/en/application-dev/application-models/figures/uiability-launch-type3.gif b/en/application-dev/application-models/figures/uiability-launch-type3.gif new file mode 100644 index 0000000000000000000000000000000000000000..029e8ba7e90eb836f8466c604d4fcf8171ffec6e Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-launch-type3.gif differ diff --git a/en/application-dev/application-models/hop-multi-device-collaboration.md b/en/application-dev/application-models/hop-multi-device-collaboration.md index 7cf66fbab7a98b109de3f9ffcc2fc7b7a2ecd127..721e135179810539bf6782489b67d2619536e8d2 100644 --- a/en/application-dev/application-models/hop-multi-device-collaboration.md +++ b/en/application-dev/application-models/hop-multi-device-collaboration.md @@ -187,7 +187,7 @@ On device A, touch the **Start** button provided by the initiator application to // ... - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbilityForResult(want).then((data) => { if (data?.resultCode === RESULT_CODE) { // Parse the information returned by the target UIAbility. @@ -384,12 +384,12 @@ The following describes how to implement multi-device collaboration through cros ```json "abilities":[{ "name": ".CalleeAbility", - "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", + "srcEnty": "./ets/CalleeAbility/CalleeAbility.ts", "launchType": "singleton", "description": "$string:CalleeAbility_desc", "icon": "$media:icon", "label": "$string:CalleeAbility_label", - "visible": true + "exported": true }] ``` @@ -459,7 +459,7 @@ The following describes how to implement multi-device collaboration through cros onDestroy() { try { - this.callee.off(MSG_SEND_METHOD) + this.callee.off(MSG_SEND_METHOD) } catch (error) { console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`) } @@ -491,7 +491,7 @@ The following describes how to implement multi-device collaboration through cros if (data != null) { caller = data console.info('get remote caller success') - // Register the onRelease listener of the CallerAbility. + // Register the onRelease() listener of the CallerAbility. caller.onRelease((msg) => { console.info(`remote caller onRelease is called ${msg}`) }) 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/js-ui-widget-development.md b/en/application-dev/application-models/js-ui-widget-development.md new file mode 100644 index 0000000000000000000000000000000000000000..1c0cd275c9192e6d5723e04241f71560427cbb15 --- /dev/null +++ b/en/application-dev/application-models/js-ui-widget-development.md @@ -0,0 +1,590 @@ +# Developing a JS Widget + + +The following describes how to develop JS widgets based on the web-like development paradigm. + + +## Working Principles + +Below shows the working principles of the widget framework. + +**Figure 1** Widget framework working principles in the stage model + +![JSCardPrinciple](figures/JSCardPrinciple.png) + +The widget host consists of the following modules: + +- Widget usage: provides operations such as creating, deleting, or updating a widget. + +- Communication adapter: provided by the OpenHarmony SDK for communication with the Widget Manager. It sends widget-related operations to the Widget Manager. + +The Widget Manager consists of the following modules: + +- Periodic updater: starts a scheduled task based on the update policy to periodically update a widget after it is added to the Widget Manager. + +- Cache manager: caches view information of a widget after it is added to the Widget Manager to directly return the cached data when the widget is obtained next time. This reduces the latency greatly. + +- Lifecycle manager: suspends update when a widget is switched to the background or is blocked, and updates and/or clears widget data during upgrade and deletion. + +- Object manager: manages RPC objects of the widget host. It is used to verify requests from the widget host and process callbacks after the widget update. + +- Communication adapter: communicates with the widget host and provider through RPCs. + +The widget provider consists of the following modules: + +- Widget service: implemented by the widget provider developer to process requests on widget creation, update, and deletion, and to provide corresponding widget services. + +- Instance manager: implemented by the widget provider developer for persistent management of widget instances allocated by the Widget Manager. + +- 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. + + +## Available APIs + +The **FormExtensionAbility** class has the following APIs. For details, see [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md). + +| 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.| +| 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 **FormProvider** class has the following APIs. For details, see [FormProvider](../reference/apis/js-apis-app-form-formProvider.md). + +| 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.| + +The **FormBindingData** class has the following APIs. For details, see [FormBindingData](../reference/apis/js-apis-app-form-formBindingData.md). + +| Name| Description| +| -------- | -------- | +| createFormBindingData(obj?: Object \| string): FormBindingData | Creates a **FormBindingData** object.| + + +## How to Develop + +The widget provider development based on the [stage model](stage-model-development-overview.md) involves the following key steps: + +- [Creating a FormExtensionAbility Instance](#creating-a-formextensionability-instance): Develop the lifecycle callback functions of FormExtensionAbility. + +- [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. + +- [Updating Widget Data](#updating-widget-data): Call **updateForm()** to update the information displayed on a widget. + +- [Developing the Widget UI Page](#developing-the-widget-ui-page): Use HML+CSS+JSON to develop a JS widget UI page. + +- [Developing Widget Events](#developing-widget-events): Add the router and message events for a widget. + + +### Creating a FormExtensionAbility Instance + +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 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'; + import dataStorage from '@ohos.data.storage'; + ``` + +2. Implement the FormExtension lifecycle callbacks in **EntryFormAbility.ts**. + + + ```ts + 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. + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + } + onCastToNormalForm(formId) { + // 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'); + } + 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": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + formProvider.updateForm(formId, formData).catch((error) => { + console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); + }); + } + onChangeFormVisibility(newStatus) { + // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. This callback takes effect only for system applications. + console.info('[EntryFormAbility] onChangeFormVisibility'); + } + onFormEvent(formId, message) { + // If the widget supports event triggering, override this method and implement the trigger. + console.info('[EntryFormAbility] onFormEvent'); + } + onRemoveForm(formId) { + // Delete widget data. + console.info('[EntryFormAbility] onRemoveForm'); + } + onConfigurationUpdate(config) { + console.info('[EntryFormAbility] nConfigurationUpdate, config:' + JSON.stringify(config)); + } + onAcquireFormState(want) { + return formInfo.FormState.READY; + } + } + ``` + +> **NOTE** +> FormExtensionAbility cannot reside in the background. Therefore, continuous tasks cannot be processed in the widget lifecycle callbacks. + + +### 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: + + + ```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** Widget profile configuration 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.| String| No| + | 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.
**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)| + | 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": "./js/widget/pages/index/index", + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + "colorMode": "auto", + "isDefault": true, + "updateEnabled": true, + "scheduledUpdateTime": "10:30", + "updateDuration": 1, + "defaultDimension": "2*2", + "supportDimensions": [ + "2*2" + ] + } + ] + } + ``` + + +### Persistently Storing Widget Data + +A widget provider is usually started when it is needed to provide information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting a widget. + + +```ts +const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store"; +async function storeFormInfo(formId: string, formName: string, tempFlag: boolean) { + // Only the widget ID (formId), widget name (formName), and whether the widget is a temporary one (tempFlag) are persistently stored. + let formInfo = { + "formName": formName, + "tempFlag": tempFlag, + "updateCount": 0 + }; + try { + const storage = await dataStorage.getStorage(DATA_STORAGE_PATH); + // put form info + await storage.put(formId, JSON.stringify(formInfo)); + console.info(`[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`); + await storage.flush(); + } catch (err) { + console.error(`[EntryFormAbility] failed to storeFormInfo, err: ${JSON.stringify(err)}`); + } +} + +export default class EntryFormAbility extends FormExtension { + ... + onAddForm(want) { + console.info('[EntryFormAbility] onAddForm'); + + let formId = want.parameters["ohos.extra.param.key.form_identity"]; + let formName = want.parameters["ohos.extra.param.key.form_name"]; + let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; + // Persistently store widget data for subsequent use, such as instance acquisition and update. + // Implement this API based on project requirements. + storeFormInfo(formId, formName, tempFlag); + + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + } +} +``` + +You should override **onRemoveForm** to implement widget data deletion. + + +```ts +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); + // del form info + await storage.delete(formId); + console.info(`[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`); + await storage.flush(); + } catch (err) { + console.error(`[EntryFormAbility] failed to deleteFormInfo, err: ${JSON.stringify(err)}`); + } +} + +... + +export default class EntryFormAbility extends FormExtension { + ... + onRemoveForm(formId) { + console.info('[EntryFormAbility] onRemoveForm'); + // Delete the persistent widget instance data. + // Implement this API based on project requirements. + deleteFormInfo(formId); + } +} +``` + +For details about persistence, see [Application Data Persistence Overview](../database/app-data-persistence-overview.md). + +The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary. + +- Normal widget: a widget persistently used by the widget host + +- Temporary widget: a widget temporarily used by the widget host + +Data of a temporary widget will be deleted on the Widget Manager if the widget framework is killed and restarted. The widget provider, however, is not notified of the deletion and still keeps the data. Therefore, the widget provider needs to clear the data of temporary widgets proactively if the data has been kept for a long period of time. If the widget host has converted a temporary widget into a normal one, the widget provider should change the widget data from temporary storage to persistent storage. Otherwise, the widget data may be deleted by mistake. + + +### Updating Widget Data + +When an application initiates a scheduled or periodic update, the application obtains the latest data and calls **updateForm()** to update the widget. + + +```ts +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": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + // Call the updateForm() method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged. + formProvider.updateForm(formId, formData).catch((error) => { + console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); + }); +} +``` + + +### Developing the Widget UI Page + +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. + +![WidgetCardPage](figures/WidgetCardPage.png) + +- HML: uses web-like paradigm components to describe the widget page information. + + + ```html +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + +- CSS: defines style information about the web-like paradigm components in HML. + + + ```css + .container { + flex-direction: column; + justify-content: center; + align-items: center; + } + + .bg-img { + flex-shrink: 0; + height: 100%; + } + + .container-inner { + flex-direction: column; + justify-content: flex-end; + align-items: flex-start; + height: 100%; + width: 100%; + padding: 12px; + } + + .title { + font-size: 19px; + font-weight: bold; + color: white; + text-overflow: ellipsis; + max-lines: 1; + } + + .detail_text { + font-size: 16px; + color: white; + opacity: 0.66; + text-overflow: ellipsis; + max-lines: 1; + margin-top: 6px; + } + ``` + +- JSON: defines data and event interaction on the widget UI page. + + + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "EntryAbility", + "params": { + "message": "add detail" + } + } + } + } + ``` + + +### Developing Widget 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 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 +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + +- CSS file: + + + ```css + .container { + flex-direction: column; + justify-content: center; + align-items: center; + } + + .bg-img { + flex-shrink: 0; + height: 100%; + } + + .container-inner { + flex-direction: column; + justify-content: flex-end; + align-items: flex-start; + height: 100%; + width: 100%; + padding: 12px; + } + + .title { + font-size: 19px; + font-weight: bold; + color: white; + text-overflow: ellipsis; + max-lines: 1; + } + + .detail_text { + font-size: 16px; + color: white; + opacity: 0.66; + text-overflow: ellipsis; + max-lines: 1; + margin-top: 6px; + } + ``` + +- JSON file + + + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "EntryAbility", + "params": { + "info": "router info", + "message": "router message" + } + }, + "messageEvent": { + "action": "message", + "params": { + "detail": "message detail" + } + } + } + } + ``` + +- 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 (params.info === "router info") { + // do something + // console.info("router info:" + params.info) + } + // Obtain the message parameter passed in the router event. + 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.detail === "message detail") { + // do something + // console.info("message info:" + msg.detail) + } + } + ... + }; + ``` diff --git a/en/application-dev/application-models/lifecycleapp-switch.md b/en/application-dev/application-models/lifecycleapp-switch.md index 892a8915bfed9927c2707364bdaffa1547f71bf6..9d89597ef5a77246ec7450261916061062d24d8d 100644 --- a/en/application-dev/application-models/lifecycleapp-switch.md +++ b/en/application-dev/application-models/lifecycleapp-switch.md @@ -1,17 +1,17 @@ # LifecycleApp Switching - | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| | -------- | -------- | -------- | | onShow?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback<WindowStageEventType>): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)
Listens for the switching to the [foreground](../reference/apis/js-apis-window.md#windowstageeventtype9).| | onHide?(): void; | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback<WindowStageEventType>): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)
Listens for the switching to the [background](../reference/apis/js-apis-window.md#windowstageeventtype9).| -| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) | +| onDestroy?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityondestroy) | | onCreate?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate) | | onWindowDisplayModeChanged?(isShownInMultiWindow: boolean, newConfig: resourceManager.Configuration): void; | There is no corresponding API in the stage model.| No corresponding API is provided.| | onStartContinuation?(): boolean; | There is no corresponding API in the stage model.| In the stage model, an application does not need to detect whether the continuation is successful (detected when the application initiates the continuation request). Therefore, the **onStartContinuation()** callback is deprecated.| | onSaveData?(data: Object): boolean; | \@ohos.app.ability.UIAbility.d.ts | [onContinue(wantParam : {[key: string]: any}): AbilityConstant.OnContinueResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncontinue) | | onCompleteContinuation?(result: number): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) | -| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)
[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)
In standard or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.| +| onRestoreData?(data: Object): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)
[onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)
In multiton or singleton mode, the target ability completes data restoration in the **onCreate()** callback. In the callback, **launchParam.launchReason** is used to determine whether it is a continuation-based launch scenario. If it is, the data saved before continuation can be obtained from the **want** parameter.| | onRemoteTerminated?(): void; | application\ContinueCallback.d.ts | [onContinueDone(result: number): void;](../reference/apis/js-apis-distributedMissionManager.md#continuecallback) | | onSaveAbilityState?(outState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onSaveState(reason: AbilityConstant.StateType, wantParam : {[key: string]: any}): AbilityConstant.OnSaveResult;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonsavestate) | | onRestoreAbilityState?(inState: PacMap): void; | \@ohos.app.ability.UIAbility.d.ts | [onCreate(want: Want, param: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncreate)
After the application is restarted, the **onCreate()** callback is triggered. In the callback, **launchParam.launchReason** is used to determine whether it is a self-recovery scenario. If it is, the data saved before the restart can be obtained from the **want** parameter.| diff --git a/en/application-dev/application-models/mission-management-launch-type.md b/en/application-dev/application-models/mission-management-launch-type.md index 72b6dbf80df2628119ebcc29339ed7e4b70e9a50..6bad0ba0079e7087406000cd1a5e5ffb54a4f17c 100644 --- a/en/application-dev/application-models/mission-management-launch-type.md +++ b/en/application-dev/application-models/mission-management-launch-type.md @@ -8,16 +8,19 @@ The following describes how the mission list manager manages the UIAbility insta - **singleton**: Only one UIAbility instance exists for an application. **Figure 1** Missions and singleton mode + ![mission-and-singleton](figures/mission-and-singleton.png) -- **standard**: Each time **startAbility()** is called, a UIAbility instance is created in the application process. +- **multiton**: Each time **startAbility()** is called, a **UIAbility** instance is created in the application process. + + **Figure 2** Missions and multiton mode - **Figure 2** Missions and standard mode - ![mission-and-standard](figures/mission-and-standard.png) + ![mission-and-multiton](figures/mission-and-standard.png) -- **specified**: The ([onAcceptWant](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create an instance. +- **specified**: The ([onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant)) method of [AbilityStage](abilitystage.md) determines whether to create an instance. **Figure 3** Missions and specified mode + ![mission-and-specified](figures/mission-and-specified.png) diff --git a/en/application-dev/application-models/mission-management-overview.md b/en/application-dev/application-models/mission-management-overview.md index e371e8380fbd7e181e13f1d5f5e7487b15eb9ff1..8d219cf935b0f4cae4093b33ed760a3603538ecc 100644 --- a/en/application-dev/application-models/mission-management-overview.md +++ b/en/application-dev/application-models/mission-management-overview.md @@ -13,6 +13,7 @@ Before getting started with the development of mission management, be familiar w - MissionListManager: system mission management module that maintains all the MissionLists and is consistent with the list in **Recents**. **Figure 1** Mission management + ![mission-list-manager](figures/mission-list-manager.png) diff --git a/en/application-dev/application-models/module-switch.md b/en/application-dev/application-models/module-switch.md index f3d5bd1c643a21945c06bdda69657ff823168907..f86d416597febe296adf6bd38b6a3d87a86fdda7 100644 --- a/en/application-dev/application-models/module-switch.md +++ b/en/application-dev/application-models/module-switch.md @@ -8,7 +8,7 @@ When switching an application from the FA model to the stage model, you must mig | Field Name in the FA Model| Field Description| Field Name in the Stage Model| Difference| | -------- | -------- | -------- | -------- | | mainAbility | Ability displayed on the Service Center icon. When the resident process is started, the **mainAbility** is started.| mainElement | The field name is changed, and the stage mode does not use the period (.) in ability names.| -| package | Package name of the HAP file, which must be unique in the application.| / | The stage model uses **name** to ensure application uniqueness. To ensure a successful switching from the FA model to the stage model, **name** in the stage model must be the same as **package** in the FA model.| +| package | Package name of the HAP file, which must be unique in the application.| / | The stage model uses **name** to ensure application uniqueness. | | name | Class name of the HAP file.| / | This configuration is not enabled in the FA model, and the stage model does not have such a field.| | supportedModes | Modes supported by the application. Currently, only the **drive** mode is defined.| / | This configuration is deprecated in the stage model.| | moduleName in the distro object| Name of the current HAP file.
moduleName in the distro object.| name | The field name is changed.| @@ -21,11 +21,12 @@ When switching an application from the FA model to the stage model, you must mig | shortcuts | Shortcuts of the application.| shortcut_config.json| In the stage model, the **shortcut_config.json** file is defined in **resources/base/profile** in the development view.| | reqPermissions | Permissions that the application requests from the system when it is running.| requestPermissions | The field name is changed.| | colorMode | Color mode of the application.| / | This configuration is not supported in the stage model.| -| distroFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.| +| distributionFilter | Distribution rules of the application.| distroFilter_config.json| In the stage model, the **distroFilter_config.json** file is defined in **resources/base/profile** in the development view.| | reqCapabilities | Device capabilities required for running the application.| / | This configuration is not supported in the stage model.| | commonEvents | Common events.| common_event_config.json| In the stage model, the **common_event_config.json** file is defined in **resources/base/profile** in the development view.| | entryTheme | Keyword of an OpenHarmony internal theme.| / | This configuration is not supported in the stage model.| + ### Table 2 metaData Comparison | Field Name Under metaData in the FA Model| Field Description| Field Name Under metaData in the Stage Model| Difference| @@ -40,7 +41,8 @@ When switching an application from the FA model to the stage model, you must mig | -------- | -------- | -------- | -------- | | name | Key name that identifies a data item. The value is a string with a maximum of 255 bytes.| name | None.| | value | Value of the data item. The value is a string with a maximum of 255 bytes.| value | None.| -| extra | Format of the current custom data. The value is the resource value of **extra**.| resource | The field name is changed. For details, see [Table 4](#table-4-metadata-examples).| +| extra | Format of the current custom data. The value is the resource value of **extra**.| resource | The field name is changed. For details, see [Table 4](#table 4-metadata-examples).| + ### Table 4 metaData Examples @@ -69,5 +71,5 @@ When switching an application from the FA model to the stage model, you must mig | formsEnabled | Whether the ability can provide widgets.| / | This configuration is not supported in the stage model.| | forms | Information about the widgets used by the ability. This field is valid only when **formsEnabled** is set to **true**.| form_config.json| In the stage model, the **form_config.json** file is defined in **resources/base/profile** in the development view.| | srcLanguage | Programming language used to develop the ability.| / | This configuration is not supported in the stage model.| -| srcPath | Path of the JS component code corresponding to the ability.| srcEntrance | Path of the JS code corresponding to the ability.| +| srcPath | Path of the JS component code corresponding to the ability.| srcEnty | Path of the JS code corresponding to the ability.| | uriPermission | Application data that the ability can access.| / | This configuration is not supported in the stage model.| diff --git a/en/application-dev/application-models/pageability-launch-type.md b/en/application-dev/application-models/pageability-launch-type.md index 5241a7cabefbf3e68e6a3f413b8892ef5f6ff8d3..3b75ff6a60899f19f08aad5235fb3dc49632cb01 100644 --- a/en/application-dev/application-models/pageability-launch-type.md +++ b/en/application-dev/application-models/pageability-launch-type.md @@ -5,10 +5,10 @@ Depending on the launch type, the action performed when the PageAbility starts d **Table 1** PageAbility launch types -| Launch Type| Description| -| -------- | -------- | -| singleton | Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.
A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.| -| standard | Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.
A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.| +| Launch Type| Meaning | Description| +| -------- | -------- | -------- | +| singleton | Singleton mode| Each time **startAbility()** is called, if an ability instance of this type already exists in the application process, the instance is reused. There is only one ability instance of this type in **Recents**.
A typical scenario is as follows: When a user opens a video playback application and watches a video, returns to the home screen, and opens the video playback application again, the video that the user watched before returning to the home screen is still played.| +| standard | Multiton mode| Default type. Each time **startAbility()** is called, a new ability instance is created in the application process. Multiple ability instances of this type are displayed in **Recents**.
A typical scenario is as follows: When a user opens a document application and touches **New**, a new document task is created. Multiple new document missions are displayed in **Recents**.| You can set **launchType** in the **config.json** file to configure the launch type. The sample code is as follows: @@ -19,8 +19,8 @@ You can set **launchType** in the **config.json** file to configure the launch t // ... "abilities": [ { - // singleton mode. - // standard mode. + // singleton means the singleton mode. + // standard means the multiton mode. "launchType": "standard", // ... } @@ -30,7 +30,8 @@ You can set **launchType** in the **config.json** file to configure the launch t ``` -When the PageAbility is started for the first time (either in standard or singleton mode), the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not. +When the PageAbility is started in multiton mode or it is started in singleton mode for the first time, the [PageAbility lifecycle callbacks](pageability-lifecycle.md#table13118194914476) are triggered. When it is not started for the first time in singleton mode, the **onNewWant()** callback (as described in the table below) is triggered, but the **onCreate()** callback is not. + **Table 2** Callbacks specific to the singleton mode diff --git a/en/application-dev/application-models/process-model-stage.md b/en/application-dev/application-models/process-model-stage.md index bbfa0602aecb127c5e484f0ebbdcb166f81310f7..03da480722de124a1ede58da52e74cd48c5f23f0 100644 --- a/en/application-dev/application-models/process-model-stage.md +++ b/en/application-dev/application-models/process-model-stage.md @@ -15,7 +15,8 @@ The OpenHarmony process model is shown below. > NOTE > -> You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications. +> - You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications. +> - To view information about all running processes, run the **hdc shell** command to enter the shell CLI of the device, and run the **ps -ef** command. A system application can apply for multi-process permissions (as shown in the following figure) and configure a custom process for an HAP. UIAbility, DataShareExtensionAbility, and ServiceExtensionAbility in the HAP run in the custom process. Different HAPs run in different processes by configuring different process names. diff --git a/en/application-dev/application-models/redirection-rules.md b/en/application-dev/application-models/redirection-rules.md index d7456653640942bca333a28f7f6d5262ec4d63f3..12926c13985dbc2a535206aa4f998df2c44b2ecb 100644 --- a/en/application-dev/application-models/redirection-rules.md +++ b/en/application-dev/application-models/redirection-rules.md @@ -7,13 +7,14 @@ Generally, UI redirection within an application is triggered by users. However, The PageAbility has a UI. It can use **startAbility()** to start an ability that has a UI and is visible to users. -The **visible** field under **abilities** in the **config.json** file specifies whether an ability can be started by other application components. +The **exported** field under **abilities** in the **config.json** file specifies whether an ability can be started by other application components. -**Table 1** Description of visible + +**Table 1** Description of exported | Name| Description| Initial Value Allowed| | -------- | -------- | -------- | -| visible | Whether the ability can be called by other applications.
**true**: The ability can be called by any application.
**false**: The ability can be called only by other components of the same application.| Yes (initial value: **false**)| +| exported | Whether the ability can be called by other applications.
**true**: The ability can be called by any application.
**false**: The ability can be called only by other components of the same application.| Yes (initial value: **false**)| To enable an ability to be called by any application, configure the **config.json** file as follows: @@ -24,7 +25,7 @@ To enable an ability to be called by any application, configure the **config.jso // ... "abilities": [ { - "visible": "true", + "exported": "true", // ... } ] @@ -33,4 +34,4 @@ To enable an ability to be called by any application, configure the **config.jso ``` -If the ability contains **skills**, you are advised to set **visible** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **visible** set to **false** are home screen, voice assistant, or search assistant. +If the ability contains **skills**, you are advised to set **exported** to **true** so that the ability can be [implicitly started](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want) by other applications. If this attribute is set to **false**, the system returns **PERMISSION_DENIED** when other applications attempt to start the ability. In this case, a system application can request the [START_INVISIBLE_ABILITY](../security/permission-list.md) permission to start the ability. Example abilities with **exported** set to **false** are home screen, voice assistant, or search assistant. 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/application-models/serviceextensionability.md b/en/application-dev/application-models/serviceextensionability.md index 9ff7a0ae5d6df7574da19565c81411236dba3dda..2e9aaeb48100d86d0cd1c7a0e69ea01bf4ef2340 100644 --- a/en/application-dev/application-models/serviceextensionability.md +++ b/en/application-dev/application-models/serviceextensionability.md @@ -1,125 +1,151 @@ # ServiceExtensionAbility +## Overview -[ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) is an ExtensionAbility component of the service type that provides extension capabilities related to background services. +[ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) is an ExtensionAbility component of the SERVICE type that provides capabilities related to background services. It holds an internal [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md), through which a variety of APIs are provided for external systems. +In this document, the started ServiceExtensionAbility component is called the server, and the component that starts ServiceExtensionAbility is called the client. -ServiceExtensionAbility can be started or connected by other application components to process transactions in the background based on the request of the caller. System applications can call the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability) method to start background services or call the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability) method to connect to background services. Third-party applications can call only **connectServiceExtensionAbility()** to connect to background services. The differences between starting and connecting to background services are as follows: +A ServiceExtensionAbility can be started or connected by other components to process transactions in the background based on the request of the caller. System applications can call the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method to start background services or call the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to background services. Third-party applications can call only **connectServiceExtensionAbility()** to connect to background services. The differences between starting and connecting to background services are as follows: +- **Starting**: In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB can still exist. -- In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB can still exist. +- **Connecting**: In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also exits. -- In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also exits. +Note the following: +- If a ServiceExtensionAbility is started only by means of connecting, its lifecycle is controlled by the client. A new connection is set up each time the client calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method. When the client exits or calls the [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextdisconnectserviceextensionability) method, the connection is disconnected. After all connections are disconnected, the ServiceExtensionAbility automatically exits. -Each type of ExtensionAbility has its own context. ServiceExtensionAbility has [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md). In this document, the started ServiceExtensionAbility component is called the server, and the component that starts ServiceExtensionAbility is called the client. - - -This topic describes how to use ServiceExtensionAbility in the following scenarios: - - -- [Implementing a Background Service (for System Applications Only)](#implementing-a-background-service-for-system-applications-only) - -- [Starting a Background Service (for System Applications Only)](#starting-a-background-service-for-system-applications-only) - -- [Connecting to a Background Service](#connecting-to-a-background-service) - +- Once a ServiceExtensionAbility is started by means of starting, it will not exit automatically. System applications can call the [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstopserviceextensionability) method to stop it. > **NOTE** -> - OpenHarmony does not support third-party applications in implementing ServiceExtensionAbility. If you want to implement transaction processing in the background, use background tasks. For details, see [Background Task](../task-management/background-task-overview.md). -> +> +> - Currently, third-party applications cannot implement ServiceExtensionAbility. If you want to implement transaction processing in the background, use background tasks. For details, see [Background Task](../task-management/background-task-overview.md). > - UIAbility of a third-party application can connect to ServiceExtensionAbility provided by the system through the context. -> > - Third-party applications can connect to ServiceExtensionAbility provided by the system only when they gain focus in the foreground. - -## Implementing a Background Service (for System Applications Only) +## Lifecycle [ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md) provides the callbacks **onCreate()**, **onRequest()**, **onConnect()**, **onDisconnect()**, and **onDestory()**. Override them as required. The following figure shows the lifecycle of ServiceExtensionAbility. - **Figure 1** ServiceExtensionAbility lifecycle +**Figure 1** ServiceExtensionAbility lifecycle ![ServiceExtensionAbility-lifecycle](figures/ServiceExtensionAbility-lifecycle.png) - **onCreate** - - This callback is triggered when a service is created for the first time. You can perform initialization operations, for example, registering a common event listener. + + This callback is triggered when a ServiceExtensionAbility is created for the first time. You can perform initialization operations, for example, registering a common event listener. > **NOTE** > - > If a service has been created, starting it again does not trigger the **onCreate()** callback. + > If a ServiceExtensionAbility has been created, starting it again does not trigger the **onCreate()** callback. - **onRequest** - - This callback is triggered when another component calls the **startServiceExtensionAbility()** method to start the service. After being started, the service runs in the background. + + This callback is triggered when another component calls the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method to start a ServiceExtensionAbility. After being started, the ServiceExtensionAbility runs in the background. This callback is triggered each time the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartserviceextensionability) method is called. - **onConnect** - - This callback is triggered when another component calls the **connectServiceExtensionAbility()** method to connect to the service. In this method, a remote proxy object (IRemoteObject) is returned, through which the client communicates with the server by means of RPC. + + This callback is triggered when another component calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to a ServiceExtensionAbility. In this method, a remote proxy object (IRemoteObject) is returned, through which the client communicates with the server by means of RPC. At the same time, the system stores the remote proxy object (IRemoteObject). If another component calls the [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability) method to connect to this ServiceExtensionAbility, the system directly returns the saved remote proxy object (IRemoteObject) and does not trigger the callback. - **onDisconnect** - - This callback is triggered when a component calls the **disconnectServiceExtensionAbility()** method to disconnect from the service. + + This callback is triggered when the last connection is disconnected. A connection is disconnected when the client exits or the [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextdisconnectserviceextensionability) method is called. - **onDestroy** - This callback is triggered when the service is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregister the listener. + This callback is triggered when ServiceExtensionAbility is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregister the listener. +## Implementing a Background Service (for System Applications Only) -## How to Develop +### Preparations -To implement a background service, manually create a ServiceExtensionAbility component in DevEco Studio. The procedure is as follows: +Only system applications can implement ServiceExtensionAbility. You must make the following preparations before development: -1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **serviceextability**. +- **Switching to the full SDK**: All APIs related to ServiceExtensionAbility are marked as system APIs and hidden by default. Therefore, you must manually obtain the full SDK from the mirror and switch to it in DevEco Studio. For details, see [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md). -2. In the **serviceextability** directory, right-click and choose **New > TypeScript File** to create a file named **ServiceExtAbility.ts**. +- **Requesting the AllowAppUsePrivilegeExtension privilege**: Only applications with the **AllowAppUsePrivilegeExtension** privilege can develop ServiceExtensionAbility. For details about how to request the privilege, see [Application Privilege Configuration Guide](../../device-dev/subsystems/subsys-app-privilege-config-guide.md). -3. Open the **ServiceExtAbility.ts** file, import the [RPC module](../reference/apis/js-apis-rpc.md), and reload the **onRemoteMessageRequest()** method to receive messages from the client and return the processing result to the client. **REQUEST_VALUE** is used to verify the service request code sent by the client. - - ```ts - import rpc from '@ohos.rpc'; - - const REQUEST_CODE = 99; - - class StubTest extends rpc.RemoteObject { - constructor(des) { - super(des); - } - - // Receive a message from the client and return the processing result to the client. - onRemoteMessageRequest(code, data, reply, option) { - if (code === REQUEST_CODE) { - // Receive data from the client. - // If the client calls data.writeInt() multiple times to write multiple pieces of data, the server can call data.readInt() multiple times to receive all the data. - let optFir = data.readInt(); - let optSec = data.readInt(); - // The server returns the data processing result to the client. - // In the example, the server receives two pieces of data and returns the sum of the two pieces of data to the client. - reply.writeInt(optFir + optSec); - } - return true; - } - - // Send messages to the client in synchronous or asynchronous mode. - sendRequest(code, data, reply, options) { - return null; - } - } - ``` +### Defining IDL Interfaces + +As a background service, ServiceExtensionAbility needs to provide interfaces that can be called by external systems. You can define the interfaces in IDL files and use the [IDL tool](../IDL/idl-guidelines.md) to generate proxy and stub files. The following demonstrates how to define a file named **IIdlServiceExt.idl**: + +```cpp +interface OHOS.IIdlServiceExt { + int ProcessData([in] int data); + void InsertDataToMap([in] String key, [in] int val); +} +``` + +Create the **IdlServiceExt** directory in the **ets** directory corresponding to the module of the DevEco Studio project, and copy the files generated by the [IDL tool](../IDL/idl-guidelines.md) to this directory. Then create a file named **idl_service_ext_impl.ts** to implement the IDL interfaces. + +``` +├── ets +│ ├── IdlServiceExt +│ │ ├── i_idl_service_ext.ts # File generated. +│ │ ├── idl_service_ext_proxy.ts # File generated. +│ │ ├── idl_service_ext_stub.ts # File generated. +│ │ ├── idl_service_ext_impl.ts # Custom file used to implement IDL interfaces. +│ └ +└ +``` + +An example of **idl_service_ext_impl.ts** is as follows: + +```ts +import {processDataCallback} from './i_idl_service_ext'; +import {insertDataToMapCallback} from './i_idl_service_ext'; +import IdlServiceExtStub from './idl_service_ext_stub'; + +const ERR_OK = 0; +const TAG: string = "[IdlServiceExtImpl]"; + +// You need to implement interfaces in this type. +export default class ServiceExtImpl extends IdlServiceExtStub { + processData(data: number, callback: processDataCallback): void { + // Implement service logic. + console.info(TAG, `processData: ${data}`); + callback(ERR_OK, data + 1); + } + + insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void { + // Implement service logic. + console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`); + callback(ERR_OK); + } +} +``` + +### Creating a ServiceExtensionAbility + +To manually create a ServiceExtensionAbility in the DevEco Studio project, perform the following steps: + +1. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **ServiceExtAbility**. + +2. In the **ServiceExtAbility** directory, right-click and choose **New > TypeScript File** to create a file named **ServiceExtAbility.ts**. + + ``` + ├── ets + │ ├── IdlServiceExt + │ │ ├── i_idl_service_ext.ts # File generated. + │ │ ├── idl_service_ext_proxy.ts # File generated. + │ │ ├── idl_service_ext_stub.ts # File generated. + │ │ ├── idl_service_ext_impl.ts # Custom file used to implement IDL interfaces. + │ ├── ServiceExtAbility + │ │ ├── ServiceExtAbility.ts + └ + ``` + +3. In the **ServiceExtAbility.ts** file, add the dependency package for importing ServiceExtensionAbility. Customize a class that inherits from ServiceExtensionAbility and implement the lifecycle callbacks, and return the previously defined **ServiceExtImpl** object in the **onConnect** lifecycle callback. -4. In the **ServiceExtAbility.ts** file, add the dependency package for importing ServiceExtensionAbility. Customize a class that inherits from ServiceExtensionAbility and add the required lifecycle callbacks. - ```ts import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'; - import rpc from '@ohos.rpc'; - - const TAG: string = "[Example].[Entry].[ServiceExtAbility]"; - const REQUEST_CODE = 99; + import ServiceExtImpl from '../IdlServiceExt/idl_service_ext_impl'; - class StubTest extends rpc.RemoteObject { - // ... - } + const TAG: string = "[ServiceExtAbility]"; export default class ServiceExtAbility extends ServiceExtensionAbility { + serviceExtImpl = new ServiceExtImpl("ExtImpl"); + onCreate(want) { console.info(TAG, `onCreate, want: ${want.abilityName}`); } @@ -130,7 +156,8 @@ To implement a background service, manually create a ServiceExtensionAbility com onConnect(want) { console.info(TAG, `onConnect, want: ${want.abilityName}`); - return new StubTest("test"); + // Return the ServiceExtImpl object, through which the client can communicate with the ServiceExtensionAbility. + return this.serviceExtImpl; } onDisconnect(want) { @@ -143,8 +170,8 @@ To implement a background service, manually create a ServiceExtensionAbility com } ``` -5. Register ServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"service"** and **srcEntrance** to the code path of the ExtensionAbility component. - +4. Register ServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"service"** and **srcEntry** to the code path of the ServiceExtensionAbility component. + ```json { "module": { @@ -155,15 +182,14 @@ To implement a background service, manually create a ServiceExtensionAbility com "icon": "$media:icon", "description": "service", "type": "service", - "visible": true, - "srcEntrance": "./ets/serviceextability/ServiceExtAbility.ts" + "exported": true, + "srcEntry": "./ets/ServiceExtAbility/ServiceExtAbility.ts" } ] } } ``` - ## Starting a Background Service (for System Applications Only) A system application uses the [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability) method to start a background service. The [onRequest()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonrequest) callback is invoked, and the **Want** object passed by the caller is received through the callback. After the background service is started, its lifecycle is independent of that of the client. In other words, even if the client is destroyed, the background service can still run. Therefore, the background service must be stopped by calling [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) when its work is complete. Alternatively, another component can call [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability) to stop the background service. @@ -173,7 +199,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis > [startServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartserviceextensionability), [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability), and [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) of ServiceExtensionContext are system APIs and cannot be called by third-party applications. 1. Start a new ServiceExtensionAbility in a system application. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). - + ```ts let want = { "deviceId": "", @@ -188,7 +214,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis ``` 2. Stop ServiceExtensionAbility in the system application. - + ```ts let want = { "deviceId": "", @@ -203,7 +229,7 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis ``` 3. ServiceExtensionAbility stops itself. - + ```ts // this is the current ServiceExtensionAbility component. this.context.terminateSelf().then(() => { @@ -213,35 +239,71 @@ A system application uses the [startServiceExtensionAbility()](../reference/apis }) ``` - > **NOTE** > > Background services can run in the background for a long time. To minimize resource usage, destroy it in time when a background service finishes the task of the requester. A background service can be stopped in either of the following ways: > > - The background service calls the [terminateSelf()](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself) method to automatically stop itself. -> > - Another component calls the [stopServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstopserviceextensionability) method to stop the background service. -> > After either method is called, the system destroys the background service. - ## Connecting to a Background Service -Either a system application or a third-party application can connect to a service (service specified in the **Want** object) through [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability). The [onConnect()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonconnect) callback is invoked, and the **Want** object passed by the caller is received through the callback. In this way, a persistent connection is established. +Either a system application or a third-party application can connect to a ServiceExtensionAbility (specified in the **Want** object) through [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability). The [onConnect()](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonconnect) callback is invoked, and the **Want** object passed by the caller is received through the callback. In this way, a persistent connection is established. The ServiceExtensionAbility component returns an IRemoteObject in the **onConnect()** callback. Through this IRemoteObject, you can define communication interfaces for RPC interaction between the client and server. Multiple clients can connect to the same background service at the same time. After a client finishes the interaction, it must call [disconnectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextdisconnectserviceextensionability) to disconnect from the service. If all clients connected to a background service are disconnected, the system destroys the service. - Call **connectServiceExtensionAbility()** to establish a connection to a background service. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). ```ts - import rpc from '@ohos.rpc'; - - const REQUEST_CODE = 99; let want = { "deviceId": "", "bundleName": "com.example.myapplication", "abilityName": "ServiceExtAbility" }; + let options = { + onConnect(elementName, remote) { + /* The input parameter remote is the object returned by ServiceExtensionAbility in the onConnect lifecycle callback. + * This object is used for communication with ServiceExtensionAbility. For details, see the section below. + */ + console.info('onConnect callback'); + if (remote === null) { + console.info(`onConnect remote is null`); + return; + } + }, + onDisconnect(elementName) { + console.info('onDisconnect callback') + }, + onFailed(code) { + console.info('onFailed callback') + } + } + // The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection. + let connectionId = this.context.connectServiceExtensionAbility(want, options); + ``` + +- Use **disconnectServiceExtensionAbility()** to disconnect from the background service. + + ```ts + // connectionId is returned when connectServiceExtensionAbility is called and needs to be manually maintained. + this.context.disconnectServiceExtensionAbility(connectionId).then((data) => { + console.info('disconnectServiceExtensionAbility success'); + }).catch((error) => { + console.error('disconnectServiceExtensionAbility failed'); + }) + ``` + +## Communication Between the Client and Server + +After obtaining the [rpc.RemoteObject](../reference/apis/js-apis-rpc.md#iremoteobject) object from the **onConnect()** callback, the client can communicate with ServiceExtensionAbility in either of the following ways: + +- Using the IDL interface provided by the server for communication (recommended) + + ```ts + // The client needs to import idl_service_ext_proxy.ts provided by the server for external systems to the local project. + import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy'; + let options = { onConnect(elementName, remote) { console.info('onConnect callback'); @@ -249,23 +311,54 @@ The ServiceExtensionAbility component returns an IRemoteObject in the **onConnec console.info(`onConnect remote is null`); return; } + let serviceExtProxy = new IdlServiceExtProxy(remote); + // Communication is carried out by interface calling, without exposing RPC details. + serviceExtProxy.processData(1, (errorCode, retVal) => { + console.log(`processData, errorCode: ${errorCode}, retVal: ${retVal}`); + }); + serviceExtProxy.insertDataToMap('theKey', 1, (errorCode) => { + console.log(`insertDataToMap, errorCode: ${errorCode}`); + }) + }, + onDisconnect(elementName) { + console.info('onDisconnect callback') + }, + onFailed(code) { + console.info('onFailed callback') + } + } + ``` + +- Calling [sendMessageRequest](../reference/apis/js-apis-rpc.md#sendmessagerequest9) to send messages to the server (not recommended) + + ```ts + import rpc from '@ohos.rpc'; + + const REQUEST_CODE = 1; + let options = { + onConnect(elementName, remote) { + console.info('onConnect callback'); + if (remote === null) { + console.info(`onConnect remote is null`); + return; + } + // Directly call the RPC interface to send messages to the server. The client needs to serialize the input parameters and deserialize the return values. The process is complex. let option = new rpc.MessageOption(); - let data = new rpc.MessageParcel(); - let reply = new rpc.MessageParcel(); + let data = new rpc.MessageSequence(); + let reply = new rpc.MessageSequence(); data.writeInt(100); - data.writeInt(200); - + // @param code Indicates the service request code sent by the client. - // @param data Indicates the {@link MessageParcel} object sent by the client. + // @param data Indicates the {@link MessageSequence} object sent by the client. // @param reply Indicates the response message object sent by the remote service. // @param options Specifies whether the operation is synchronous or asynchronous. // // @return Returns {@code true} if the operation is successful; returns {@code false} otherwise. - remote.sendRequest(REQUEST_CODE, data, reply, option).then((ret) => { + remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret) => { let msg = reply.readInt(); - console.info(`sendRequest ret:${ret} msg:${msg}`); + console.info(`sendMessageRequest ret:${ret} msg:${msg}`); }).catch((error) => { - console.info('sendRequest failed'); + console.info('sendMessageRequest failed'); }); }, onDisconnect(elementName) { @@ -275,18 +368,90 @@ The ServiceExtensionAbility component returns an IRemoteObject in the **onConnec console.info('onFailed callback') } } - // The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection. - let connectionId = this.context.connectServiceExtensionAbility(want, options); ``` -- Use **disconnectServiceExtensionAbility()** to disconnect from the background service. - +## Client Identity Verification by the Server + +When ServiceExtensionAbility is used to provide sensitive services, the client identity must be verified. You can implement the verification on the stub of the IDL interface. For details about the IDL interface implementation, see [Defining IDL Interfaces](#defining-idl-interfaces). Two verification modes are recommended: + +- **Verifying the client identity based on callerUid** + + Call the [getCallingUid()](../reference/apis/js-apis-rpc.md#getcallinguid) method to obtain the UID of the client, and then call the [getBundleNameByUid()](../reference/apis/js-apis-bundleManager.md#bundlemanagergetbundlenamebyuid) method to obtain the corresponding bundle name. In this way, the client identify is verified. Note that [getBundleNameByUid()](../reference/apis/js-apis-bundleManager.md#bundlemanagergetbundlenamebyuid) is asynchronous, and therefore the server cannot return the verification result to the client. This verification mode applies when the client sends an asynchronous task execution request to the server. The sample code is as follows: + ```ts - let connectionId = 1 // ID returned when the service is connected through connectServiceExtensionAbility. - this.context.disconnectServiceExtensionAbility(connectionId).then((data) => { - console.info('disconnectServiceExtensionAbility success'); - }).catch((error) => { - console.error('disconnectServiceExtensionAbility failed'); - }) + import rpc from '@ohos.rpc'; + import bundleManager from '@ohos.bundle.bundleManager'; + import {processDataCallback} from './i_idl_service_ext'; + import {insertDataToMapCallback} from './i_idl_service_ext'; + import IdlServiceExtStub from './idl_service_ext_stub'; + + const ERR_OK = 0; + const ERR_DENY = -1; + const TAG: string = "[IdlServiceExtImpl]"; + + export default class ServiceExtImpl extends IdlServiceExtStub { + processData(data: number, callback: processDataCallback): void { + console.info(TAG, `processData: ${data}`); + + let callerUid = rpc.IPCSkeleton.getCallingUid(); + bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => { + console.info(TAG, 'getBundleNameByUid: ' + callerBundleName); + // Identify the bundle name of the client. + if (callerBundleName != 'com.example.connectextapp') { // The verification fails. + console.info(TAG, 'The caller bundle is not in whitelist, reject'); + return; + } + // The verification is successful, and service logic is executed normally. + }).catch(err => { + console.info(TAG, 'getBundleNameByUid failed: ' + err.message); + }); + } + + insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void { + // Implement service logic. + console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`); + callback(ERR_OK); + } + } + ``` + +- **Verifying the client identity based on callerTokenId** + + Call the [getCallingTokenId()](../reference/apis/js-apis-rpc.md#getcallingtokenid) method to obtain the token ID of the client, and then call the [verifyAccessTokenSync()](../reference/apis/js-apis-abilityAccessCtrl.md#verifyaccesstokensync) method to check whether the client has a specific permission. Currently, OpenHarmony does not support permission customization. Therefore, only [system-defined permissions](../security/permission-list.md) can be verified. The sample code is as follows: + + ```ts + import rpc from '@ohos.rpc'; + import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; + import {processDataCallback} from './i_idl_service_ext'; + import {insertDataToMapCallback} from './i_idl_service_ext'; + import IdlServiceExtStub from './idl_service_ext_stub'; + + const ERR_OK = 0; + const ERR_DENY = -1; + const TAG: string = "[IdlServiceExtImpl]"; + + export default class ServiceExtImpl extends IdlServiceExtStub { + processData(data: number, callback: processDataCallback): void { + console.info(TAG, `processData: ${data}`); + + let callerTokenId = rpc.IPCSkeleton.getCallingTokenId(); + let accessManger = abilityAccessCtrl.createAtManager(); + // The permission to be verified varies depending on the service requirements. ohos.permission.SET_WALLPAPER is only an example. + let grantStatus = + accessManger.verifyAccessTokenSync(callerTokenId, "ohos.permission.SET_WALLPAPER"); + if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { + console.info(TAG, `PERMISSION_DENIED`); + callback(ERR_DENY, data); // The verification fails and an error is returned. + return; + } + callback(ERR_OK, data + 1); // The verification is successful, and service logic is executed normally. + } + + insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void { + // Implement service logic. + console.log(TAG, `insertDataToMap, key: ${key} val: ${val}`); + callback(ERR_OK); + } + } ``` diff --git a/en/application-dev/application-models/start-page.md b/en/application-dev/application-models/start-page.md index 58966d93cba037eaad141caaed0feaaaa672cde1..4296d832fdaafaba67544e8e62b5c7c08395ecdf 100644 --- a/en/application-dev/application-models/start-page.md +++ b/en/application-dev/application-models/start-page.md @@ -12,7 +12,7 @@ import featureAbility from '@ohos.ability.featureAbility'; async function restartAbility() { let wantInfo = { bundleName: "com.sample.MyApplication", - abilityName: "EntryAbility", + abilityName: "MainAbility", parameters: { page: "pages/second" } @@ -70,7 +70,7 @@ struct Index { ``` -When the launch type of a PageAbility is set to **standard** or when the PageAbility with the launch type set to **singleton** is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page. +When a PageAbility in multiton mode is started or when the PageAbility in singleton mode is started for the first time, you can use the **parameters** parameter in **want** to transfer the pages information and use the **startAbility()** method to start the PageAbility. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). The target PageAbility can use the **featureAbility.getWant()** method in **onCreate** to obtain the **want** parameter, and then call **router.push** to start a specified page. When a user touches the button on the page of the caller PageAbility, the **startAbility()** method is called to start the target PageAbility. The **want** parameter in **startAbility()** carries the specified page information. @@ -89,7 +89,7 @@ struct Index { featureAbility.startAbility({ want: { bundleName: "com.exm.myapplication", - abilityName: "com.exm.myapplication.EntryAbility", + abilityName: "com.exm.myapplication.MainAbility", parameters: { page: "pages/page1" } } }).then((data) => { @@ -104,7 +104,7 @@ struct Index { featureAbility.startAbility({ want: { bundleName: "com.exm.myapplication", - abilityName: "com.exm.myapplication.EntryAbility", + abilityName: "com.exm.myapplication.MainAbility", parameters: { page: "pages/page2" } } }).then((data) => { diff --git a/en/application-dev/application-models/thread-model-stage.md b/en/application-dev/application-models/thread-model-stage.md index deaab60b7bd7549dcb96bc00d7896d5c67e5c5d2..4ca9fb3ed369f78cf12054c7b6da085b8640b1db 100644 --- a/en/application-dev/application-models/thread-model-stage.md +++ b/en/application-dev/application-models/thread-model-stage.md @@ -2,19 +2,14 @@ For an OpenHarmony application, each process has a main thread to provide the following functionalities: -- Manage other threads. - -- Enable multiple UIAbility components of the same application to share the same main thread. - -- Distribute input events. - - Draw the UI. - -- Invoke application code callbacks (event processing and lifecycle callbacks). - +- Manage the ArkTS engine instance of the main thread so that multiple UIAbility components can run on it. +- Manage ArkTS engine instances of other threads (such as the worker thread), for example, starting and terminating other threads. +- Distribute interaction events. +- Process application code callbacks (event processing and lifecycle management). - Receive messages sent by the worker thread. -In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. It cannot directly operate the UI. The worker thread is created in the main thread and is independent of the main thread. A maximum of seven worker threads can be created. +In addition to the main thread, there is an independent thread, named worker. The worker thread is mainly used to perform time-consuming operations. The worker thread is created in the main thread and is independent from the main thread. It cannot directly operate the UI. A maximum of seven worker threads can be created. ![thread-model-stage](figures/thread-model-stage.png) @@ -22,4 +17,5 @@ Based on the OpenHarmony thread model, different services run on different threa > **NOTE** > -> The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread. +> - The stage model provides only the main thread and worker thread. Emitter is mainly used for event synchronization within the main thread or between the main thread and worker thread. +> - To view thread information about an application process, run the **hdc shell** command to enter the shell CLI of the device, and then run the **ps -p ** -T command**, where ** indicates the ID of the application process. diff --git a/en/application-dev/application-models/uiability-intra-device-interaction.md b/en/application-dev/application-models/uiability-intra-device-interaction.md index 5ea819219e45d219e68aee7f34988f4822dda5a9..148e804f48531f286ecfe395d1ecd03464a5eb45 100644 --- a/en/application-dev/application-models/uiability-intra-device-interaction.md +++ b/en/application-dev/application-models/uiability-intra-device-interaction.md @@ -38,7 +38,7 @@ Assume that your application has two UIAbility components: EntryAbility and Func info: 'From the Index page of EntryAbility', }, } - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbility(wantInfo).then(() => { // ... }).catch((err) => { @@ -65,7 +65,7 @@ Assume that your application has two UIAbility components: EntryAbility and Func 3. To stop the **UIAbility** instance after the FuncAbility service is complete, call **terminateSelf()** in FuncAbility. ```ts - // context is the UIAbilityContext of the UIAbility instance to stop. + // context is the AbilityContext of the UIAbility instance to stop. this.context.terminateSelf((err) => { // ... }); @@ -88,7 +88,7 @@ When starting FuncAbility from EntryAbility, you want the result to be returned info: 'From the Index page of EntryAbility', }, } - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbilityForResult(wantInfo).then((data) => { // ... }).catch((err) => { @@ -124,7 +124,7 @@ When starting FuncAbility from EntryAbility, you want the result to be returned // ... - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbilityForResult(want).then((data) => { if (data?.resultCode === RESULT_CODE) { // Parse the information returned by the target UIAbility. @@ -187,7 +187,7 @@ This section describes how to start the UIAbility of another application through entities: ['entity.system.default'], } - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbility(wantInfo).then(() => { // ... }).catch((err) => { @@ -251,7 +251,7 @@ If you want to obtain the return result when using implicit Want to start the UI entities: ['entity.system.default'], } - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbilityForResult(wantInfo).then((data) => { // ... }).catch((err) => { @@ -289,7 +289,7 @@ If you want to obtain the return result when using implicit Want to start the UI // Want parameter information. }; - // context is the UIAbilityContext of the initiator UIAbility. + // context is the AbilityContext of the initiator UIAbility. this.context.startAbilityForResult(want).then((data) => { if (data?.resultCode === RESULT_CODE) { // Parse the information returned by the target UIAbility. @@ -322,7 +322,7 @@ let wantInfo = { router: 'funcA', }, } -// context is the UIAbilityContext of the initiator UIAbility. +// context is the AbilityContext of the initiator UIAbility. this.context.startAbility(wantInfo).then(() => { // ... }).catch((err) => { @@ -500,12 +500,12 @@ For the CalleeAbility, implement the callback to receive data and the methods to ```json "abilities":[{ "name": ".CalleeAbility", - "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", + "srcEnty": "./ets/CalleeAbility/CalleeAbility.ts", "launchType": "singleton", "description": "$string:CalleeAbility_desc", "icon": "$media:icon", "label": "$string:CalleeAbility_label", - "visible": true + "exported": true }] ``` @@ -596,7 +596,7 @@ For the CalleeAbility, implement the callback to receive data and the methods to 2. Obtain the caller interface. - The **UIAbilityContext** attribute implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **UIAbilityContext**, uses **startAbilityByCall** to start the CalleeAbility, obtain the caller object, and register the **onRelease** listener of the CallerAbility. You need to implement processing based on service requirements. + The **context** attribute of the UIAbility implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the UIAbility, uses **startAbilityByCall** to start the CalleeAbility, obtain the caller object, and register the **onRelease** listener of the CallerAbility. You need to implement processing based on service requirements. ```ts diff --git a/en/application-dev/application-models/uiability-launch-type.md b/en/application-dev/application-models/uiability-launch-type.md index cf185cd9dad9593534afef59babe5cbf37585cae..ff904d4f60918a5ceed622840d5a153e52f8d1a4 100644 --- a/en/application-dev/application-models/uiability-launch-type.md +++ b/en/application-dev/application-models/uiability-launch-type.md @@ -6,7 +6,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility - [Singleton](#singleton) -- [Standard](#standard) +- [Multiton](#multiton) - [Specified](#specified) @@ -18,8 +18,7 @@ The launch type of the UIAbility component refers to the state of the UIAbility Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, if a UIAbility instance of this type already exists in the application process, the instance is reused. Therefore, only one UIAbility instance of this type exists in the system, that is, displayed in **Recents**. **Figure 1** Demonstration effect in singleton mode - -![uiability-launch-type1](figures/uiability-launch-type1.png) +![uiability-launch-type1](figures/uiability-launch-type1.gif) > **NOTE** > @@ -43,15 +42,15 @@ To use the singleton mode, set **launchType** in the [module.json5 configuration ``` -## Standard +## Multiton -In standard mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**. +In multiton mode, each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, a new UIAbility instance of this type is created in the application process. Multiple UIAbility instances of this type are displayed in **Recents**. -**Figure 2** Demonstration effect in standard mode +**Figure 2** Demonstration effect in multiton mode -![standard-mode](figures/standard-mode.png) +![uiability-launch-type2](figures/uiability-launch-type2.gif) -To use the standard mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **standard**. +To use the multiton mode, set **launchType** in the [module.json5 file](../quick-start/module-configuration-file.md) to **multiton**. ```json @@ -60,7 +59,7 @@ To use the standard mode, set **launchType** in the [module.json5 configuration // ... "abilities": [ { - "launchType": "standard", + "launchType": "multiton", // ... } ] @@ -73,14 +72,13 @@ To use the standard mode, set **launchType** in the [module.json5 configuration The **specified** mode is used in some special scenarios. For example, in a document application, you want a document instance to be created each time you create a document, but you want to use the same document instance when you repeatedly open an existing document. -**Figure 3** Demonstration effect in specified mode - -![uiability-launch-type2](figures/uiability-launch-type2.png) +**Figure 3** Demonstration effect in specified mode +![uiability-launch-type3](figures/uiability-launch-type3.gif) For example, there are two UIAbility components: EntryAbility and SpecifiedAbility (with the launch type **specified**). You are required to start SpecifiedAbility from EntryAbility. 1. In SpecifiedAbility, set the **launchType** field in the [module.json5 file](../quick-start/module-configuration-file.md) to **specified**. - + ```json { "module": { @@ -95,8 +93,8 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili } ``` -2. Create a unique string key for the instance. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application, based on the key, identifies the UIAbility instance used to respond to the request. In EntryAbility, add a custom parameter, for example, **instanceKey**, to the [want](want-overview.md) parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instance. - +2. Create a unique string key for the instance. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application, based on the key, identifies the UIAbility instance used to respond to the request. In EntryAbility, add a custom parameter, for example, **instanceKey**, to the **want** parameter in [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) to distinguish the UIAbility instance. + ```ts // Configure an independent key for each UIAbility instance. // For example, in the document usage scenario, use the document path as the key. @@ -120,10 +118,11 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili // ... }) ``` - -3. During running, the internal service of UIAbility determines whether to create multiple instances. If the key is matched, the UIAbility instance bound to the key is started. Otherwise, a new UIAbility instance is created. - The launch type of SpecifiedAbility is set to **specified**. Before SpecifiedAbility is started, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the corresponding AbilityStage instance is invoked to parse the input **want** parameter and obtain the custom parameter **instanceKey**. A string key identifier is returned through the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the AbilityStage instance. [If the returned key corresponds to a started UIAbility instance](mission-management-launch-type.md#fig14520125175314), that UIAbility instance is switched to the foreground and gains focus again. Otherwise, a new instance is created and started. - + +3. Before SpecifiedAbility is started, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of the corresponding AbilityStage instance is invoked to obtain the key of the UIAbility, because the launch type of SpecifiedAbility is set to **specified**. If a UIAbility instance matching the key exists, the system starts the UIAbility instance and invokes its [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback. Otherwise, the system creates a new UIAbility instance and invokes its [onCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate) and [onWindowStageCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate) callbacks. + + In the sample code, the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback parses the **want** parameter to obtain the custom parameter **instanceKey**. The service logic returns a key string based on **instanceKey** parameter to identify the UIAbility instance. If the returned key maps to a started UIAbility instance, the system pulls the UIAbility instance back to the foreground and obtains the focus. If the returned key does not map to a started UIAbility instance, the system creates a new UIAbility instance and starts it. + ```ts import AbilityStage from '@ohos.app.ability.AbilityStage'; @@ -140,12 +139,12 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili } } ``` - + > **NOTE** > > 1. Assume that the application already has a UIAbility instance created, and the launch type of the UIAbility instance is set to **specified**. If [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called again to start the UIAbility instance, and the [onAcceptWant()](../reference/apis/js-apis-app-ability-abilityStage.md#abilitystageonacceptwant) callback of [AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md) matches a created UIAbility instance, the original UIAbility instance is started, and no new UIAbility instance is created. In this case, the [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback is invoked, but the [onCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate) and [onWindowStageCreate()](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate) callbacks are not. > 2. AbilityStage is not automatically generated in the default project of DevEco Studio. For details about how to create an AbilityStage file, see [AbilityStage Component Container](abilitystage.md). - + For example, in the document application, different keys are bound to different document instances. Each time a document is created, a new key (for example, file path) is passed, and a new UIAbility instance is created when UIAbility is started in AbilityStage. However, when you open an existing document, the same UIAbility instance is started again in AbilityStage. The following steps are used as an example. @@ -153,6 +152,4 @@ For example, there are two UIAbility components: EntryAbility and SpecifiedAbili 1. Open file A. A UIAbility instance, for example, UIAbility instance 1, is started. 2. Close the process of file A in **Recents**. UIAbility instance 1 is destroyed. Return to the home screen and open file A again. A new UIAbility instance is started, for example, UIAbility instance 2. 3. Return to the home screen and open file B. A new UIAbility instance is started, for example, UIAbility instance 3. - 4. Return to the home screen and open file A again. UIAbility instance 2 is started. - - \ No newline at end of file + 4. Return to the home screen and open file A again. UIAbility instance 2 is started. This is because the system automatically matches the key of the UIAbility instance and starts the UIAbility instance that has a matching key. In this example, UIAbility instance 2 has the same key as file A. Therefore, the system pulls back UIAbility instance 2 and focuses it without creating a new instance. diff --git a/en/application-dev/application-models/uiability-overview.md b/en/application-dev/application-models/uiability-overview.md index cd059b9555bfd80c02c9bce66f4c50cd58fff568..7862f2038fc6c353629bcdc9b3e51cfb5bedb046 100644 --- a/en/application-dev/application-models/uiability-overview.md +++ b/en/application-dev/application-models/uiability-overview.md @@ -37,7 +37,7 @@ To enable an application to properly use a UIAbility component, declare the UIAb "abilities": [ { "name": "EntryAbility", // Name of the UIAbility component. - "srcEntrance": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component. + "srcEnty": "./ets/entryability/EntryAbility.ts", // Code path of the UIAbility component. "description": "$string:EntryAbility_desc", // Description of the UIAbility component. "icon": "$media:icon", // Icon of the UIAbility component. "label": "$string:EntryAbility_label", // Label of the UIAbility component. diff --git a/en/application-dev/application-models/widget-development-fa.md b/en/application-dev/application-models/widget-development-fa.md index 17f9ee7234865b5d01e2a5f68e52cf7928739db7..73cf20e0ce6ab82ae9e775dd8fb8f43922218b48 100644 --- a/en/application-dev/application-models/widget-development-fa.md +++ b/en/application-dev/application-models/widget-development-fa.md @@ -232,7 +232,7 @@ The widget configuration file is named **config.json**. Find the **config.json** "type": "service", "srcLanguage": "ets", "formsEnabled": true, - "formConfigAbility": "ability://com.example.entry.EntryAbility", + "formConfigAbility": "ability://com.example.entry.MainAbility", "forms": [{ "colorMode": "auto", "defaultDimension": "2*2", @@ -323,7 +323,7 @@ async function deleteFormInfo(formId: string) { // ... ``` -For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). +For details about how to implement persistent data storage, see [Application Data Persistence Overview](../database/app-data-persistence-overview.md). The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary. @@ -364,7 +364,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi > **NOTE** > -> Only the JavaScript-based web-like development paradigm is supported when developing the widget UI. +> In the FA model, only the JavaScript-based web-like development paradigm is supported when developing the widget UI. - HML: uses web-like paradigm components to describe the widget page information. @@ -434,7 +434,7 @@ You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. Thi "actions": { "routerEvent": { "action": "router", - "abilityName": "com.example.entry.EntryAbility", + "abilityName": "com.example.entry.MainAbility", "params": { "message": "add detail" } @@ -452,8 +452,8 @@ You can set router and message events for components on a widget. The router eve 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 created by DevEco Studio in the FA model is com.example.entry.EntryAbility. - - **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the EntryAbility in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field. + - **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name created by DevEco Studio in the FA model is com.example.entry.MainAbility. + - **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the MainAbility in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field. 3. Set the message event. - **action**: **"message"**, which indicates a message event. @@ -529,7 +529,7 @@ The following is an example: "actions": { "routerEvent": { "action": "router", - "abilityName": "com.example.entry.EntryAbility", + "abilityName": "com.example.entry.MainAbility", "params": { "message": "add detail" } @@ -543,4 +543,3 @@ The following is an example: } } ``` - diff --git a/en/application-dev/application-models/widget-switch.md b/en/application-dev/application-models/widget-switch.md index 8d9823385a8a05f71c742327dc966054427a6718..0de83a6593f521e3b51b84dea5ff275e7ee5450f 100644 --- a/en/application-dev/application-models/widget-switch.md +++ b/en/application-dev/application-models/widget-switch.md @@ -11,7 +11,7 @@ Widget switching involves the following parts: | Configuration Item | FA Model | Stage Model | | ---------------- | ------------------------------------------- | ------------------------------------------------------------ | | Configuration item location | **formAbility** and **forms** are in the **config.json** file.| **extensionAbilities** (configuration for **formExtensionAbility**) is in the **module.json5** file in the level-1 directory, and **forms** (configuration for **forms** contained in **formExtensionAbility**) is in the **form_config.json** file in the level-2 directory.| -| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEntrance**, with the file name. | +| Widget code path | Specified by **srcPath**, without the file name. | Specified by **srcEnty**, with the file name. | | Programming language | **srcLanguage** can be set to **js** or **ets**. | This configuration item is unavailable. Only ets is supported. | | Whether to enable widgets | formsEnabled | This configuration item is unavailable. The setting of **type** set to **form** means that the widgets are enabled. | | Ability type | type: service | type: form | @@ -32,7 +32,7 @@ Figure 2 Widget configuration differences | Item| FA Model| Stage Model| | -------- | -------- | -------- | -| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEntrance**| +| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEnty**| | Lifecycle| export default| import FormExtension from '\@ohos.app.form.FormExtensionAbility';
export default class FormAbility extends FormExtension| diff --git a/en/application-dev/application-models/windowextensionability.md b/en/application-dev/application-models/windowextensionability.md index bdbcb65ffca3aa635146cdb8dfa97763ce99d652..a307a1da5e1c21e11b71d054b8300bb35ddf0522 100644 --- a/en/application-dev/application-models/windowextensionability.md +++ b/en/application-dev/application-models/windowextensionability.md @@ -1,5 +1,6 @@ # WindowExtensionAbility + [WindowExtensionAbility](../reference/apis/js-apis-application-windowExtensionAbility.md) is a type of ExtensionAbility component that allows a system application to be embedded in and displayed over another application. @@ -14,7 +15,7 @@ the context is [WindowExtensionContext](../reference/apis/js-apis-inner-applicat > -## Setting an Embedded Ability (for System Applications Only) +## Setting an Embedded UIAbility (for System Applications Only) The **WindowExtensionAbility** class provides **onConnect()**, **onDisconnect()**, and **onWindowReady()** lifecycle callbacks, which can be overridden. @@ -58,7 +59,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i } ``` -4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEntrance** to the code path of the ExtensionAbility component. +4. Register the WindowExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"window"** and **srcEnty** to the code path of the ExtensionAbility component. ```json { @@ -66,11 +67,11 @@ To implement an embedded application, manually create a WindowExtensionAbility i "extensionAbilities": [ { "name": "WindowExtAbility", - "srcEntrance": "./ets/WindowExtAbility/WindowExtAbility.ts", + "srcEnty": "./ets/WindowExtAbility/WindowExtAbility.ts", "icon": "$media:icon", "description": "WindowExtension", "type": "window", - "visible": true, + "exported": true, } ], } @@ -78,7 +79,7 @@ To implement an embedded application, manually create a WindowExtensionAbility i ``` -## Starting an Embedded Ability (for System Applications Only) +## Starting an Embedded UIAbility (for System Applications Only) System applications can load the created WindowExtensionAbility through the AbilityComponent. diff --git a/en/application-dev/database/Readme-EN.md b/en/application-dev/database/Readme-EN.md index b397b5b38682c9910724ea70e4759fe9a9aaf06e..77e1d8f9738d949ce9b0f0396bf66f99b9bf924e 100644 --- a/en/application-dev/database/Readme-EN.md +++ b/en/application-dev/database/Readme-EN.md @@ -5,7 +5,7 @@ - [Overview of Application Data Persistence](app-data-persistence-overview.md) - [Persisting Preferences Data](data-persistence-by-preferences.md) - [Persisting KV Store Data](data-persistence-by-kv-store.md) - - [Persisting RDB Store Data] (data-persistence-by-rdb-store.md) + - [Persisting RDB Store Data](data-persistence-by-rdb-store.md) - Distributed Application Data Synchronization - [Distributed Application Data Synchronization Overview](sync-app-data-across-devices-overview.md) - [Cross-Device Synchronization of KV Stores](data-sync-of-kv-store.md) @@ -16,7 +16,7 @@ - [Database Backup and Restoration](data-backup-and-restore.md) - [Database Encryption](data-encryption.md) - [Access Control by Device and Data Level](access-control-by-device-and-data-level.md) -- Cross-Application Data Sharing (Available Only for System Applications) +- Cross-Application Data Sharing (for System Applications Only) - [Cross-Application Data Sharing Overview](share-device-data-across-apps-overview.md) - [Sharing Data Using DataShareExtensionAbility](share-data-by-datashareextensionability.md) - [Sharing Data in Silent Access](share-data-by-silent-access.md) 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 358661e83d952349220a45c0d8ac065f422e3f70..804fb6b12764b95cec9566bdc165234284d32a8d 100644 --- a/en/application-dev/database/data-persistence-by-kv-store.md +++ b/en/application-dev/database/data-persistence-by-kv-store.md @@ -21,22 +21,24 @@ 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 -1. Create a **KvManager** instance to manage database objects. Example: +1. Create a **KvManager** instance to manage database objects. + + Example: Stage model: - + ```js // Import the module. import distributedKVStore from '@ohos.data.distributedKVStore'; @@ -67,7 +69,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'; @@ -90,8 +92,10 @@ The following table lists the APIs used for KV data persistence. Most of the API } ``` -2. Create and obtain a KV store. Example: - +2. Create and obtain a KV store. + + Example: + ```js try { const options = { @@ -116,8 +120,10 @@ The following table lists the APIs used for KV data persistence. Most of the API } ``` -3. Use **put()** to add data to the KV store. Example: - +3. Use **put()** to add data to the KV store. + + Example: + ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -138,8 +144,10 @@ The following table lists the APIs used for KV data persistence. Most of the API > > The **put()** method adds a KV pair if the specified key does not exists and changes the value if the the specified key already exists. -4. Use **get()** to obtain the value of a key. Example: - +4. Use **get()** to obtain the value of a key. + + Example: + ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; @@ -163,8 +171,10 @@ The following table lists the APIs used for KV data persistence. Most of the API } ``` -5. Use **delete()** to delete the data of the specified key. Example: - +5. Use **delete()** to delete the data of the specified key. + + Example: + ```js const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; diff --git a/en/application-dev/database/data-persistence-by-preferences.md b/en/application-dev/database/data-persistence-by-preferences.md index a0c4aafbae9314363b44cd99e3abc563a21d2abe..87a4fe9c523baffae4b05448fa36eb9d6daf3b99 100644 --- a/en/application-dev/database/data-persistence-by-preferences.md +++ b/en/application-dev/database/data-persistence-by-preferences.md @@ -10,7 +10,9 @@ The **Preferences** module provides APIs for processing data in the form of key- User applications call **Preference** through the JS interface to read and write data files. You can load the data of a **Preferences** persistence file to a **Preferences** instance. Each file uniquely corresponds to an instance. The system stores the instance in memory through a static container until the instance is removed from the memory or the file is deleted. The following figure illustrates how **Preference** works. - **Figure 1** Preferences working mechanism +The preference persistent file of an application is stored in the application sandbox. You can use **context** to obtain the file path. For details, see [Obtaining the Application Development Path](../application-models/application-context-stage.md#obtaining-the-application-development-path). + +**Figure 1** Preferences working mechanism ![preferences](figures/preferences.jpg) @@ -28,23 +30,23 @@ User applications call **Preference** through the JS interface to read and write The following table lists the APIs used for preferences data persistence. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [User Preferences](../reference/apis/js-apis-data-preferences.md). - | API| Description| +| API| Description| | -------- | -------- | -| getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void | Obtain a **Preferences** instance.| -| put(key: string, value: ValueType, callback: AsyncCallback<void>): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data.| -| has(key: string, callback: AsyncCallback<boolean>): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty.| -| get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned.| -| delete(key: string, callback: AsyncCallback<void>): void | Deletes the KV pair with the given key from the **Preferences** instance.| -| flush(callback: AsyncCallback<void>): void | Flushes the data of this **Preferences** instance to a file for data persistence.| -| on(type: 'change', callback: Callback<{ key : string }>): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data.| -| off(type: 'change', callback?: Callback<{ key : string }>): void | Unsubscribes from data changes.| -| deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.| +| getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void | Obtain a **Preferences** instance.| +| put(key: string, value: ValueType, callback: AsyncCallback<void>): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data.| +| has(key: string, callback: AsyncCallback<boolean>): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty.| +| get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned.| +| delete(key: string, callback: AsyncCallback<void>): void | Deletes the KV pair with the given key from the **Preferences** instance.| +| flush(callback: AsyncCallback<void>): void | Flushes the data of this **Preferences** instance to a file for data persistence.| +| on(type: 'change', callback: Callback<{ key : string }>): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data.| +| off(type: 'change', callback?: Callback<{ key : string }>): void | Unsubscribes from data changes.| +| deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.| ## How to Develop 1. Import the **@ohos.data.preferences** module. - + ```js import dataPreferences from '@ohos.data.preferences'; ``` @@ -53,7 +55,7 @@ The following table lists the APIs used for preferences data persistence. Most o Stage model: - + ```js import UIAbility from '@ohos.app.ability.UIAbility'; @@ -77,7 +79,7 @@ The following table lists the APIs used for preferences data persistence. Most o FA model: - + ```js import featureAbility from '@ohos.ability.featureAbility'; @@ -108,7 +110,7 @@ The following table lists the APIs used for preferences data persistence. Most o Example: - + ```js try { preferences.has('startup', function (err, val) { @@ -141,8 +143,10 @@ The following table lists the APIs used for preferences data persistence. Most o 4. Read data. - Use **get()** to obtain the value of the specified key. If the value is null or is not of the default value type, the default data is returned. Example: - + Use **get()** to obtain the value of the specified key. If the value is null or is not of the default value type, the default data is returned. + + Example: + ```js try { preferences.get('startup', 'default', (err, val) => { @@ -157,11 +161,11 @@ The following table lists the APIs used for preferences data persistence. Most o } ``` -5. Deletes data. +5. Delete data. Use delete() to delete a KV pair.
Example: - + ```js try { preferences.delete('startup', (err) => { @@ -232,7 +236,7 @@ The following table lists the APIs used for preferences data persistence. Most o Example: - + ```js try { dataPreferences.deletePreferences(this.context, 'mystore', (err, val) => { @@ -245,4 +249,4 @@ The following table lists the APIs used for preferences data persistence. Most o } catch (err) { console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`); } - ``` + ``` \ No newline at end of file diff --git a/en/application-dev/database/data-persistence-by-rdb-store.md b/en/application-dev/database/data-persistence-by-rdb-store.md index d74e79a53c78d4bc0cc7cb2cb6dd95ea7a9ba1fb..e4ee7a87a0fb3166a0f8c4a617d4cb1a823eb743 100644 --- a/en/application-dev/database/data-persistence-by-rdb-store.md +++ b/en/application-dev/database/data-persistence-by-rdb-store.md @@ -18,7 +18,7 @@ A relational database (RDB) store is used to store data in complex relational mo **RelationalStore** provides APIs for applications to perform data operations. With SQLite as the underlying persistent storage engine, **RelationalStore** provides SQLite database features, including transactions, indexes, views, triggers, foreign keys, parameterized queries, prepared SQL statements, and more. **Figure 1** Working mechanism - + ![relationStore_local](figures/relationStore_local.jpg) @@ -37,15 +37,15 @@ A relational database (RDB) store is used to store data in complex relational mo The following table lists the APIs used for RDB data persistence. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md). -| API| Description| +| API| Description| | -------- | -------- | -| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void | Obtains a **RdbStore** instance to implement RDB store operations. You can set **RdbStore** parameters based on actual requirements and use **RdbStore** APIs to perform data operations.| -| executeSql(sql: string, bindArgs: Array<ValueType>, callback: AsyncCallback<void>):void | Executes an SQL statement that contains specified arguments but returns no value.| -| insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void | Inserts a row of data into a table.| -| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void | Updates data in the RDB store based on the specified **RdbPredicates** instance.| -| delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void | Deletes data from the RDB store based on the specified **RdbPredicates** instance.| -| query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>):void | Queries data in the RDB store based on specified conditions.| -| deleteRdbStore(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes an RDB store.| +| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void | Obtains a **RdbStore** instance to implement RDB store operations. You can set **RdbStore** parameters based on actual requirements and use **RdbStore** APIs to perform data operations.| +| executeSql(sql: string, bindArgs: Array<ValueType>, callback: AsyncCallback<void>):void | Executes an SQL statement that contains specified arguments but returns no value.| +| insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void | Inserts a row of data into a table.| +| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void | Updates data in the RDB store based on the specified **RdbPredicates** instance.| +| delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void | Deletes data from the RDB store based on the specified **RdbPredicates** instance.| +| query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>):void | Queries data in the RDB store based on specified conditions.| +| deleteRdbStore(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes an RDB store.| ## How to Develop @@ -53,7 +53,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP 1. Obtain an **RdbStore** instance.
Example: Stage model: - + ```js import relationalStore from '@ohos.data.relationalStore'; // Import the module. import UIAbility from '@ohos.app.ability.UIAbility'; @@ -84,7 +84,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP FA model: - + ```js import relationalStore from '@ohos.data.relationalStore'; // Import the module. import featureAbility from '@ohos.ability.featureAbility'; @@ -118,8 +118,10 @@ The following table lists the APIs used for RDB data persistence. Most of the AP > > - When an application calls **getRdbStore()** to obtain an RDB store instance for the first time, the corresponding database file is generated in the application sandbox. If you want to move the files of an RDB store to another place for view, you must also move the temporary files with finename extensions **-wal** or **-shm** in the same directory. Once an application is uninstalled, the database files and temporary files generated by the application on the device are also removed. -2. Use **insert()** to insert data to the RDB store. Example: - +2. Use **insert()** to insert data to the RDB store. + + Example: + ```js const valueBucket = { 'NAME': 'Lisa', @@ -133,17 +135,19 @@ The following table lists the APIs used for RDB data persistence. Most of the AP return; } console.info(`Succeeded in inserting data. rowId:${rowId}`); - }) +}) ``` - + > **NOTE** - > +> > **RelationalStore** does not provide explicit flush operations for data persistence. Data inserted by **insert()** is stored in files persistently. - + 3. Modify or delete data based on the specified **Predicates** instance. - Use **update()** to modify data and **delete()** to delete data. Example: - + Use **update()** to modify data and **delete()** to delete data. + + Example: + ```js // Modify data. const valueBucket = { @@ -176,8 +180,10 @@ The following table lists the APIs used for RDB data persistence. Most of the AP 4. Query data based on the conditions specified by **Predicates**. - Use **query()** to query data. The data obtained is returned in a **ResultSet** object. Example: - + Use **query()** to query data. The data obtained is returned in a **ResultSet** object. + + Example: + ```js let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); predicates.equalTo('NAME', 'Rose'); @@ -197,11 +203,13 @@ The following table lists the APIs used for RDB data persistence. Most of the AP 5. Delete the RDB store. - Use **deleteRdbStore()** to delete the RDB store and related database files. Example: + Use **deleteRdbStore()** to delete the RDB store and related database files. + + Example: Stage model: - + ```js import UIAbility from '@ohos.app.ability.UIAbility'; @@ -220,7 +228,7 @@ The following table lists the APIs used for RDB data persistence. Most of the AP FA model: - + ```js import featureAbility from '@ohos.ability.featureAbility'; 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 f6b2d2c55dca745843d55d37bc3a96166bc3e4ff..a32e605f9c358e83b47660d12a32eeb29d677851 100644 --- a/en/application-dev/database/data-sync-of-kv-store.md +++ b/en/application-dev/database/data-sync-of-kv-store.md @@ -68,7 +68,7 @@ When data is added, deleted, or modified, a notification is sent to the subscrib - The KV stores do not support custom conflict resolution policies for applications. -- A maximum of 16 distributed KV stores can be opened simultaneously for an application. +- A maximum of 16 KV stores can be opened simultaneously for an application. - Each KV store supports a maximum of eight callbacks for subscription of data change notifications. diff --git a/en/application-dev/database/share-data-by-datashareextensionability.md b/en/application-dev/database/share-data-by-datashareextensionability.md index fc0a7d581b8bf9d60eb990a93fbad4c4160b7a63..ea6bdbcd210f4ddc1ffa67f4d50dcca8b96cf8dd 100644 --- a/en/application-dev/database/share-data-by-datashareextensionability.md +++ b/en/application-dev/database/share-data-by-datashareextensionability.md @@ -16,8 +16,8 @@ There are two roles in **DataShare**: - Data consumer: accesses the data provided by the provider using [createDataShareHelper()](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper). -**Figure 1** Data sharing mechanism - +**Figure 1** Data sharing mechanism + ![dataShare](figures/dataShare.jpg) - The **DataShareExtensionAbility** module, as the data provider, implements services related to data sharing between applications. @@ -60,7 +60,7 @@ Before implementing a **DataShare** service, you need to create a **DataShareExt 3. Import **@ohos.application.DataShareExtensionAbility** and other dependencies to the **DataShareExtAbility.ts** file, and override the service implementation as required. For example, if the data provider provides only the data insertion, deletion, and query services, you can override only these APIs. - + ```js import Extension from '@ohos.application.DataShareExtensionAbility'; import rdb from '@ohos.data.relationalStore'; @@ -68,7 +68,7 @@ override the service implementation as required. For example, if the data provid ``` 4. Implement the data provider services. For example, implement data storage of the data provider by using a database, reading and writing files, or accessing the network. - + ```js const DB_NAME = 'DB00.db'; const TBL_NAME = 'TBL00'; @@ -126,18 +126,18 @@ override the service implementation as required. For example, if the data provid **Table 1** Fields in module.json5 - | Field| Description| Mandatory| + | Field| Description| Mandatory| | -------- | -------- | -------- | - | name | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**.| Yes| - | type | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template.| Yes| - | uri | URI used for communication. It is the unique identifier for the data consumer to connect to the provider.| Yes| - | exported | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**.| Yes| - | readPermission | Permission required for accessing data. If this parameter is not set, the read permission is not verified by default.| No| - | writePermission | Permission required for modifying data. If this parameter is not set, write permission verification is not performed by default.| No| + | name | Ability name, corresponding to the **ExtensionAbility** class name derived from **Ability**.| Yes| + | type | Ability type. The value is **dataShare**, indicating the development is based on the **datashare** template.| Yes| + | uri | URI used for communication. It is the unique identifier for the data consumer to connect to the provider.| Yes| + | exported | Whether it is visible to other applications. Data sharing is allowed only when the value is **true**.| Yes| + | readPermission | Permission required for accessing data. If this parameter is not set, the read permission is not verified by default.| No| + | writePermission | Permission required for modifying data. If this parameter is not set, write permission verification is not performed by default.| No| **module.json5 example** - + ```json "extensionAbilities": [ { @@ -156,7 +156,7 @@ override the service implementation as required. For example, if the data provid ### Data Consumer Application Development 1. Import the dependencies. - + ```js import UIAbility from '@ohos.app.ability.UIAbility'; import dataShare from '@ohos.data.dataShare'; @@ -164,14 +164,14 @@ override the service implementation as required. For example, if the data provid ``` 2. Define the URI string for communicating with the data provider. - + ```js // Different from the URI defined in the module.json5 file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/). let dseUri = ('datashare:///com.samples.datasharetest.DataShare'); ``` 3. Create a **DataShareHelper** instance. - + ```js let dsHelper; let abilityContext; @@ -187,7 +187,7 @@ override the service implementation as required. For example, if the data provid ``` 4. Use the APIs provided by **DataShareHelper** to access the services provided by the provider, for example, adding, deleting, modifying, and querying data. - + ```js // Construct a piece of data. let valuesBucket = { 'name': 'ZhangSan', 'age': 21, 'isStudent': false, 'Binary': new Uint8Array([1, 2, 3]) }; diff --git a/en/application-dev/database/share-device-data-across-apps-overview.md b/en/application-dev/database/share-device-data-across-apps-overview.md index 38aead4c3c77553daab497ab3436291a409a227f..6392e579a8e078e4ff41751aa2ebcc1481ac58a0 100644 --- a/en/application-dev/database/share-device-data-across-apps-overview.md +++ b/en/application-dev/database/share-device-data-across-apps-overview.md @@ -1,46 +1,47 @@ -# DataShare Overview - +# Cross-Application Data Sharing Overview ## Function -The **DataShare** module allows an application to share its data with other applications. Currently, data can be shared only between applications on the same device. +The application data on a device, such as the Contacts, short message service (SMS), and Gallery data, always needs to be shared with other applications. However, certain data, such as the accounts and passwords, cannot be shared. Certain data, such as SMS messages, can be accessed but not modified by other applications. The **DataShare** module provides a secure and easy-to-use mechanism for sharing data of an application with other applications on the same device. -Data needs to be shared in a wealth of scenarios. For example, the Contacts, short message service (SMS), and Gallery data always needs to be shared with other applications. However, certain data, such as accounts and passwords, cannot be shared. Some data, such as SMS messages, can be queried but not modified by other applications. **DataShare** provides a secure and convenient sharing mechanism for application data. +## Basic Concepts -The data provider can directly use **DataShare** to share data with other applications without complex encapsulation. The data consumer only needs to use a set of APIs because the DataShare access mode does not vary with the data provision mode. This greatly reduces the learning time and development difficulty. +Before developing cross-application data sharing on a device, understand the following concepts: -Data can be shared across applications in either of the following ways: +- Data provider: an application that provides data and implements related services. It is also called the data producer or server. -- Using **DataShareExtensionAbility** - An extension ability is implemented in the HAP to invoke a callback. When the data consumer calls an API, the extension ability of the data provider will be automatically started to invoke the registered callback. +- Data consumer: an application that accesses the data or services provided by the data provider. It is also called the client. - You can use **DataShareExtensionAbility** when the cross-application data access involves service operations other than mere addition, deletion, modification, and query of data in databases. +- **ValuesBucket**: a set of data to be inserted. It can be one or more data records in KV pairs. In each KV pair, the key must be of the string type, and the value can be a number, a string, a Boolean value, or an unsigned integer array. -- Using Silent Access - Database access rules are configured in the HAP. When the data consumer calls an API, the system ability automatically obtains the access rules in the HAP and returns data without starting the data provider. +- **ResultSet**: a set of query results. It provides flexible modes for obtaining various data. - You can use the silent access feature when the cross-application data access involves only the operations for adding, deleting, modifying, and querying data in databases. +- **Predicates**: an object that specifies the conditions for updating, deleting, or querying data in a database. -## Basic Concepts +## Implementation -Before developing cross-application data sharing on a device, understand the following concepts: +The data provider can directly use **DataShare** to share data with other applications without complex encapsulation. The data consumer only needs to use a set of APIs to access the data, because the **DataShare** access mode does not vary with the data provisioning mode. This greatly reduces the learning time and development difficulty. -- Data provider: an application that provides data and implements related services. It is also called the producer or server. +The cross-application data sharing can be implemented in either of the following ways: -- Data consumer: an application that accesses the data or services provided by the data provider. It is also called the client. +- **DataShareExtensionAbility** -- **ValuesBucket**: a set of data to be inserted. It can be one or more data records in KV pairs. In each KV pair, the key must be of the string type, and the value can be a number, a string, a Boolean value, or an unsigned integer array. + You can implement an ExtensionAbility with a callback in the HAP. When the data consumer calls an API, the ExtensionAbility of the data provider will be automatically started to invoke the registered callback. -- **ResultSet**: a set of query results. It provides flexible modes for users to obtain various data. + This method is recommended when the cross-application data access involves service operations other than mere addition, deletion, modification, and query of data in databases. -- **Predicates**: an object that specifies the conditions for updating, deleting, or querying data in a database. +- Silent access + + You can configure database access rules in the HAP. When the data consumer calls an API, the system ability automatically obtains the access rules in the HAP and returns data without starting the data provider. + + This method is recommended when the cross-application data access involves only the operations for adding, deleting, modifying, and querying data in databases. ## Constraints -- **DataShare** is subject to the limitations on the database used by the data provider. For example, the supported data models, length of the keys and values, and maximum number of databases that can be accessed at a time by each application vary with the database in use. +- **DataShare** is subject to the limitations on the database used by the data provider. The supported data models, length of the keys and values, and maximum number of databases that can be accessed at a time by each application vary with the database in use. -- The payloads of **ValuesBucket**, **Predicates**, and **ResultSet** are restricted by IPC. +- The payloads of **ValuesBucket**, **Predicates**, and **ResultSet** are restricted by inter-process communication (IPC). - Currently, **dataShare** supports development based on the stage model only. 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 6f7135b41482a159c152bc18ed056ae0c3f12e60..875b70fef7d4b3bcd6b78a2102ec40c80d7da5f9 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,7 +36,7 @@ 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-label). 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: +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| |---|---| diff --git a/en/application-dev/faqs/Readme-EN.md b/en/application-dev/faqs/Readme-EN.md index 63535a32ae16eca13b03d20b4bce93569e2fe1d0..f8beb57887ae7a20273641cc7e5f697baf0137d2 100644 --- a/en/application-dev/faqs/Readme-EN.md +++ b/en/application-dev/faqs/Readme-EN.md @@ -1,21 +1,14 @@ # FAQs -- [Programming Languages](faqs-language.md) - [Ability Framework Development](faqs-ability.md) -- [Bundle Management Development](faqs-bundle.md) -- [ArkUI (ArkTS) Development](faqs-ui-ets.md) -- [ArkUI Web Component (ArkTS) Development](faqs-web-arkts.md) -- [ArkUI (JavaScript) Development](faqs-ui-js.md) +- [Resource Management Development](faqs-globalization.md) - [Common Event and Notification Development](faqs-event-notification.md) - [Graphics and Image Development](faqs-graphics.md) +- [Data Management Development](faqs-distributed-data-management.md) +- [Basic Security Capability Development](faqs-security.md) +- [Application Access Control Development](faqs-ability-access-control.md) - [File Management Development](faqs-file-management.md) -- [Media Development](faqs-media.md) -- [Network and Connection Development](faqs-connectivity.md) -- [Data Management Development](faqs-data-management.md) -- [Device Management Development](faqs-device-management.md) +- [Network Management Development](faqs-network-management.md) - [DFX Development](faqs-dfx.md) -- [Intl Development](faqs-international.md) -- [Native API Usage](faqs-native.md) -- [Usage of Third- and Fourth-Party Libraries](faqs-third-party-library.md) -- [IDE Usage](faqs-ide.md) -- [Development Board](faqs-development-board.md) \ No newline at end of file +- [Startup Development](faqs-startup.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..f336120a2b131eb75604fa3e51b1b8ff0130072e --- /dev/null +++ b/en/application-dev/faqs/faqs-ability-access-control.md @@ -0,0 +1,7 @@ +# Application 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-connectivity.md b/en/application-dev/faqs/faqs-connectivity.md deleted file mode 100644 index 31e1db2e15e82875427d52a92dd26bcfeb69c34e..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-connectivity.md +++ /dev/null @@ -1,33 +0,0 @@ -# Network and Connection Development - - - -## What are the data formats supported by extraData in an HTTP request? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -**extraData** indicates additional data in an HTTP request. It varies depending on the HTTP request method. - -- If the HTTP request uses a POST or PUT method, **extraData** serves as the content of the HTTP request. - -- If the HTTP request uses a GET, OPTIONS, DELETE, TRACE, or CONNECT method, **extraData** serves as a supplement to the HTTP request parameters and will be added to the URL when the request is sent. - -- If you pass in a string object, **extraData** contains the string encoded on your own. - - -## What does error code 28 mean for an HTTP request? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -Error code 28 refers to **CURLE_OPERATION_TIMEDOUT**, which means a cURL operation timeout. For details, see any HTTP status code description available. - -Reference: [Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) - - -## What does error code 6 mean for the response of \@ohos.net.http.d.ts? - -Applicable to: OpenHarmony SDK 3.2.3.5 - -Error code 6 indicates a failure to resolve the host in the address. You can ping the URL carried in the request to check whether the host is accessible. - -Reference: [Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) diff --git a/en/application-dev/faqs/faqs-data-management.md b/en/application-dev/faqs/faqs-data-management.md deleted file mode 100644 index 47f0b7ce20cd54a1cee4eb521801d4e7ca94e04b..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-data-management.md +++ /dev/null @@ -1,76 +0,0 @@ -# Data Management Development - -## How Do I Save PixelMap Data to a Database? - -Applicable to: OpenHarmony SDK 3.2.3.5 - -You can convert a **PixelMap** into 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 SDK 3.2.3.5, stage model of API version 9 - -Run the hdc_std command to copy the .db, .db-shm, and .db-wal files in **/data/app/el2/100/database/*bundleName*/entry/db/**, and then use the SQLite tool to open the files. - -Example: - -``` - hdc_std file recv /data/app/el2/100/database/com.xxxx.xxxx/entry/db/test.db ./test.db -``` - -## Does the Database Has a Lock Mechanism? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -The distributed data service (DDS), relational database (RDB) store, and preferences provided OpenHarmony have a lock mechanism. You do not need to bother with the lock mechanism during the development. - -## What Is a Transaction in an RDB Store? - -Applicable to: all versions - -When a large number of operations are performed in an RDB store, an unexpected exception may cause a failure of some data operations and loss of certain data. As a result, the application may become abnormal or even crash. - -A transaction is a group of tasks serving as a single logical unit. It eliminates the failure of some of the operations and loss of associated data. - -## What Data Types Does an RDB Store Support? - -Applicable to: OpenHarmony SDK 3.0 or later, stage model of API version 9 - -An RDB store supports data of the number, string, and Boolean types. The number array supports data of the Double, Long, Float, Int, or Int64 type, with a maximum precision of 17 decimal digits. - -## How Do I View Database db Files? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -1. Run the **hdc_std shell** command. - -2. Obtain the absolute path or sandbox path of the database. - -The absolute path is **/data/app/el2//database/**. The default **** is **100**. - -To obtain the sandbox path, run the **ps -ef | grep hapName** command to obtain the process ID of the application. - -The database sandbox path is **/proc//root/data/storage/el2/database/**. - -3. Run the **find ./ -name "\*.db"** command in the absolute path or sandbox path of the database. - -## How Do I Store Long Text Data? - -Applicable to: OpenHarmony SDK 3.2.5.5, API version 9 - -- Preferences support a string of up to 8192 bytes. - -- The KV store supports a value of up to 4 MB. - -Reference: [Preference Overview](../database/database-preference-overview.md) and [Distributed Data Service Overview](../database/database-mdds-overview.md) - -## How Do I Develop DataShare on the Stage Model - -Applicable to: OpenHarmony SDK 3.2.5.5, API version 9 - -The DataShare on the stage model cannot be used with the **DataAbility** for the FA model. The connected server application must be implemented by using **DataShareExtensionAbility**. - -Reference: [DataShare Development](../database/database-datashare-guidelines.md) - diff --git a/en/application-dev/faqs/faqs-development-board.md b/en/application-dev/faqs/faqs-development-board.md deleted file mode 100644 index 0a2a29db5ba68e57e2eee790485ae682ac78b6c0..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-development-board.md +++ /dev/null @@ -1,50 +0,0 @@ -# Development Board Usage - -## How do I take screenshots on a development board? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -- Method 1: Click the screenshot button in the Control Panel from the development board UI. The screenshot is displayed in Gallery. - -- Method 2: Run the screenshot script. Connect to the development board to a computer running Windows. Create a text file on the computer, copy the following script content to the file, change the file name extension to **.bat** (the HDC environment variables must be configured in advance), and click **Run**. The screenshot is saved to the same directory as the **.bat** script file. - Example: - - ``` - set filepath=/data/%date:~0,4%%date:~5,2%%date:~8,2%%time:~1,1%%time:~3,2%%time:~6,2%.png - echo %filepath% - : pause - hdc_std shell snapshot_display -f %filepath% - : pause - hdc_std file recv %filepath% . - : pause - ``` - -## How do I adjust Previewer in DevEco Studio so that the preview looks the same as what's displayed on a real RK3568 development board? - -Applicable to: DevEco Studio 3.0.0.991 - -1. Create a profile in Previewer. - - ![en-us_image_0000001361254285](figures/en-us_image_0000001361254285.png) - -2. Set the profile parameters as follows: - - Device type : default - - Resolution: 720\*1280 - - DPI: 240 - -## What should I do if Device Manager incorrectly identifies a development board as FT232R USB UART even when the development board already has a driver installed? - -Possible cause: The USB serial driver of the development version is not installed. - -Solution: Search for **FT232R USB UART**, and download and install the driver. - -## How do I complete authentication when logging in to the development board? - -Applicable to: OpenHarmony SDK 3.2.2.5 - -When connecting to the network that requires authentication, open any web page in the browser to access the authentication page. - -If there is no browser on the development board, you can install the [sample browser application](https://gitee.com/openharmony/app_samples/tree/master/device/Browser). diff --git a/en/application-dev/faqs/faqs-device-management.md b/en/application-dev/faqs/faqs-device-management.md deleted file mode 100644 index ea71edd6c9940437e197be35e60a6638c73ae88d..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-device-management.md +++ /dev/null @@ -1,48 +0,0 @@ -# Device Management Development - -## How do I obtain the DPI of a device? - -Applicable to: OpenHarmony 3.2 Beta5, stage model of API version 9 - -Import the **@ohos.display** module and call the **getDefaultDisplaySync** API. - -**Example** - -``` -import display from '@ohos.display'; -let displayClass = null; -try { - displayClass = display.getDefaultDisplaySync(); - console.info('Test densityDPI:' + JSON.stringify(data.densityDPI)); -} catch (exception) { - console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception)); -} -``` - -## How do I obtain the type of the device where the application is running? - -Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 - -Import the **\@ohos.deviceInfo** module and call the **deviceInfo.deviceType** API. - -For details, see [Device Information](../reference/apis/js-apis-device-info.md). - -## How do I obtain the system version of a device? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Use the **osFullName** attribute of the [deviceInfo](../reference/apis/js-apis-device-info.md) object. - -## How do I obtain the UDID of an OpenHarmony device? - -Applicable to: OpenHarmony SDK3.0, stage model of API version 9 - -- To obtain the UDID of the connected device, run the **hdc shell bm get --udid** command. - -- For details about how to obtain the UDID from code, see [udid](../reference/apis/js-apis-device-info.md). - -## How do I develop a shortcut key function? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -To develop a shortcut key function, use the APIs in [Input Consumer](../reference/apis/js-apis-inputconsumer.md). diff --git a/en/application-dev/faqs/faqs-dfx.md b/en/application-dev/faqs/faqs-dfx.md index 9fc12a1b1c26e109240702cca50e50b77495bdf5..51945bd8d0b9742703696d19fd2cc1f52add112d 100644 --- a/en/application-dev/faqs/faqs-dfx.md +++ b/en/application-dev/faqs/faqs-dfx.md @@ -1,54 +1,27 @@ # DFX Development -## How do I locate the fault when the application crashes? +## How do I flush HiLog information to disks? -Applicable to: OpenHarmony SDK 3.2.5.5 +Applicable to: OpenHarmony 3.2 Beta (API version 9) -1. Locate the crash-related code based on the service log. +**Symptom** -2. View the error information in the crash file, which is located at **/data/log/faultlog/faultlogger/**. +How do I flush HiLog information to disks? -## Why cannot access controls in the UiTest test framework? +**Solution** -Applicable to: OpenHarmony SDK 3.2.5.5 +Run the **hilog -w start -f ckTest -l 1M -n 5 -m zlib -j 11** command. -Check whether **persist.ace.testmode.enabled** is turned on. +The log file is saved in the **/data/log/hilog/** directory. -Run **hdc\_std shell param get persist.ace.testmode.enabled**. +Parameter description: -If the value is **0**, run the **hdc\_std shell param set persist.ace.testmode.enabled 1** to enable the test mode. - - -## Why is private displayed in logs when the format parameter type of HiLog in C++ code is %d or %s? - -When format parameters such as **%d** and **%s** are directly used, the standard system uses **private** to replace the actual data for printing by default to prevent data leakage. To print the actual data, replace **%d** with **%{public}d** or replace **%s** with **%{public}s**. - -## What should I do if the hilog.debug log cannot be printed? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Run **hdc_std shell hilog -b D** to turn on the debugging switch. - -## Is HiLog or console recommended for log printing? How do I set the domain if HiLog is used? - -Applicable to: OpenHarmony SDK 3.2.2.5 - -You are advised to use the [HiLog](../reference/apis/js-apis-hilog.md) for log printing. For details about how to set the **domain** parameter, see the [Development Guide](../reference/apis/js-apis-hilog.md#hilogisloggable). - -## What is the maximum length of a log record when HiLog is used? Is it configurable? - -Applicable to: OpenHarmony SDK 3.2.2.5 - -The maximum length of a log record is 1,024 characters, and it is not changeable. - -## Can I separate multiple strings by spaces in the tag parameter of the HiLog API? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -No. Separating multiple strings by spaces is not allowed. - -## How do I print real data if HiLog does not contain data labeled by {public}? - -Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 - -Run **hdc\_std shell hilog -p off** to disable logging of data labeled by {public}. +``` +-**-w**: Starts a log flushing task. **start** means to start the task, and **stop** means to stop the task. +-**-f**: Sets the log file name. +-**-l**: Sets the size of a single log file. The unit can be B, KB, MB, or GB. +-**-n**: Sets the maximum number of log files. When the number of log files exceeds the specified value, the earliest log file will be overwritten. The value range is [2,1000]. +-**-m**: Specifies the log file compression algorithm. +-**-j**: Specifies the task ID. The value ranges from **10** to **0xffffffffff**. +For more details about parameters, run the **hilog --help** command. +``` 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-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-globalization.md b/en/application-dev/faqs/faqs-globalization.md new file mode 100644 index 0000000000000000000000000000000000000000..b4d06ab98cbb1b24f4f0384ed893126c334ff383 --- /dev/null +++ b/en/application-dev/faqs/faqs-globalization.md @@ -0,0 +1,118 @@ +# Resource Manager Development + +## How do I read an XML file in rawfile and convert the data in it to the string type? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Call **getRawFileContent** of the **ResourceManager** module to obtain the data in the XML file, and then use **String.fromCharCode** to convert the data to the string type. + +**Sample Code** + +``` +resourceManager.getRawFileContent('test.xml', (error, value) => { + if (error != null) { + console.log("error is " + error); + } else { + let rawFile = value; + let xml = String.fromCharCode.apply(null, rawFile) + } +}); +``` + +**Reference** + +[Resource Manager](../reference/apis/js-apis-resource-manager.md) + +## How do I obtain resources in the stage model? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Solution** + +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 mode does not apply to the FA model. + +**Sample Code** + +``` +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 the path of the resource directory by using an API? + +Applicable to: OpenHarmony 3.1 Beta 5 (API version 9) + +**Symptom** + +How do I obtain the path of the **resource** directory so that I can manage the files in it by using the file management API? + +**Solution** + +Because the application is installed in HAP mode and the HAP package is not decompressed after the installation is complete, the resource path cannot be obtained when the program is running. + +To obtain the path of the **resource** directory, try either of the following ways: + +1. Use **\$r** or **\$rawfile** for access. This method applies to static access, during which the **resource** directory remains unchanged when the application is running. + +2. Use **ResourceManager** for access. This method applies to dynamic access, during which the **resource** directory dynamically changes when the application is running. + +**Reference** + +[Resource Categories and Access](../quick-start/resource-categories-and-access.md) and [Resource Manager](../reference/apis/js-apis-resource-manager.md) + +## Why does getPluralString return an incorrect value? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +The value obtained by the **getPluralString** is **other**, which is incorrect. + +**Solution** + +The **getPluralString** API is effective only when the system language is English. + +## How do I obtain the customized string fields in the resources directory? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Use **getStringValue** of the **ResourceManager** module. + +**Reference** + +[Resource Manager](../reference/apis/js-apis-resource-manager.md#getstringvalue9) + +## How do I reference resources such as images and text in AppScope? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Reference resources in the **\$r\('app.type.name'\)** format. Wherein, **type** indicates the resource type, such as color, string, and media, and **name** indicates the resource name. + +## How do I convert resources to strings? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +For a qualifier directory, use **this.context.resourceManager.getStringSync\(\$r\('app.string.test'\).id\)** to covert resources to strings synchronously. Note that the **\$r\('app.string.test', 2\)** mode is not supported. + +**Reference** + +[Resource Manager](../reference/apis/js-apis-resource-manager.md#getstringsync9) + +## Can $ be used to reference constants in the form\_config.json file? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**\$** cannot be used to reference constants in the **form\_config.json** file. 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-international.md b/en/application-dev/faqs/faqs-international.md deleted file mode 100644 index 546402921ce3a2cd9f9972721727a84d9a31295a..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-international.md +++ /dev/null @@ -1,19 +0,0 @@ -# Intl Development - -## How resources in AppScope, such as images and text, are referenced? - -Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 - -Resources are referenced in the **$r('app.type.name')** format. Where, **type** indicates the resource type, such as color, string, and media, and **name** indicates the resource name. - -## How do I convert the resource type to string? - -Applicable to: OpenHarmony SDK3.0, stage model of API version 9 - -If the resource type is set to **string**, the qualifier directory can be set as **this.context.resourceManager.getStringSync(\\$r('app.string.test').id)** and can be converted synchronously. The **\$r('app.string.test', 2)** mode is not supported. For more usage methods, see [Resource Manager](../reference/apis/js-apis-resource-manager.md#getstringsync9). - -## Why should I do if the constants referenced by $ in the form_config.json file does not take effect? - -Applicable to: OpenHarmony SDK 3.2.6.5, API9 Stage model - -In the **form\_config.json** file, **$** cannot be used to reference constants. diff --git a/en/application-dev/faqs/faqs-language.md b/en/application-dev/faqs/faqs-language.md deleted file mode 100644 index 6d3ded94a76155feae22d761bdb63422e07f0316..0000000000000000000000000000000000000000 --- a/en/application-dev/faqs/faqs-language.md +++ /dev/null @@ -1,291 +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. - -Reference: [State Management with Application-level Variables](../quick-start/arkts-state-mgmt-application-level.md) - -## 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**). For details, see [BuilderParam](../quick-start/arkts-dynamic-ui-elememt-building.md#builderparam8). - -## 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-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-network-management.md b/en/application-dev/faqs/faqs-network-management.md new file mode 100644 index 0000000000000000000000000000000000000000..dd585f87cc40f2942404cc51c3fcb15bcf04d55e --- /dev/null +++ b/en/application-dev/faqs/faqs-network-management.md @@ -0,0 +1,222 @@ +# Network Management Development + +## What are the data formats supported by extraData in an HTTP request? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Solution** + +**extraData** indicates additional data in an HTTP request. It varies depending on the HTTP request method. + +- If the HTTP request uses a POST or PUT method, **extraData** serves as the content of the HTTP request. +- If the HTTP request uses a GET, OPTIONS, DELETE, TRACE, or CONNECT method, **extraData** serves as a supplement to the HTTP request parameters and will be added to the URL when the request is sent. +- If you pass in a string object, **extraData** contains the string encoded on your own. + +## What does error code 28 mean in the response to an HTTP request? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +Error code 28 is reported after an HTTP request is initiated. + +**Solution** + +Error code 28 indicates **CURLE\_OPERATION\_TIMEDOUT**, which means a libcurl library operation timeout. For details, see any HTTP status code description available. + +**Reference** + +[Common HTTP Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) + +## What does error code 6 mean in the response to an HTTP request? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +Error code 6 is reported after an HTTP request is initiated. + +**Solution** + +Error code 6 indicates a failure to resolve the host in the address. You can ping the URL carried in the request to check whether the host is accessible. + +**Reference** + +[Common HTTP Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) + +## How are parameters passed to queryParams of the POST request initiated by @ohos/axios? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +How are parameters passed to **queryParams** when the third-party component @ohos/axios initiates a POST request? + +**Solution** + +- Method 1: Have the **axios.post** API receive only one parameter. The **Url.URLSearchParams** parameter needs to be converted into a string and appended to the end of the URL. + + ``` + let params:Url.URLSearchParams = new Url.URLSearchParams() + params.append('ctl', 'sug') + params.append('query', 'wangjunkai') + params.append('cfrom', '1099a') + axios.post('http://10.100.195.234:3000/save?' + params.toString()).then(res => { + this.message = "request result: " + JSON.stringify(res.data); + }).catch(err => { + this.message = "request error: " + err.message; + }) + ``` + +- Method 2: Have the **axios** API receive only one **config** object. The request parameters are written in **params** of the **config** object. + + ``` + axios({ + url: 'http://10.100.195.234:3000/save', + method: 'post', + params: { + ctl: 'sug', + query: 'wangjunkai', + cfrom: '1099a' + } + }).then(res => { + this.message = "request result: " + JSON.stringify(res.data); + }).catch(err => { + this.message = "request error: " + err.message; + }) + ``` + + +## What should I do if no data is returned after connection.getNetCapabilities\(mNetHandle\) is called? + +Applicable to: OpenHarmony 3.2 Beta 2 (API version 9) + +**Symptom** + +No data is returned after **connection.getNetCapabilities\(\)** is called. What should I do? + +**Possible Cause** + +This problem is due to incorrect pointing of the **this** object. You are expected to use **\(err,data\)=\>\{\}** instead of **function\(err,data\)** to access the callback function to obtain the return result. The reason is that the function declared by **function** has its own **this** object and therefore cannot point to the **globalThis** object. + +**Solution** + +Change **function\(err,data\)** to **\(err,data\)** for the second parameter of **getNetCapabilities**. + +## How is data in HTTP requests transmitted in JSON format? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Solution** + +In the HTTP message header, **Content-Type** is used to indicate the media type information. It tells the server how to process the requested data and tells the client (usually a browser) how to parse the response data, for example, displaying an image, parsing HTML, or displaying only the text. + +To transmit data in HTTP requests in JSON format, set **Content-Type** to **application/json**. + +``` +this.options = { + method: http.RequestMethod.GET, + extraData: this.extraData, + header: { 'Content-Type': 'application/json' }, + readTimeout: 50000, + connectTimeout: 50000 +} +``` + +## How do I upload photos taken by a camera to the server? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Symptom** + +After an application calls the camera to take a photo, how do I upload the photo to the server? + +**Solution** + +After the application is started and the permission is obtained, have the system access the remote server and transfer the locally saved photos to the remote server through the upload API. + +**Reference** + +[Upload and Download](../reference/apis/js-apis-request.md) + +## What should I do if calling connection.hasDefaultNet\(\) fails even when the network is normal? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +The network connection is normal, and web pages can be opened properly on the browser. However, calling the **hasDefaultNet** fails, and the callback function returns an error. + +**Solution** + +Declare the **ohos.permission.GET\_NETWORK\_INFO** permission when calling **connection.hasDefaultNet**. + +For details, see [Applying for Permissions](../security/accesstoken-guidelines.md). + +## What does netId mean in the netHandle object returned by connection.getDefaultNet? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +What are the meanings of the values of **netId**, such as **0** and **100**? + +**Solution** + +If the value of **netId** is **0**, no network connection is available. In such a case, check and rectify network faults. If the value is greater than or equal to **100**, the network connection is normal. + +## How do I use HTTP requests to obtain data from the network? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Solution** + +Use the **@ohos.net.http** module to initiate an HTTP request. + +1. Import the **http** module and create an HTTP request. +2. Set the request URL and parameters and initiate the HTTP request. +3. Obtain the response and parse the data. + +**Reference** + +[HTTP Data Request](../connectivity/http-request.md) + +## How do I encapsulate network requests by using JavaScript? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Solution** + +OpenHarmony supports the JavaScript development mode. You can directly use JavaScript to encapsulate network requests. For details, see [Network Connection](../reference/apis/js-apis-http.md). + +## How do I write network requests when developing a JavaScript-based application for smart watches? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Solution** + +OpenHarmony supports the JavaScript development mode. You can directly use JavaScript to encapsulate network requests. For details, see [Network Connection](../reference/apis/js-apis-http.md). + +## Why does an application fail to start after the ohos.permission.NOTIFICATION\_CONTROLLER permission is declared? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +When an application is started, the following error message is reported w: error: install failed due to grant request permissions failed. + +**Solution** + +The **ohos.permission.NOTIFICATION\_CONTROLLER** permission is a **system core** permission and is not available for third-party applications. + +## What should I do if an error is reported when wifi.getIpInfo\(\).ipAddress is used in the Wi-Fi module? + +Applicable to: OpenHarmony 3.2 Beta (API version 9) + +**Symptom** + +When **wifi.getIpInfo\(\).ipAddress** is used in the Wi-Fi module, the following error message is reported: Error: assertion \(wifiDevicePtr != nullptr\) failed: Wifi device instance is null. + +**Solution** + +This problem is due to insufficient permissions. Check whether you have applied for the required permissions. For details, see [Permission Management](../security/accesstoken-overview.md). 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-startup.md b/en/application-dev/faqs/faqs-startup.md new file mode 100644 index 0000000000000000000000000000000000000000..3d0d9d2cf8b59cb7f1b3b3c778b963c509958ced --- /dev/null +++ b/en/application-dev/faqs/faqs-startup.md @@ -0,0 +1,43 @@ +# Startup Development + +## How do I obtain the system version of a device? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +You can obtain the system version of a device through the **osFullName** attribute of the [deviceInfo](../reference/apis/js-apis-device-info.md) object. + +**Sample Code** + +``` +import deviceInfo from '@ohos.deviceInfo' +let v = deviceInfo.osFullName +``` + +## How do I obtain the UDID of a device? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +- Method 1: Run the **hdc shell bm get --udid** command. +- Method 2: Obtain the value from the code. For details, see [udid](../reference/apis/js-apis-device-info.md). + +## How do I obtain device information? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +You can call **deviceInfo** to obtain device information, such as the device model. + +**Reference** + +[Device Information](../reference/apis/js-apis-device-info.md) + +## How do I prevent application development from being interrupted by screen saving? + +Applicable to: OpenHarmony 3.2 Beta 5 (API version 9) + +**Solution** + +Run the **hdc shell "power-shell setmode 602"** command to turn off screen saving. diff --git a/en/application-dev/faqs/faqs-third-party-library.md b/en/application-dev/faqs/faqs-third-fourth-party-library.md similarity index 100% rename from en/application-dev/faqs/faqs-third-party-library.md rename to en/application-dev/faqs/faqs-third-fourth-party-library.md 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 \