diff --git a/en/application-dev/application-models/Readme-EN.md b/en/application-dev/application-models/Readme-EN.md new file mode 100644 index 0000000000000000000000000000000000000000..2a920300623358bc25f7256d6af8b957665bc600 --- /dev/null +++ b/en/application-dev/application-models/Readme-EN.md @@ -0,0 +1,130 @@ +# Application Models + +- Application Model Overview + - [Elements of the Application Model](application-model-composition.md) + - [Interpretation of the Application Model](application-model-description.md) +- Stage Model Development + - [Stage Model Development Overview](stage-model-development-overview.md) + - Stage Mode Application Components + - [Application- or Component-Level Configuration](application-component-configuration-stage.md) + - UIAbility Component + - [UIAbility Component Overview](uiability-overview.md) + - [UIAbility Component Lifecycle](uiability-lifecycle.md) + - [UIAbility Component Launch Type](uiability-launch-type.md) + - [UIAbility Component Usage](uiability-usage.md) + - [Data Synchronization Between UIAbility and UI](uiability-data-sync-with-ui.md) + - [Interaction Between Intra-Device UIAbility Components](uiability-intra-device-interaction.md) + - ExtensionAbility Component + - [ExtensionAbility Component Overview](extensionability-overview.md) + - [ServiceExtensionAbility](serviceextensionability.md) + - [DataShareExtensionAbility](datashareextensionability.md) + - [FormExtensionAbility (Widget)](widget-development-stage.md) + - [AbilityStage Component Container](abilitystage.md) + - [Context](application-context-stage.md) + - Want + - [Want Overview](want-overview.md) + - [Matching Rules of Explicit Want and Implicit Want](explicit-implicit-want-mappings.md) + - [Common action and entities Values](actions-entities.md) + - [Using Explicit Want to Start an Ability](ability-startup-with-explicit-want.md) + - [Using Implicit Want to Open a Website](ability-startup-with-implicit-want.md) + - [Using Want to Share Data Between Applications](data-share-via-want.md) + - [Component Startup Rules](component-startup-rules.md) + - Inter-Device Application Component Interaction (Continuation) + - [Continuation Overview](inter-device-interaction-hop-overview.md) + - [Cross-Device Migration](hop-cross-device-migration.md) + - [Multi-device Collaboration](hop-multi-device-collaboration.md) + - IPC + - [Process Model](process-model-stage.md) + - Common Events + - [Introduction to Common Events](common-event-overview.md) + - [Subscribing to Common Events](common-event-subscription.md) + - [Publishing Common Events](common-event-publish.md) + - [Unsubscribing from Common Events](common-event-unsubscription.md) + - [Background Services](background-services.md) + - Inter-Thread Communication + - [Thread Model](thread-model-stage.md) + - [Using Emitter for Inter-Thread Communication](itc-with-emitter.md) + - [Using Worker for Inter-Thread Communication](itc-with-worker.md) + - Mission Management + - [Mission Management Scenarios](mission-management-overview.md) + - [Mission Management and Launch Type](mission-management-launch-type.md) + - [Page Stack and MissionList](page-mission-stack.md) + - [Application Configuration File](config-file-stage.md) +- FA Model Development + - [FA Model Development Overview](fa-model-development-overview.md) + - FA Mode Application Components + - [Application- or Component-Level Configuration](application-component-configuration-fa.md) + - PageAbility Component Development + - [PageAbility Component Overview](pageability-overview.md) + - [PageAbility Component Configuration](pageability-configuration.md) + - [PageAbility Lifecycle](pageability-lifecycle.md) + - [PageAbility Launch Type](pageability-launch-type.md) + - [Creating a PageAbility](create-pageability.md) + - [Starting a Local PageAbility](start-local-pageability.md) + - [Stopping a PageAbility](stop-pageability.md) + - [Starting a Remote PageAbility](start-remote-pageability.md) + - [Starting a Specified Page](start-page.md) + - [Window Properties](window-properties.md) + - [Requesting Permissions](request-permissions.md) + - [Redirection Rules](redirection-rules.md) + - ServiceAbility Component Development + - [ServiceAbility Component Overview](serviceability-overview.md) + - [ServiceAbility Component Configuration](serviceability-configuration.md) + - [ServiceAbility Lifecycle](serviceability-lifecycle.md) + - [Creating a ServiceAbility](create-serviceability.md) + - [Starting a ServiceAbility](start-serviceability.md) + - [Connecting to a ServiceAbility](connect-serviceability.md) + - DataAbility Component Development + - [DataAbility Component Overview](dataability-overview.md) + - [DataAbility Component Configuration](dataability-configuration.md) + - [DataAbility Lifecycle](dataability-lifecycle.md) + - [Creating a DataAbility](create-dataability.md) + - [Starting a DataAbility](start-dataability.md) + - [Accessing a DataAbility](access-dataability.md) + - [DataAbility Permission Control](dataability-permission-control.md) + - [Widget Development](widget-development-fa.md) + - [Context](application-context-fa.md) + - [Want](want-fa.md) + - [Component Startup Rules](component-startup-rules-fa.md) + - IPC + - [Process Model](process-model-fa.md) + - [Common Events](common-event-fa.md) + - [Background Services](rpc.md) + - Inter-Thread Communication + - [Thread Model](thread-model-fa.md) + - [Inter-Thread Communication](itc-fa-overview.md) + - [Mission Management](mission-management-fa.md) + - [Application Configuration File](config-file-fa.md) +- Development of Component Interaction Between the FA Model and Stage Model + - [Component Interaction Between the FA Model and Stage Model](fa-stage-interaction-overview.md) + - [Starting a UIAbility from the FA Model](start-uiability-from-fa.md) + - [Connecting to a ServiceExtensionAbility from the FA Model](bind-serviceextensionability-from-fa.md) + - [Accessing a DataShareExtensionAbility from the FA Model](access-datashareextensionability-from-fa.md) + - [Starting a PageAbility from the Stage Model](start-pageability-from-stage.md) + - [Connecting to a ServiceAbility from the Stage Model](bind-serviceability-from-stage.md) +- Switching from the FA Model to the Stage Model + - [Model Switching Overview](model-switch-overview.md) + - Configuration File Switching + - [Differences in Configuration Files](configuration-file-diff.md) + - [Switching of app and deviceConfig](app-deviceconfig-switch.md) + - [Switching of module](module-switch.md) + - Component Switching + - [PageAbility Switching](pageability-switch.md) + - [ServiceAbility Switching](serviceability-switch.md) + - [DataAbility Switching](dataability-switch.md) + - [Widget Switching](widget-switch.md) + - API Switching + - [API Switching Overview](api-switch-overview.md) + - [Context Switching](context-switch.md) + - [featureAbility Switching](featureability-switch.md) + - [particleAbility Switching](particleability-switch.md) + - [LifecycleForm Switching](lifecycleform-switch.md) + - [LifecycleApp Switching](lifecycleapp-switch.md) + - [LifecycleService Switching](lifecycleservice-switch.md) + - [LifecycleData Switching](lifecycledata-switch.md) + - [DataAbilityHelper Switching](dataabilityhelper-switch.md) + - [mediaLibrary Switching](medialibrary-switch.md) + - [request Switching](request-switch.md) + - [resourceManager Switching](resourcemanager-switch.md) + - [window Switching](window-switch.md) + - [Storage Switching](storage-switch.md) diff --git a/en/application-dev/application-models/ability-startup-with-explicit-want.md b/en/application-dev/application-models/ability-startup-with-explicit-want.md new file mode 100644 index 0000000000000000000000000000000000000000..9186379f32299ee7a42b7f82af4fc7f464c160d1 --- /dev/null +++ b/en/application-dev/application-models/ability-startup-with-explicit-want.md @@ -0,0 +1,4 @@ +# Using Explicit Want to Start an Ability + + +When a user touches a button in an application, the application often needs to start a UIAbility component to complete a specific task. If the **abilityName** and **bundleName** parameters are specified when starting a UIAbility, the explicit Want is used. For details about how to use the explicit Want, see [Starting UIAbility in the Same Application](uiability-intra-device-interaction.md#starting-uiability-in-the-same-application). diff --git a/en/application-dev/application-models/ability-startup-with-implicit-want.md b/en/application-dev/application-models/ability-startup-with-implicit-want.md new file mode 100644 index 0000000000000000000000000000000000000000..ab116c430cb7b248b947ccbee46cf5ac932f9fc9 --- /dev/null +++ b/en/application-dev/application-models/ability-startup-with-implicit-want.md @@ -0,0 +1,82 @@ +# Using Implicit Want to Open a Website + + +## Prerequisites + +One or more browsers are installed on your device. + +The **module.json5** of a browser application is as follows: + +```json +"skills": [ + { + "entities": [ + "entity.system.browsable" + // ... + ], + "actions": [ + "ohos.want.action.viewData" + // ... + ], + "uris": [ + { + "scheme": "https", + "host": "www.test.com", + "port": "8080", + // Prefix matching is used. + "pathStartWith": "query", + "type": "text/*" + }, + { + "scheme": "http", + // ... + } + // ... + ] + }, +] +``` + + +## How to Develop + +1. Use the custom function **implicitStartAbility** to start an ability. + + ```ts + async implicitStartAbility() { + try { + let want = { + // Uncomment the line below if you want to implicitly query data only in the specific bundle. + // bundleName: "com.example.myapplication", + "action": "ohos.want.action.viewData", + // entities can be omitted. + "entities": [ "entity.system.browsable" ], + "uri": "https://www.test.com:8080/query/student", + "type": "text/plain" + } + let context = getContext(this) as common.UIAbilityContext; + await context.startAbility(want) + console.info(`explicit start ability succeed`) + } catch (error) { + console.info(`explicit start ability failed with ${error.code}`) + } + let context = getContext(this) as common.UIAbilityContext; + await context.startAbility(want) + console.info(`explicit start ability succeed`) + } catch (error) { + console.info(`explicit start ability failed with ${error.code}`) + } + } + ``` + + The matching process is as follows: + 1. If **action** in the passed **want** parameter is specified and is included in **actions** under **skills**, the matching is successful. + + 2. If **entities** in the passed **want** parameter is specified and is included in **entities** under **skills**, the matching is successful. + + 3. If **uri** in the passed **want** parameter is included in **uris** under **skills**, which is concatenated into `https://www.test.com:8080/query*` (where \* is a wildcard), the matching is successful. + + 4. If **type** in the passed **want** parameter is specified and is included in **type** under **skills**, the matching is successful. + +2. When there are multiple matching applications, a dialog box is displayed for you to select one of them. +stage-want1 diff --git a/en/application-dev/application-models/abilitystage.md b/en/application-dev/application-models/abilitystage.md new file mode 100644 index 0000000000000000000000000000000000000000..4e0a273f850b4919d0964580ebed89c053c273f7 --- /dev/null +++ b/en/application-dev/application-models/abilitystage.md @@ -0,0 +1,57 @@ +# AbilityStage Component Container + + +AbilityStage is a component container at the [module](../quick-start/application-package-structure-stage.md) level. When the HAP of an application is loaded for the first time, an AbilityStage instance is created. You can perform operations such as initialization on the instance. + + +An AbilityStage instance corresponds to a module. + + +AbilityStage is not automatically generated in the default project of DevEco Studio. To use AbilityStage, you can manually create an AbilityStage file. 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 **myabilitystage**. + +2. In the **myabilitystage** directory, right-click and choose **New > ts 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. + + ```ts + 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"; + } + } + ``` + + +[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). + + +- **onCreate()** lifecycle callback: Before the first UIAbility instance of a module is loaded, an AbilityStage instance is created. This callback is invoked when the AbilityStage instance is created. The AbilityStage module notifies you of when you can perform module initialization such as resource pre-loading and thread creation during module loading. + +- **onAcceptWant()** event callback: triggered when the UIAbility is started in [specified mode](uiability-launch-type.md#specified). For details, see [UIAbility Component Launch Type](uiability-launch-type.md). + +- **onConfigurationUpdated()** event callback: triggered when the global system configuration changes. The global system configuration, such as the system language and theme, are defined in the [Configuration](../reference/apis/js-apis-app-ability-configuration.md) class before project configuration. + +- **onMemoryLevel()** event callback: triggered when the system adjusts the memory. + +When an application is switched to the background, it is cached in the background. This adversely affects the overall system performance. When system resources are insufficient, the system reclaims memory from applications in multiple ways. For example, the system may stop applications to release memory for executing key tasks. To further maintain the balance of the system memory and prevent the system from stopping application processes, you can subscribe to the system memory changes in the **onMemoryLevel()** lifecycle callback of AbilityStage to release unnecessary resources. + + + ```ts + 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. + } + } + ``` + diff --git a/en/application-dev/application-models/access-dataability.md b/en/application-dev/application-models/access-dataability.md new file mode 100644 index 0000000000000000000000000000000000000000..24dc9305f194a61c974c63db224f2e7727689f5f --- /dev/null +++ b/en/application-dev/application-models/access-dataability.md @@ -0,0 +1,204 @@ +# Accessing a DataAbility + + +To access a DataAbility, import the basic dependency packages and obtain the URI string for communicating with the DataAbility. + + +The basic dependency packages include: + + +- @ohos.ability.featureAbility + +- @ohos.data.dataAbility + +- @ohos.data.rdb + + +The sample code for accessing a DataAbility is as follows: + + +1. Create a **DataAbilityHelper** instance. + + ```ts + // Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), three slashes in total. + import featureAbility from '@ohos.ability.featureAbility' + import ohos_data_ability from '@ohos.data.dataAbility' + import ohos_data_rdb from '@ohos.data.rdb' + + let urivar = "dataability:///com.ix.DataAbility" + let DAHelper = featureAbility.acquireDataAbilityHelper(urivar); + ``` + +2. Construct RDB data. + + ```ts + let valuesBucket = {"name": "gaolu"} + let da = new ohos_data_ability.DataAbilityPredicates() + let valArray =new Array("value1"); + let cars = new Array({"batchInsert1" : "value1",}); + ``` + + For details about DataAbilityPredicates, see [DataAbility Predicates](../reference/apis/js-apis-data-ability.md). + +3. Use **insert** to insert data to the DataAbility. + + ```ts + // Callback mode: + DAHelper.insert( + urivar, + valuesBucket, + (error, data) => { + console.info("DAHelper insert result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let datainsert = await DAHelper.insert(urivar, valuesBucket).then((data) => { + console.info("insert success."); + }).catch((error) => { + console.error("insert failed."); + }); + ``` + +4. Use **delete** to delete data from the DataAbility. + + ```ts + // Callback mode: + DAHelper.delete( + urivar, + da, + (error, data) => { + console.info("DAHelper delete result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let datadelete = await DAHelper.delete( + urivar, + da, + ); + ``` + +5. Use **update** to update data in the DataAbility. + + ```ts + // Callback mode: + DAHelper.update( + urivar, + valuesBucket, + da, + (error, data) => { + console.info("DAHelper update result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let dataupdate = await DAHelper.update( + urivar, + valuesBucket, + da, + ); + ``` + +6. Use **query** to query data in the DataAbility. + + ```ts + // Callback mode: + DAHelper.query( + urivar, + valArray, + da, + (error, data) => { + console.info("DAHelper query result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let dataquery = await DAHelper.query( + urivar, + valArray, + da + ); + ``` + +7. Use **batchInsert** to insert data in batches to the DataAbility. + + ```ts + // Callback mode: + DAHelper.batchInsert( + urivar, + cars, + (error, data) => { + console.info("DAHelper batchInsert result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let databatchInsert = await DAHelper.batchInsert( + urivar, + cars + ); + ``` + +8. Use **executeBatch** to process data in batches in the DataAbility. + + ```ts + // Callback mode: + DAHelper.executeBatch( + urivar, + [ + { + uri: urivar, + type: featureAbility.DataAbilityOperationType.TYPE_INSERT, + valuesBucket: {"executeBatch" : "value1",}, + predicates: da, + expectedCount:0, + predicatesBackReferences: null, + interrupted:true, + } + ], + (error, data) => { + console.info("DAHelper executeBatch result: " + data) + } + ); + ``` + + + ```ts + // Promise mode (await needs to be used in the asynchronous method): + let dataexecuteBatch = await DAHelper.executeBatch( + urivar, + [ + { + uri: urivar, + type: featureAbility.DataAbilityOperationType.TYPE_INSERT, + valuesBucket: + { + "executeBatch" : "value1", + }, + predicates: da, + expectedCount:0, + predicatesBackReferences: null, + interrupted:true, + } + ] + ); + ``` + + +The APIs for operating a DataAbility are provided by **DataAbilityHelper**. For details about the APIs, see [DataAbilityHelper](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md). diff --git a/en/application-dev/application-models/access-datashareextensionability-from-fa.md b/en/application-dev/application-models/access-datashareextensionability-from-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..0abc7e3b8e948529b9916f936bf59b4a60a93637 --- /dev/null +++ b/en/application-dev/application-models/access-datashareextensionability-from-fa.md @@ -0,0 +1,52 @@ +# Accessing a DataShareExtensionAbility from the FA Model + + +## Overview + +Regardless of the FA model or stage model, the data read/write function consists of the client and server. + +- In the FA model, the client uses the **DataAbilityHelper** class to provide external APIs, and the server uses the **DataAbility** class to provide database read and write services. + +- In the stage model, the client uses the **DataShareHelper** class to provide external APIs, and the server uses the **DataShareExtensionAbility** class to provide database read and write services. + +If the client uses the FA model whereas the server is upgraded to the stage model, the client cannot access the server. + +To resolve this issue, OpenHarmony provides a solution on the framework side for smooth evolution. + + +## Basic Principles + +A compatible method is that **DataAbilityHelper** determines whether to call the **DataShareHelper** APIs based on the URI prefix (either **DataAbility** or **DataShare**). However, this method requires modification to the URI in the original client code. + +Instead of manual modification, OpenHarmony adopts the following processing: + +1. The system attempts to start the DataAbility based on the URI passed in. If the startup fails, the system converts the URI prefix to **DataShare** and attempts to start the DataShareExtensionAbility. + +2. If the URI does not map to any DataAbility or DataShareExtensionAbility, the startup fails. Otherwise, either the DataAbility or DataShareExtensionAbility is started. + + +## Constraints + +1. When you switch a DataAbility to a DataShareExtensionAbility, only the URI prefix can be modified.![FAvsStage-uri](figures/FAvsStage-uri.png) + +2. The **DataShareHelper** class implements only certain APIs of **DataAbilityHelper**. For details about the APIs, see the table below. + + **Table 1** APIs invoked when the FA model accesses a DataShareExtensionAbility of the stage model + + | API| Provided by DataAbilityHelper| Provided by DataShareHelper| Compatible| + | -------- | -------- | -------- | -------- | + | on | Yes| Yes| Yes| + | off | Yes| Yes| Yes| + | notifyChange | Yes| Yes| Yes| + | insert | Yes| Yes| Yes| + | delete | Yes| Yes| Yes| + | query | Yes| Yes| Yes| + | update | Yes| Yes| Yes| + | batchInsert | Yes| Yes| Yes| + | getType | Yes| No| No| + | getFileTypes | Yes| No| No| + | normalizeUri | Yes| Yes| Yes| + | denormalizeUri | Yes| Yes| Yes| + | openFile | Yes| No| No| + | call | Yes| No| No| + | executeBatch | Yes| No| No| diff --git a/en/application-dev/application-models/actions-entities.md b/en/application-dev/application-models/actions-entities.md new file mode 100644 index 0000000000000000000000000000000000000000..85dfb9523ca117e691480bcbd2321b5fb3b22304 --- /dev/null +++ b/en/application-dev/application-models/actions-entities.md @@ -0,0 +1,27 @@ +# Common action and entities Values + +The [action](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction) field specifies the common operation (such as viewing, sharing, and application details) to be performed by the caller. In implicit Want, you can define this field and use it together with **uri** or **parameters** to specify the operation to be performed on the data, for example, viewing URI data. For example, if the URI is a website and the action is **ohos.want.action.viewData**, the ability that supports website viewing is matched. Declaring the **action** field in Want indicates that the invoked application should support the declared operation. The **actions** field under **skills** in the configuration file indicates the operations supported by the application. + + +**Common action Values** + + +- **ACTION_HOME**: action of starting the application entry component. It must be used together with **ENTITY_HOME**. The application icon on the home screen is an explicit entry component. Users can touch the icon to start the entry component. Multiple entry components can be configured for an application. + +- **ACTION_CHOOSE**: action of selecting local resource data, such as Contacts and Gallery. Generally, the system has corresponding Picker applications for different types of data. + +- **ACTION_VIEW_DATA**: action of viewing data. A website URI indicates the action for opening the website. + +- **ACTION_VIEW_MULTIPLE_DATA**: action of launching the UI for sending multiple data records. + +The [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) field specifies the additional category information (such as browser and video player) of the target ability. It is a supplement to **action** in implicit Want. You can define this field to filter application categories, for example, browser. Declaring the **entities** field in Want indicates that the invoked application should belong to the declared category. The **entities** field under **skills** in the configuration file indicates the categories supported by the application. + + +**Common entities Values** + + +- **ENTITY_DEFAULT**: default category, which is meaningless. + +- **ENTITY_HOME**: abilities with an icon displayed on the home screen. + +- **ENTITY_BROWSABLE**: browser type. diff --git a/en/application-dev/application-models/api-switch-overview.md b/en/application-dev/application-models/api-switch-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..bf8223b5a6c047af46e960dad6713f20e251d02f --- /dev/null +++ b/en/application-dev/application-models/api-switch-overview.md @@ -0,0 +1,41 @@ +# API Switching Overview + + +Due to the differences in the thread model and process model, certain APIs (marked with **FAModelOnly** in the SDK) can be used only in the FA model. When switching an application from the FA model to the stage model, replace the APIs marked with **FAModelOnly** in the application with the APIs supported in the stage model. This topic uses the switching of **startAbility()** as an example. + +![api-switch-overview](figures/api-switch-overview.png) + + + +- Sample code of **startAbility()** in the FA model: + + ```ts + import fa from '@ohos.ability.featureAbility'; + let parameter = { + "want": { + bundleName: "com.example.myapplication", + abilityName: "com.example.myapplication.EntryAbility" + } + } + fa.startAbility(parameter).then((data) => { + console.info('startAbility success'); + }).catch((error) => { + console.error('startAbility failed.'); + }) + ``` + +- Sample code of **startAbility()** in the stage model: + + ```ts + // context is a member of the ability object and is required for invoking inside a non-ability object. + // Pass in the Context object. + let wantInfo = { + bundleName: "com.example.myapplication", + abilityName: "EntryAbility" + }; + this.context.startAbility(wantInfo).then((data) => { + console.info('startAbility success.'); + }).catch((error) => { + console.error('startAbility failed.'); + }) + ``` diff --git a/en/application-dev/application-models/app-deviceconfig-switch.md b/en/application-dev/application-models/app-deviceconfig-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..1092c21081cd9a8d62c92a1a68ba434efee7c8c9 --- /dev/null +++ b/en/application-dev/application-models/app-deviceconfig-switch.md @@ -0,0 +1,30 @@ +# Switching of app and deviceConfig + + +To help you better maintain the configuration of application-level attributes, OpenHarmony has extracted the **app** and **deviceConfig** tags from the **config.json** file to the **app.json5** file and changed certain tag names in the stage model. + +**Table 1** Comparison of the app tag in the configuration files + +| Configuration Item| app in config.json| app in app.json5| +| -------- | -------- | -------- | +| Internal version number of an application| "version": {
"code": 1,
} | "versionCode": 1 , | +| Text description of the version number, which is displayed to users| "version": {
"name": "1.0.0",
} | "versionName" : "1.0.0" , | +| Earliest compatible version of the application| "version": {
"minCompatibleVersionCode": 1,
} | "minCompatibleVersionCode" : 1 , | +| Minimum API version required for application running| "apiVersion": {
"compatible": 7,
} | "minAPIVersion" : 7 , | +| Target API version required for application running| "apiVersion": {
"target": 8,
} | "targetApiVersion" : 8 , | +| Type of the target API version required for application running| "apiVersion": {
"releaseType": Release,
} | "apiReleaseType": "Release" , | + + +OpenHarmony has reconstructed the [deviceConfig](../quick-start/deviceconfig-structure.md) tag of the **config.json** file in the **app.json5** file. It has integrated the fields related to device information under **deviceConfig** into the **app** tag of the [app.json5](../quick-start/app-configuration-file.md) file. + +**Table 2** Comparison of the deviceConfig tag in the configuration files + +| deviceConfig in the FA Model| Description| Stage Model| Difference| +| -------- | -------- | -------- | -------- | +| deviceConfig| Device information.| / | This tag is no longer available in the stage model. In the stage model, device information is configured under the **app** tag.| +| process | Name of the process running the application or ability. If the **process** attribute is configured in the **deviceConfig** tag, all abilities of the application run in this process. You can set the **process** attribute for a specific ability in the **abilities** attribute, so that the ability can run in the particular process.| / | The stage model does not support the configuration of process names.| +| keepAlive | Whether the application is always running. This attribute applies only to system applications and does not take effect for third-party applications.| / | The stage model does not support changing of the model control mode for system applications.| +| supportBackup | Whether the application supports data backup and restore.| / | This configuration is not supported in the stage model.| +| compressNativeLibs | Whether the **libs** libraries are packaged in the HAP file after being compressed.| / | This configuration is not supported in the stage model.| +| network | Network security configuration.| / | This configuration is not supported in the stage model.| + diff --git a/en/application-dev/application-models/application-component-configuration-fa.md b/en/application-dev/application-models/application-component-configuration-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..4cc1c9ad6831f0e54ae4c70f4f7229a7abc7c62f --- /dev/null +++ b/en/application-dev/application-models/application-component-configuration-fa.md @@ -0,0 +1,40 @@ +# Application- or Component-Level Configuration (FA Model) + + +When developing an application, you may need to configure certain tags to identify the application, such as the bundle name and application icon. This topic describes key tags that need to be configured during application development. + + +- **Configuring the bundle name** + + The bundle name is specified by the **bundleName** field under **app** in the **config.json** file. This field uniquely identifies an application. The bundle name can contain only letters, digits, underscores (_), and periods (.). It must start with a letter. The bundle name is a string with 7 to 127 bytes of a reverse domain name, for example, **com.example.myapplication**. It is recommended that the first part is the top-level domain **"com"**, and the second part is the vendor or individual name, which can be of multiple levels. For details about the configuration, see [app](../quick-start/app-structure.md). + +- **Configuring the application icon and label** + + The FA model does not support direct configuration of application icons and labels. Instead, the icon and label of a PageAbility component that meet the rules are used as the application icon and label. For details about the rules, see [PageAbility Component](pageability-configuration.md). The icon is specified by the **icon** field under **abilities** in the **config.json** file. The icon must be configured in the resource file on DevEco Studio, and the path of the icon must be **/resource/base/media**. An example value is **$media:ability_icon**. The label is the index of the resource file. It identifies the name of the ability presented to users. The label value can be an ability name or a resource index to the ability name in multiple languages. In the **skills** attribute of the ability, if the **actions** value contains **action.system.home** and the **entities** value contains **entity.system.home**, the icon and label of the ability is used as the application icon and label. If multiple abilities address this condition, the icon and label of the first candidate ability is used as the application icon and label. For details about the configuration, see [abilities](../quick-start/module-structure.md). + + ```json + "abilities": [ + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "skills": [ + { + "entities": ["entity.system.home"], + "actions": ["action.system.home"] + } + ] + // ... + } + ``` + +- **Configuring application version declaration** + + To declare the application version, set the **version** field under **app** in the **config.json** file to specify the version number, version name, and earliest compatible version number. For details about the configuration, see [version](../quick-start/module-structure.md). + +- **Configuring device types supported by the module** + + To configure the device types supported by the module, set the **deviceType** field in the **config.json** file. If a certain device type is added to **deviceTypes**, the module can run on that device. For details about the configuration, see [deviceType](../quick-start/module-structure.md). + +- **Configuring the component permission** + + To request component permissions, set the **reqPermission** field under **module** in the **config.json** file. This field declares the name of the permission to request, the reason for requesting the permission, and the scenario where the permission is used. For details about the configuration, see [reqPermission](../quick-start/module-structure.md). + diff --git a/en/application-dev/application-models/application-component-configuration-stage.md b/en/application-dev/application-models/application-component-configuration-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..de9e29941b5ddcc9e29f62ddc039fb38b6bc54b6 --- /dev/null +++ b/en/application-dev/application-models/application-component-configuration-stage.md @@ -0,0 +1,72 @@ +# Application- or Component-Level Configuration (Stage Model) + + +When developing an application, you may need to configure certain tags to identify the application, such as the bundle name and application icon. This topic describes key tags that need to be configured during application development. Icons and labels are usually configured together. There is the application icon, application label, entry icon, and entry label, which correspond to the **icon** and **label** fields in the [app.json5 file](../quick-start/app-configuration-file.md) and [module.json5 file](../quick-start/module-configuration-file.md). The application icon and label are used in **Settings**. For example, they are displayed in the application list in **Settings**. The entry icon is displayed on the device's home screen after the application is installed. The entry icon maps to a [UIAbility](uiability-overview.md) component. Therefore, an application can have multiple entry icons and labels. When you touch one of them, the corresponding UIAbility page is displayed. + +**Figure 1** Icons and labels + +![application-component-configuration-stage](figures/application-component-configuration-stage.png) + + +- **Configuring the bundle name** + + The bundle name is specified by the **bundleName** field in the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** directory of the project. This field uniquely identifies an application. You are advised to use the reverse domain name notion, for example, *com.example.demo*, where the first part is the domain suffix **com**, the second part is the vendor/individual name, and the third part is the application name, which can be of multiple levels. + +- **Configuring the application icon and label** + + The application icon is specified by the **icon** field in the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** directory of the project. The **icon** field must be set to the index of an image so that the image is displayed as the application icon. The application icon is usually displayed in an application list, for example, the application list in **Settings**. + + The application label is specified by the **label** field in the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** module of the project. The **label** field specifies the application name displayed to users. It must be set to the index of a string resource. + + The **icon** and **label** fields in the **app.json5** file are under **app**, as follows: + + ```json + { + "app": { + "icon": "$media:app_icon", + "label": "$string:app_name" + // ... + } + } + ``` + +- **Configuring the entry icon and label** + + The entry icon and label are configured by specifying **icon** and **label** under **abilities** in the [module.json5 file](../quick-start/module-configuration-file.md). For example, if you want to display the icon and label of the UIAbility component on the home screen, add **entity.system.home** to **entities** and **action.system.home** to **actions** under **skills**. If the preceding fields are configured for multiple UIAbility components of an application, multiple icons and labels are displayed on the home screen, corresponding to their respective UIAbility component. + + ```json + { + "module": { + // ... + "abilities": [ + { + // The information starting with $ is the resource value. + "icon": "$media:icon", + "label": "$string:EntryAbility_label", + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + } + ] + } + } + ``` +- **Configuring application version declaration** + + To declare the application version, configure the **versionCode** and **versionName** fields in the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** directory of the project. **versionCode** specifies the version number of the application. The value is a 32-bit non-negative integer. It is used only to determine whether a version is later than another version. A larger value indicates a later version. **versionName** provides the text description of the version number. + +- **Configuring device types supported by the module** + + To configure the device types supported by the module, set the **deviceTypes** field in the [module.json5 file](../quick-start/module-configuration-file.md). If a certain device type is added to **deviceTypes**, the module can run on that device. + +- **Configuring the module permission** + + The **requestPermission** field in the [module.json5 file](../quick-start/module-configuration-file.md) is used to configure the permission information required by the module to access the protected part of the system or other applications. This field declares the name of the permission to request, the reason for requesting the permission, and the scenario where the permission is used. + diff --git a/en/application-dev/application-models/application-context-fa.md b/en/application-dev/application-models/application-context-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..9f68b42a873782c9fd1693c73724354cbf347ced --- /dev/null +++ b/en/application-dev/application-models/application-context-fa.md @@ -0,0 +1,66 @@ +# Context (FA Model) + + +There is only one context in the FA model. All capabilities in the context are provided through methods. The context uses these methods to extend the capabilities of the **featureAbility** class. + + +## Available APIs + +To use the context in the FA model, first import the **featureAbility** module. + + +```ts +import featureAbility from "@ohos.ability.featureAbility"; +``` + +Then, call **getContext()** to obtain the **Context** object: + + +```ts +let context = featureAbility.getContext() +``` + +For details about the APIs, see [API Reference](../reference/apis/js-apis-inner-app-context.md). + + +## How to Develop + +1. Query bundle information. + + ```ts + import featureAbility from '@ohos.ability.featureAbility' + export default { + onCreate() { + // Obtain the context and call related APIs. + let context = featureAbility.getContext(); + context.getBundleName((data, bundleName)=>{ + console.info("ability bundleName:" + bundleName) + }); + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, + } + ``` + +2. Set the display orientation of the host featureAbility. + + ```ts + import featureAbility from '@ohos.ability.featureAbility' + import bundle from '@ohos.bundle'; + + export default { + onCreate() { + // Obtain the context and call related APIs. + let context = featureAbility.getContext(); + context.setDisplayOrientation(bundle.DisplayOrientation.LANDSCAPE).then(() => { + console.info("Set display orientation.") + }) + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, + } + ``` diff --git a/en/application-dev/application-models/application-context-stage.md b/en/application-dev/application-models/application-context-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..8d49b7369bb93e26f4407313f2d9352acd7380e1 --- /dev/null +++ b/en/application-dev/application-models/application-context-stage.md @@ -0,0 +1,295 @@ +# Context (Stage Model) + + +## Overview + +[Context](../reference/apis/js-apis-inner-application-context.md) is the context of an object in an application. It provides basic information about the application, for example, **resourceManager**, **applicationInfo**, **dir** (application development path), and **area** (encrypted area). It also provides basic methods such as **createBundleContext()** and **getApplicationContext()**. The UIAbility component and ExtensionAbility derived class components have their own **Context** classes, for example, the base class **Context**, **ApplicationContext**, **AbilityStageContext**, **UIAbilityContext**, **ExtensionContext**, and **ServiceExtensionContext**. + +- The figure below illustrates the inheritance relationship of contexts. + context-inheritance + +- The figure below illustrates the holding relationship of contexts. + context-holding + +- The following describes the information provided by different contexts. + - [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md): Each UIAbility has the **Context** attribute, which provides APIs to operate the ability, obtain the ability configuration, and more. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let uiAbilityContext = this.context; + // ... + } + } + ``` + - Scenario-specific [ExtensionContext](../reference/apis/js-apis-inner-application-extensionContext.md): For example, ServiceExtensionContext, inherited from ExtensionContext, provides APIs related to background services. + + ```ts + import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'; + export default class MyService extends ServiceExtensionAbility { + onCreate(want) { + let serviceExtensionContext = this.context; + // ... + } + } + ``` + - [AbilityStageContext](../reference/apis/js-apis-inner-application-abilityStageContext.md): module-level context. It provides **HapModuleInfo** and **Configuration** in addition to those provided by the base class **Context**. + + ```ts + import AbilityStage from "@ohos.app.ability.AbilityStage"; + export default class MyAbilityStage extends AbilityStage { + onCreate() { + let abilityStageContext = this.context; + // ... + } + } + ``` + - [ApplicationContext](../reference/apis/js-apis-inner-application-applicationContext.md): application-level context. It provides APIs for subscribing to ability lifecycle changes, system memory changes, and system environment changes. The application-level context can be obtained from UIAbility, ExtensionAbility, and AbilityStage. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let applicationContext = this.context.getApplicationContext(); + // ... + } + } + ``` + + +## Typical Usage Scenarios of Context + + +This topic describes how to use the context in the following scenarios: + + +- [Obtaining the Application Development Path](#obtaining-the-application-development-path) +- [Obtaining and Modifying Encrypted Areas](#obtaining-and-modifying-encrypted-areas) +- [Creating Context of Another Application or Module](#creating-context-of-another-application-or-module) +- [Subscribing to Ability Lifecycle Changes in a Process](#subscribing-to-ability-lifecycle-changes-in-a-process) + + +### Obtaining the Application Development Path + +The following table describes the application development paths obtained from context. + +**Table 1** Application development paths + +| Name| Type| Readable| Writable| Description| +| -------- | -------- | -------- | -------- | -------- | +| cacheDir | string | Yes| No| Cache directory of the application on the internal storage.
It is the content of **Storage** of an application under **Settings > Apps & services > Apps**.| +| tempDir | string | Yes| No| Temporary file directory of the application.
Files in this directory are deleted after the application is uninstalled.| +| filesDir | string | Yes| No| File directory of the application on the internal storage.
Files in this directory may be synchronized to other directories during application migration or backup.| +| databaseDir | string | Yes| No| Storage directory of the local database.| +| bundleCodeDir | string | Yes| No| Installation directory of the application on the internal storage.| +| distributedFilesDir | string | Yes| No| Storage directory of distributed application data files.| +| preferencesDir | string | Yes| Yes| Preferences directory of the application.| + +The capability of obtaining the application development path is provided by the base class **Context**. This capability is also provided by **ApplicationContext**, **AbilityStageContext**, **UIAbilityContext**, and **ExtensionContext**. However, the paths obtained from different contexts may differ, as shown below. + +**Figure 1** Application development paths obtained from context +context-dir + +- Obtain the application-level path through **ApplicationContext**. It is recommended that global application information be stored in this path. Files stored in this path will be deleted only when the application is uninstalled. + | Name| Path| + | -------- | -------- | + | bundleCodeDir | {Path prefix}/el1/bundle/| + | cacheDir | {Path prefix}/{Encryption level}/base/cache/| + | filesDir | {Path prefix}/{Encryption level}/base/files/| + | preferencesDir | {Path prefix}/{Encryption level}/base/preferences/| + | tempDir | {Path prefix}/{Encryption level}/base/temp/| + | databaseDir | {Path prefix}/{Encryption level}/database/| + | distributedFilesDir | {Path prefix}/el2/distributedFiles/| + +- Obtain the HAP level path through **AbilityStageContext**, **UIAbilityContext**, and **ExtensionContext**. It is recommended that the HAP information be stored in this path. The file content stored in this path will be deleted when the HAP is uninstalled. The file content in the application-level path will be deleted only after all the HAPs of the application are uninstalled. + | Name| Path| + | -------- | -------- | + | bundleCodeDir | {Path prefix}/el1/bundle/| + | cacheDir | {Path prefix}/{Encryption level}/base/**haps/{moduleName}**/cache/| + | filesDir | {Path prefix}/{Encryption level}/base/**haps/{moduleName}**/files/| + | preferencesDir | {path prefix}/{encryption level}/base/**haps/{moduleName}**/preferences/| + | tempDir | {Path prefix}/{Encryption level}/base/**haps/{moduleName}**/temp/| + | databaseDir | {Path prefix}/{Encryption level}/database/**{moduleName}**/| + | distributedFilesDir | {Path prefix}/el2/distributedFiles/**{moduleName}**/| + +The sample code for obtaining the application development paths is as follows: + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let cacheDir = this.context.cacheDir; + let tempDir = this.context.tempDir; + let filesDir = this.context.filesDir; + let databaseDir = this.context.databaseDir; + let bundleCodeDir = this.context.bundleCodeDir; + let distributedFilesDir = this.context.distributedFilesDir; + let preferencesDir = this.context.preferencesDir; + // ... + } +} +``` + + +### Obtaining and Modifying Encrypted Areas + +You can read and write [the area attribute in the context](../reference/apis/js-apis-inner-application-context.md) to obtain and set an encrypted area. Two encryption levels are supported: + +- AreaMode.EL1: device-level encryption area, which is accessible after the device is powered on. + +- AreaMode.EL2: user-level encryption area, which is accessible only after the device is powered on and the password is entered (for the first time). + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + // Before storing common information, switch the encryption level to EL1. + if (this.context.area === 1) {// Obtain the area. + this.context.area = 0; // Modify the area. + } + // Store common information. + + // Before storing sensitive information, switch the encryption level to EL2. + if (this.context.area === 0) { // Obtain the area. + this.context.area = 1; // Modify the area. + } + // Store sensitive information. + } +} +``` + + +### Creating Context of Another Application or Module + +The base class **Context** provides the [createBundleContext(bundleName:string)](../reference/apis/js-apis-inner-application-context.md#contextcreatebundlecontext), [createModuleContext(moduleName:string)](../reference/apis/js-apis-inner-application-context.md#contextcreatemodulecontext), and [createModuleContext(bundleName:string, moduleName:string)](../reference/apis/js-apis-inner-application-context.md#contextcreatemodulecontext-1) methods for creating the context of other applications or modules, so as to obtain the resource information, for example, [obtaining the application development paths](#obtaining-the-application-development-path) of other modules. + +- Call **createBundleContext(bundleName:string)** to create the context of another application. + > **NOTE** + > + > To obtain the context of another application: + > + > - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Permission Application Guide](../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'; + + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let bundleName2 = "com.example.application"; + let context2 = this.context.createBundleContext(bundleName2); + let label2 = context2.applicationInfo.label; + // ... + } + } +``` + +- Call **createModuleContext(bundleName:string, moduleName:string)** to obtain the context of a specified module of another application. After obtaining the context, you can obtain the resource information of that module. + > **NOTE** + > + > To obtain the context of a specified module of another application: + > + > - Request the **ohos.permission.GET_BUNDLE_INFO_PRIVILEGED** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + > +> - This is a system API and cannot be called by third-party applications. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let bundleName2 = "com.example.application"; + let moduleName2 = "module1"; + let context2 = this.context.createModuleContext(bundleName2, moduleName2); + // ... + } + } + ``` + +- Call **createModuleContext(moduleName:string)** to obtain the context of another module in the current application. After obtaining the context, you can obtain the resource information of that module. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + let moduleName2 = "module1"; + let context2 = this.context.createModuleContext(moduleName2); + // ... + } + } + ``` + + +### Subscribing to Ability Lifecycle Changes in a Process + +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 ability lifecycle changes. + +When the ability 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, and a listener ID is returned. The ID is incremented by 1 each time the listener is registered. 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 +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +const TAG: string = "[Example].[Entry].[EntryAbility]"; + +export default class EntryAbility extends UIAbility { + lifecycleId: number; + + onCreate(want, launchParam) { + let abilityLifecycleCallback = { + onAbilityCreate(ability) { + console.info(TAG, "onAbilityCreate ability:" + JSON.stringify(ability)); + }, + onWindowStageCreate(ability, windowStage) { + console.info(TAG, "onWindowStageCreate ability:" + JSON.stringify(ability)); + console.info(TAG, "onWindowStageCreate windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageActive(ability, windowStage) { + console.info(TAG, "onWindowStageActive ability:" + JSON.stringify(ability)); + console.info(TAG, "onWindowStageActive windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageInactive(ability, windowStage) { + console.info(TAG, "onWindowStageInactive ability:" + JSON.stringify(ability)); + console.info(TAG, "onWindowStageInactive windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageDestroy(ability, windowStage) { + console.info(TAG, "onWindowStageDestroy ability:" + JSON.stringify(ability)); + console.info(TAG, "onWindowStageDestroy windowStage:" + JSON.stringify(windowStage)); + }, + onAbilityDestroy(ability) { + console.info(TAG, "onAbilityDestroy ability:" + JSON.stringify(ability)); + }, + onAbilityForeground(ability) { + console.info(TAG, "onAbilityForeground ability:" + JSON.stringify(ability)); + }, + onAbilityBackground(ability) { + console.info(TAG, "onAbilityBackground ability:" + JSON.stringify(ability)); + }, + onAbilityContinue(ability) { + console.info(TAG, "onAbilityContinue ability:" + JSON.stringify(ability)); + } + } + // 1. Obtain the application context through the context attribute. + let applicationContext = this.context.getApplicationContext(); + // 2. Register a listener for the lifecycle changes through the application context. + this.lifecycleId = applicationContext.on("abilityLifecycle", abilityLifecycleCallback); + console.info(TAG, "register callback number: " + JSON.stringify(this.lifecycleId)); + } + + onDestroy() { + let applicationContext = this.context.getApplicationContext(); + applicationContext.off("abilityLifecycle", this.lifecycleId, (error, data) => { + console.info(TAG, "unregister callback success, err: " + JSON.stringify(error)); + }); + } +} +``` diff --git a/en/application-dev/application-models/application-model-composition.md b/en/application-dev/application-models/application-model-composition.md new file mode 100644 index 0000000000000000000000000000000000000000..2d7ed88490136c6e94277e94da375278fcab0adf --- /dev/null +++ b/en/application-dev/application-models/application-model-composition.md @@ -0,0 +1,27 @@ +# Elements of the Application Model + + +The application model is the abstraction of capabilities required by OpenHarmony applications. It provides necessary components and running mechanisms for applications. With application models, you can develop applications based on a unified set of models, making application development simpler and more efficient. + + +The OpenHarmony application model consists of the following elements: + + +- Application component + + An application component is the basic unit and running entry of an application. When a user starts, uses, or exits an application, the application component transits in different states. This is called the application component lifecycle. The application component provides lifecycle callback functions, through which you can detect application [status changes](uiability-lifecycle.md). When compiling an application, you needs to compile application components and their lifecycle callback functions, and configure related information in the application configuration file. In this way, the operating system creates an application component instance based on the configuration file during running, and schedules the lifecycle callback functions, so as to execute your code. +- Application process model + + The application process model defines how application processes are created, destroyed, and communicate with each other. + +- Application thread model + + The application thread model defines how a thread in an application process is created and destroyed, how the main thread and UI thread are created, and how the threads communicate with each other. + +- Application mission management model + + The application mission management model defines how a mission is created and destroyed, and the relationship between missions and components. A mission is a record about the use of an application component instance. Each time a user starts an application component instance, a mission is generated. For example, when a user starts a video application, the video application mission is displayed on the **Recents** page. When the user clicks the mission, the system switches the mission to the foreground. If the video editing functionality in the video application is compiled by using an application component, an application component instance for video editing is created when the user starts video editing. In this case, both the video application mission and video editing mission are displayed on the **Recents** page. + +- Application configuration file + + The application configuration file contains information about the application configuration, application components, and permissions, as well as custom information. The information will be provided for the compiler, application market, and operating system in the build, distribution, and running phases. diff --git a/en/application-dev/application-models/application-model-description.md b/en/application-dev/application-models/application-model-description.md new file mode 100644 index 0000000000000000000000000000000000000000..de7e3045d79eff2c681291f8d4de55129d361245 --- /dev/null +++ b/en/application-dev/application-models/application-model-description.md @@ -0,0 +1,60 @@ +# Interpretation of the Application Model + + +## Application Model Overview + +Along its evolution, OpenHarmony has provided two application models: + +- Feature Ability (FA) model. This model is supported by OpenHarmony API version 7 and 8. It is no longer recommended. + +- Stage model. This model is supported since OpenHarmony API version 9. It is recommended and will evolve for a long time. In this model, classes such as **AbilityStage** and **WindowStage** are provided as the stage of application components and windows. That's why it is named stage model. + +The stage model is designed based on the following considerations, which make it become the recommended model: + +1. **Designed for complex applications** + + - In the stage model, multiple application components share an ArkTS engine (VM running the programming language ArkTS) instance, making it easy for application components to share objects and status while requiring less memory. +- The object-oriented development mode makes the code of complex applications easy to read, maintain, and scale. + +2. **Native support for [cross-device migration](hop-cross-device-migration.md) and [multi-device collaboration](hop-multi-device-collaboration.md) at the application component level** + + The stage model decouples application components from User Interfaces (UIs). + + - In cross-device migration scenarios, after the system migrates application component data or status between devices, it can use the declarative feature of ArkUI to restore the UI based on the data or status saved in the application components. + + - In multi-device collaboration scenarios, application components can initiate Remote Procedure Calls (RPCs) and support interaction with cross-device application components. + +3. **Support for multiple device types and window forms** + + Application component management and window management are decoupled at the architecture level. This decoupling makes it: + + - Easy to tailor application components. For example, windows can be tailored for devices without screens. + + - Easy to extend the window forms. + + - Possible for application components to use the same lifecycle on multiple devices (such as desktop devices and mobile devices). + +4. **Well balanced application capabilities and system management costs** + + The stage model redefines the boundary of application capabilities to well balance application capabilities and system management costs. + + - Diverse application components (such as widgets and input methods) for specific scenarios. + - Standardized background process management. To deliver a better user experience, the stage model manages background application processes in a more orderly manner. Applications cannot reside in the background randomly, and their background behavior is strictly managed to minimize malicious behavior. + + +## Differences Between the FA Model and Stage Model + +In the stage model, multiple application components share the same ArkTS engine instance. In the FA model, each application component exclusively uses an ArkTS engine instance. This is their biggest difference. In the stage model, application components can easily share objects and status while requiring less memory. Therefore, you are advised to use the stage model when developing complex applications in distributed scenarios. + +The table below describes their differences in detail. + + **Table 1** Differences between the FA model and stage model + +| Item| FA model| Stage model| +| -------- | -------- | -------- | +| **Application component**| 1. Component classification
- PageAbility: has the UI and supports user interaction. For details, see [PageAbility Component Overview](pageability-overview.md).
- ServiceAbility: provides background services and has no UI. For details, see [ServiceAbility Component Overview](serviceability-overview.md).
- DataAbility: provides the data sharing capability and has no UI. For details, see [DataAbility Component Overview](dataability-overview.md).
2. Development mode
Application components are specified by exporting anonymous objects and fixed entry files. You cannot perform derivation. It is inconvenient for capability expansion.| 1. Component classification
- UIAbility: has the UI and supports user interaction. For details, see [UIAbility Component Overview](uiability-overview.md).
- ExtensionAbility: provides extension capabilities (such as widget and input methods) for specific scenarios. For details, see [ExtensionAbility Component Overview](extensionability-overview.md).
2. Development mode
The object-oriented mode is used to provide open application components as classes. You can derive application components for capability expansion.| +| **Process model**| There are two types of processes:
1. Main process
2. Rendering process
For details, see [Process Model (FA Model)](process-model-fa.md). | There are three types of processes:
1. Main process
2. ExtensionAbility process
3. Rendering process
For details, see [Process Model (Stage Model)](process-model-stage.md). | +| **Thread model**| 1. ArkTS engine instance creation
A process can run multiple application component instances, and each application component instance runs in an independent ArkTS engine instance.
2. Thread model
Each ArkTS engine instance is created on an independent thread (non-main thread). The main thread does not have an ArkTS engine instance.
3. Intra-process object sharing: not supported.
For details, see [Thread Model (FA Model)](thread-model-fa.md). | 1. ArkTS engine instance creation
A process can run multiple application component instances, and all application component instances share one ArkTS engine instance.
2. Thread model
The ArkTS engine instance is created on the main thread.
3. Intra-process object sharing: supported.
For details, see [Thread Model (Stage Model)](thread-model-stage.md). | +| **Mission management model**| - A mission is created for each PageAbility component instance.
- Missions are stored persistently until the number of missions exceeds the maximum (customized based on the product configuration) or users delete missions.
- PageAbility components do not form a stack structure.
For details, see [Mission Management Scenarios](mission-management-overview.md).| - A mission is created for each UIAbility component instance.
- Missions are stored persistently until the number of missions exceeds the maximum (customized based on the product configuration) or users delete missions.
- UIAbility components do not form a stack structure.
For details, see [Mission Management Scenarios](mission-management-overview.md).| +| **Application configuration file**| The **config.json** file is used to describe the application, HAP, and application component information.
For details, see [Application Configuration File Overview (FA Model)](../quick-start/application-configuration-file-overview-fa.md).| The **app.json5** file is used to describe the application information, and the **module.json5** file is used to describe the HAP and application component information.
For details, see [Application Configuration File Overview (Stage Model)](../quick-start/application-configuration-file-overview-stage.md).| + diff --git a/en/application-dev/application-models/background-services.md b/en/application-dev/application-models/background-services.md new file mode 100644 index 0000000000000000000000000000000000000000..77ed5d98c0798037e57f2867b8e216928bfc2240 --- /dev/null +++ b/en/application-dev/application-models/background-services.md @@ -0,0 +1,7 @@ +# Background Services (Stage Model) + + +The stage model uses ServiceExtensionAbility to provide background services. A system application can implement a background service and provide external capabilities. For example, if system application A implements a background service, third-party application B can communicate with A by connecting to A's background service. + + +For details about ServiceExtensionAbility, see [Background Service Development](serviceextensionability.md). diff --git a/en/application-dev/application-models/bind-serviceability-from-stage.md b/en/application-dev/application-models/bind-serviceability-from-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..2d99fddfe503db082cf7613f3875dcf490331dd9 --- /dev/null +++ b/en/application-dev/application-models/bind-serviceability-from-stage.md @@ -0,0 +1,90 @@ +# Connecting to a ServiceAbility from the Stage Model + + +This topic describes how the two application components of the stage model connect to the ServiceAbility component of the FA model. + + +## UIAbility Accessing a ServiceAbility + +A UIAbility accesses a ServiceAbility in the same way as it accesses a ServiceExtensionAbility. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + console.info("EntryAbility onCreate"); + } + onDestroy() { + console.info("EntryAbility onDestroy") + } + onWindowStageCreate(windowStage) { + console.info("EntryAbility onWindowStageCreate") + let want = { + bundleName: "com.ohos.fa", + abilityName: "ServiceAbility", + }; + + let options = { + onConnect:function (elementName, proxy) { + console.info("onConnect called."); + }, + onDisconnect:function (elementName) { + console.info("onDisconnect called."); + }, + onFailed:function (code) { + console.info("onFailed code is: " + code); + } + }; + let connectionId = this.context.connectServiceExtensionAbility(want, options); + } + onWindowStageDestroy() { + console.info("EntryAbility onWindowStageDestroy") + } + onForeground() { + console.info("EntryAbility onForeground") + } + onBackground() { + console.info("EntryAbility onBackground") + } +} +``` + + +## ExtensionAbility Accessing a ServiceAbility + +The following uses the ServiceExtensionAbility component as an example to describe how an ExtensionAbility accesses a ServiceAbility. A ServiceExtensionAbility accesses a ServiceAbility in the same way as it accesses another ServiceExtensionAbility. + + +```ts +import Extension from '@ohos.app.ability.ServiceExtensionAbility' + +export default class ServiceExtension extends Extension { + onCreate(want) { + console.info("ServiceExtension onCreate") + } + onDestroy() { + console.info("ServiceExtension onDestroy") + } + onRequest(want, startId) { + console.info("ServiceExtension onRequest") + let wantFA = { + bundleName: "com.ohos.fa", + abilityName: "ServiceAbility", + }; + let options = { + onConnect:function (elementName, proxy) { + console.info("onConnect called."); + }, + onDisconnect:function (elementName) { + console.info("onDisconnect called."); + }, + onFailed:function (code) { + console.info("onFailed code is: " + code); + } + }; + let connectionId = this.context.connectServiceExtensionAbility(wantFA, options); + } +} +``` diff --git a/en/application-dev/application-models/bind-serviceextensionability-from-fa.md b/en/application-dev/application-models/bind-serviceextensionability-from-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..e5f90bf9d6b7616261d2ae1eb1e62438fe2e71e3 --- /dev/null +++ b/en/application-dev/application-models/bind-serviceextensionability-from-fa.md @@ -0,0 +1,60 @@ +# Connecting to a ServiceExtensionAbility from the FA Model + + +This topic describes how the three application components of the FA model connect to the ServiceExtensionAbility component of the stage model. + + +## PageAbility Accessing a ServiceExtensionAbility + +A PageAbility accesses a ServiceExtensionAbility in the same way as it accesses a ServiceAbility. + + +```ts +import featureAbility from '@ohos.ability.featureAbility'; + +let want = { + bundleName: "com.ohos.stage", + abilityName: "com.ohos.stage.ServiceExtensionAbility" +}; + +let faConnect = { + onConnect:function (elementName, proxy) { + console.info("Faconnection onConnect called."); + }, + onDisconnect:function (elementName) { + console.info("Faconnection onDisconnect called."); + }, + onFailed:function (code) { + console.info("Faconnection onFailed code is: " + code); + } +}; +let connectionId = featureAbility.connectAbility(want, faConnect); +``` + + +## ServiceAbility or DataAbility Accessing a ServiceExtensionAbility + +A ServiceAbility or DataAbility accesses a ServiceExtensionAbility in the same way as it accesses a ServiceAbility. + + +```ts +import particleAbility from '@ohos.ability.particleAbility'; + +let want = { + bundleName: "com.ohos.stage", + abilityName: "com.ohos.stage.ServiceExtensionAbility" +}; + +let faConnect = { + onConnect:function (elementName, proxy) { + console.info("Faconnection onConnect called."); + }, + onDisconnect:function (elementName) { + console.info("Faconnection onDisconnect called."); + }, + onFailed:function (code) { + console.info("Faconnection onFailed code is: " + code); + } +}; +let connectionId = particleAbility.connectAbility(want, faConnect); +``` diff --git a/en/application-dev/application-models/common-event-fa.md b/en/application-dev/application-models/common-event-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..9e2f44144d8f028c61c538b48797f5842a48d2a7 --- /dev/null +++ b/en/application-dev/application-models/common-event-fa.md @@ -0,0 +1,4 @@ +# Common Events (FA Model) + + +For details, see [Common Events](common-event-overview.md) in the stage model. diff --git a/en/application-dev/application-models/common-event-overview.md b/en/application-dev/application-models/common-event-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..0d3788b41b516d0af9619d320ceeefc3f52c74c5 --- /dev/null +++ b/en/application-dev/application-models/common-event-overview.md @@ -0,0 +1,28 @@ +# Introduction to Common Events + + +OpenHarmony provides Common Event Service (CES) for applications to subscribe to, publish, and unsubscribe from common events. + + +Common events are classified into system common events and custom common events. + + +- System common events: defined in CES. Only system applications and system services can publish system common events, such as HAP installation, update, and uninstall. For details about the supported system common events, see [Support](../reference/apis/js-apis-commonEventManager.md#support). + +- Custom common events: customized by applications to implement cross-process event communication. + + +Common events are also classified into unordered, ordered, and sticky common events. + + +- Unordered common events: CES forwards common events based on the subscription sequence, regardless of whether subscribers receive the events. + +- Ordered common event: CES forwards common events to the next subscriber only after receiving a reply from the previous subscriber. + +- Sticky common event: a public event that can be sent to a subscriber before they initiate a subscription. Only system applications or system services can send sticky common event, and they must request the **ohos.permission.COMMONEVENT_STICKY** permission. For details about the configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + + +Each application can subscribe to common events as required. After your application subscribes to a common event, the system sends it to your application every time the event is published. Such an event may be published by the system, other applications, or your own application. + +**Figure 1** Common events +![common-event](figures/common-event.png) \ No newline at end of file diff --git a/en/application-dev/application-models/common-event-publish.md b/en/application-dev/application-models/common-event-publish.md new file mode 100644 index 0000000000000000000000000000000000000000..b29c137319fcbb1fe4eaff8e262dca1a403c87e4 --- /dev/null +++ b/en/application-dev/application-models/common-event-publish.md @@ -0,0 +1,78 @@ +# Publishing Common Events + + +## When to Use + +You can use [publish()](../reference/apis/js-apis-commonEventManager.md#commoneventmanagerpublish) to publish a custom common event, which can carry data for subscribers to parse and process. + +> **NOTE** +> +> Subscribers can receive sticky common events that have been sent. However, they must subscribe to common events of other types before receiving them. For details about subscription, see [Subscribing to Common Events](common-event-subscription.md). + + +## Available APIs + +For details about the APIs, see [API Reference](../reference/apis/js-apis-commonEventManager.md#commoneventmanagerpublish). + +| API| Description| +| -------- | -------- | +| publish(event: string, callback: AsyncCallback) | Publishes a common event.| +| publish(event: string, options: [CommonEventPublishData](../reference/apis/js-apis-commonEventManager.md#commoneventpublishdata), callback: AsyncCallback) | Publishes a common event with given attributes.| + + +## Publishing a Common Event That Does Not Carry Information + +Common events that do not carry information can be published only as unordered common events. + +1. Import the **commonEventManager** module. + + ```ts + import commonEventManager from '@ohos.commonEventManager'; + ``` + +2. Pass in the common event name and callback, and publish the event. + + ```ts + // Publish a common event. + commonEventManager.publish("usual.event.SCREEN_OFF", (err) => { + if (err) { + console.error(`[CommonEvent] PublishCallBack err=${JSON.stringify(err)}`); + } else { + console.info(`[CommonEvent] Publish success`); + } + }) + ``` + + +## Publishing a Common Event That Carries Information + +Common events that carry information can be published as unordered, ordered, and sticky common events, which are specified by the **isOrdered** and **isSticky** fields of [CommonEventPublishData](../reference/apis/js-apis-commonEventManager.md#commoneventpublishdata). + +1. Import the **commonEventManager** module. + + ```ts + import commonEventManager from '@ohos.commonEventManager'; + ``` + +2. Pass in the common event name and callback, and publish the event. + + ```ts + // Attributes of a common event. + let options = { + code: 1, // Result code of the common event. + data: "initial data", // Result data of the common event. + } + ``` + +3. Pass in the common event name, attributes of the common event, and callback, and publish the event. + + ```ts + // Publish a common event. + commonEventManager.publish("usual.event.SCREEN_OFF", options, (err) => { + if (err) { + console.error('[CommonEvent] PublishCallBack err=' + JSON.stringify(err)); + } else { + console.info('[CommonEvent] Publish success') + } + }) + ``` diff --git a/en/application-dev/application-models/common-event-subscription.md b/en/application-dev/application-models/common-event-subscription.md new file mode 100644 index 0000000000000000000000000000000000000000..ce61e40458a7cbd5c9ec226138535da93d3766b1 --- /dev/null +++ b/en/application-dev/application-models/common-event-subscription.md @@ -0,0 +1,69 @@ +# Subscribing to Common Events + + +## When to Use + +You can create a subscriber object to subscribe to a common event so as to obtain the parameters passed in the event. Certain system common events [require specific permissions](../security/accesstoken-guidelines.md) to subscribe to. For details, see [Required Permissions](../reference/apis/js-apis-commonEventManager.md#support). + + +## Available APIs + +For details about the APIs, see [API Reference](../reference/apis/js-apis-commonEventManager.md#commoneventmanagersubscribe). + +| API| Description| +| -------- | -------- | +| createSubscriber(subscribeInfo: [CommonEventSubscribeInfo](../reference/apis/js-apis-commonEventManager.md#commoneventsubscribeinfo), callback: AsyncCallback<[CommonEventData](../reference/apis/js-apis-commonEventManager.md#commoneventdata)>): void | Creates a subscriber. This API uses an asynchronous callback to return the result.| +| createSubscriber(subscribeInfo: CommonEventSubscribeInfo): Promise<CommonEventSubscriber> | Creates a subscriber. This API uses a promise to return the result.| +| subscribe(subscriber: CommonEventSubscriber, callback: AsyncCallback): void | Subscribes to common events.| + + +## How to Develop + +1. Import the **commonEventManager** module. + + ```ts + import commonEventManager from '@ohos.commonEventManager'; + ``` + +2. Create a **subscribeInfo** object. For details about the data types and parameters of the object, see [CommonEventSubscribeInfo](../reference/apis/js-apis-commonEventManager.md#commoneventsubscribeinfo). + + ```ts + // Used to save the created subscriber object for subsequent subscription and unsubscription. + let subscriber = null; + // Subscriber information. + let subscribeInfo = { + events: ["usual.event.SCREEN_OFF"], // Subscribe to the common event screen-off. + } + ``` + +3. Create a subscriber object and save the returned object for subsequent operations such as subscription and unsubscription. + + ```ts + // Callback for subscriber creation. + commonEventManager.createSubscriber(subscribeInfo, (err, data) => { + if (err) { + console.error(`[CommonEvent] CreateSubscriberCallBack err=${JSON.stringify(err)}`); + } else { + console.info(`[CommonEvent] CreateSubscriber success`); + subscriber = data; + // Callback for common event subscription. + } + }) + ``` + +4. Create a subscription callback, which is triggered when an event is received. The data returned in the subscription callback contains information such as the common event name and data carried by the publisher. For details about the data types and parameters of the common event data, see [CommonEventData](../reference/apis/js-apis-commonEventManager.md#commoneventdata). + + ```ts + // Callback for common event subscription. + if (subscriber !== null) { + commonEventManager.subscribe(subscriber, (err, data) => { + if (err) { + console.error(`[CommonEvent] SubscribeCallBack err=${JSON.stringify(err)}`); + } else { + console.info(`[CommonEvent] SubscribeCallBack data=${JSON.stringify(data)}`); + } + }) + } else { + console.error(`[CommonEvent] Need create subscriber`); + } + ``` diff --git a/en/application-dev/application-models/common-event-unsubscription.md b/en/application-dev/application-models/common-event-unsubscription.md new file mode 100644 index 0000000000000000000000000000000000000000..c87017ef08c05e8a22097c4bd2a05f52fc758134 --- /dev/null +++ b/en/application-dev/application-models/common-event-unsubscription.md @@ -0,0 +1,40 @@ +# Unsubscribing from Common Events + + +## When to Use + +You can call [unsubscribe()](../reference/apis/js-apis-commonEventManager.md#commoneventmanagerunsubscribe) to unsubscribe from a common event that is no longer required. + + +## Available APIs + +| API| Description| +| -------- | -------- | +| unsubscribe(subscriber: CommonEventSubscriber, callback?: AsyncCallback) | Unsubscribes from a common event.| + + +## How to Develop + +1. Import the **commonEventManager** module. + + ```ts + import commonEventManager from '@ohos.commonEventManager'; + ``` + +2. Subscribe to an event by following the procedure described in [Subscribing to Common Events](common-event-subscription.md). + +3. Call **unsubscribe** in **CommonEvent** to unsubscribe from the common event. + + ```ts + // The subscriber object iscreated during event subscription. + if (subscriber !== null) { + commonEventManager.unsubscribe(subscriber, (err) => { + if (err) { + console.error(`[CommonEvent] UnsubscribeCallBack err=${JSON.stringify(err)}`); + } else { + console.info(`[CommonEvent] Unsubscribe`); + subscriber = null; + } + }) + } + ``` diff --git a/en/application-dev/application-models/component-startup-rules-fa.md b/en/application-dev/application-models/component-startup-rules-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..db64e8c093df679a9e52d6bc753e4935a21c25be --- /dev/null +++ b/en/application-dev/application-models/component-startup-rules-fa.md @@ -0,0 +1,69 @@ +# Component Startup Rules (FA Model) + + +Component startup refers to the behavior of starting or connecting to an application component. + + +- Start the PageAbility and ServiceAbility. For example, you can use **startAbility()**. + +- Connect to the ServiceAbility and DataAbility. For example, you can use **connectAbility()** and **acquireDataAbilityHelper()**. + + +To deliver a better user experience, OpenHarmony restricts the following behavior: + + +- A background application randomly displays a dialog box, such as an ads pop-up. + +- Background applications wake up each other. This type of behavior occupies system resources and increases power consumption, or even causes system frozen. + +- A foreground application randomly redirects to another application, for example, redirecting to the payment page of another application. This type of behavior poses security risks. + + +In view of this, OpenHarmony formulates a set of component startup rules, as follows: + + +- **Before starting a component of another application, verify the visible field of the target component.** + - This rule applies only to cross-application scenarios. + - If the **visible** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission. + - For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities). + +- **Before starting a component of a background application, verify the BACKGROUND permission.** + - An application is considered as a foreground application only when the application process gains focus or its UIAbility component is running in the foreground. + - Verify the **ohos.permission.START_ABILITIES_FROM_BACKGROUND** permission. + +- **Before starting the ServiceAbility or DataAbility component of an application, verify the AssociateWakeUp field of the target application.** + - This rule applies only to cross-application scenarios. + - This rule is valid only when the target component is ServiceAbility or DataAbility. + - The ServiceAbility and DataAbility of an application can be accessed by others only when **AssociateWakeUp** of the target application is set to **true**. + - The **AssociateWakeUp** field can be configured only for preset applications. For other applications, this field is set to **false** by default. + + +> **NOTE** +> 1. Component startup control has been implemented since OpenHarmony v3.2 Release. +> +> 2. The new component startup rules are more strict than the original ones. You must be familiar with the new startup rules to prevent service exceptions. + + + + +## Intra-Device Component Startup Rules + + The rules for starting components on the same device vary in the following scenarios: + +- Starting a PageAbility + +- Starting a ServiceAbility or DataAbility + +![startup-rule](figures/component-startup-inner-fa.png) + + +## Inter-Device Component Startup Rules + + The rules for starting components on a different device vary in the following scenarios: + +- Starting a PageAbility + +- Starting a ServiceAbility + +![component-startup-rules](figures/component-startup-inter-fa.png) + diff --git a/en/application-dev/application-models/component-startup-rules.md b/en/application-dev/application-models/component-startup-rules.md new file mode 100644 index 0000000000000000000000000000000000000000..0e6c2ce33c68913221c7b09f02e96327b0ea1c30 --- /dev/null +++ b/en/application-dev/application-models/component-startup-rules.md @@ -0,0 +1,64 @@ +# Component Startup Rules (Stage Model) + + +Component startup refers to the behavior of starting or connecting to an application component. + + +- Start the UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility components. For example, you can use **startAbility()**, **startServiceExtensionAbility()**, and **startAbilityByCall()**. + +- Connect to the ServiceExtensionAbility and DataShareExtensionAbility components. For example, you can use **connectServiceExtensionAbility()** and **createDataShareHelper()**. + + +To deliver a better user experience, OpenHarmony restricts the following behavior: + + +- A background application randomly displays a dialog box, such as an ads pop-up. + +- Background applications wake up each other. This type of behavior occupies system resources and increases power consumption, or even causes system frozen. + +- A foreground application randomly redirects to another application, for example, redirecting to the payment page of another application. This type of behavior poses security risks. + + +In view of this, OpenHarmony formulates a set of component startup rules, as follows: + + +- **Before starting a component of another application, verify the visible field of the target component.** + - If the **visible** field of the target component is **false**, verify the **ohos.permission.START_INVISIBLE_ABILITY** permission. + - For details, see [Component Visible Configuration](../quick-start/module-configuration-file.md#abilities). + +- **Before starting a component of a background application, verify the BACKGROUND permission.** + - An application is considered as a foreground application only when the application process gains focus or its UIAbility component is running in the foreground. + - Verify the **ohos.permission.START_ABILITIES_FROM_BACKGROUND** permission. + +- **When the startAbilityByCall() method is used, verify the call permission.** For details, see [Using Ability Call to Implement UIAbility Interaction](uiability-intra-device-interaction.md#using-ability-call-to-implement-uiability-interaction) and [Using Cross-Device Ability Call](hop-multi-device-collaboration.md#using-cross-device-ability-call). + - Verify the **ohos.permission.ABILITY_BACKGROUND_COMMUNICATION** permission. + + +> **NOTE** +> +> - Component startup control has been implemented since OpenHarmony v3.2 Release. +> +> - The new component startup rules are more strict than the original ones. You must be familiar with the new startup rules to prevent service exceptions. + + +## Intra-Device Component Startup Rules + + The rules for starting components on the same device vary in the following scenarios: + +- Starting or connecting to the UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility components + +- Using **startAbilityByCall()** to start the UIAbility component + +![startup-rule](figures/component-startup-inner-stage.png) + + +## Inter-Device Component Startup Rules + + The rules for starting components on a different device vary in the following scenarios: + +- Starting or connecting to the UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility components + +- Using **startAbilityByCall()** to start the UIAbility component + +![component-startup-rules](figures/component-startup-inter-stage.png) + diff --git a/en/application-dev/application-models/configuration-file-diff.md b/en/application-dev/application-models/configuration-file-diff.md new file mode 100644 index 0000000000000000000000000000000000000000..745f2702cab12b8ef99e174c924d49cf2217bf2b --- /dev/null +++ b/en/application-dev/application-models/configuration-file-diff.md @@ -0,0 +1,11 @@ +# Differences in Configuration Files + + +The FA model uses the [config.json file](../quick-start/application-configuration-file-overview-fa.md) to describe the basic information about an application. An application can have multiple modules, and each module has a **config.json** file. The **config.json** file consists of three parts: **app**, **deviceConfig**, and **module**. The **app** tag is used to configure application-level attributes. If an application has multiple modules, the **app** configuration in each **config.json** file must be consistent. + + +The stage model uses the [app.json5](../quick-start/app-configuration-file.md) and [module.json](../quick-start/module-configuration-file.md) files to describe the basic information about an application. An application can have multiple modules but only one **app.json5** file. This file is used to configure application-level attributes and takes effect for all the modules. Each module has a **module.json5** file, which is used to configure module-level attributes and takes effect only for the current module. + +**Figure 1** Configuration file differences +![comparison-of-configuration-file](figures/comparison-of-configuration-file.png) + diff --git a/en/application-dev/application-models/connect-serviceability.md b/en/application-dev/application-models/connect-serviceability.md new file mode 100644 index 0000000000000000000000000000000000000000..ac2acb898a3bd7ef905b8a33dc10f7980ce74548 --- /dev/null +++ b/en/application-dev/application-models/connect-serviceability.md @@ -0,0 +1,93 @@ +# Connecting to a ServiceAbility + + +If a ServiceAbility wants to interact with a PageAbility or a ServiceAbility in another application, you must first create a connection by calling **connectAbility()**. This method is defined in the **featureAbility** class for the PageAbility and in the **particleAbility** class for the ServiceAbility. For details about the connection rules, see [Component Startup Rules](component-startup-rules.md). When calling **connectAbility()**, you should pass in a **Want** object containing information about the target ServiceAbility and an **IAbilityConnection** object. **IAbilityConnection** provides the following APIs that you need to implement. + +**Table 1** IAbilityConnection APIs + +| API| Description| +| -------- | -------- | +| onConnect() | Callback invoked when the ServiceAbility is connected.| +| onDisconnect() | Callback invoked when the ServiceAbility is disconnected.| +| onFailed() | Callback invoked when the connection to the ServiceAbility fails.| + + +The following sample code enables the PageAbility to create connection callback instances and connect to the local ServiceAbility: + +```ts +import rpc from "@ohos.rpc" +import prompt from '@system.prompt' +import featureAbility from '@ohos.ability.featureAbility' + +let option = { + onConnect: function onConnectCallback(element, proxy) { + console.info(`onConnectLocalService onConnectDone`) + if (proxy === null) { + prompt.showToast({ + message: "Connect service failed" + }) + return + } + let data = rpc.MessageParcel.create() + let reply = rpc.MessageParcel.create() + let option = new rpc.MessageOption() + data.writeInterfaceToken("connect.test.token") + proxy.sendRequest(0, data, reply, option) + prompt.showToast({ + message: "Connect service success" + }) + }, + onDisconnect: function onDisconnectCallback(element) { + console.info(`onConnectLocalService onDisconnectDone element:${element}`) + prompt.showToast({ + message: "Disconnect service success" + }) + }, + onFailed: function onFailedCallback(code) { + console.info(`onConnectLocalService onFailed errCode:${code}`) + prompt.showToast({ + message: "Connect local service onFailed" + }) + } +} + +let request = { + bundleName: "com.example.myapplication", + abilityName: "com.example.myapplication.ServiceAbility", +} +let connId = featureAbility.connectAbility(request, option) +``` + + +When the ServiceAbility is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the ServiceAbility. OpenHarmony provides a default implementation of **IRemoteObject**. You can extend **rpc.RemoteObject** to implement your own class of **IRemoteObject**. + + +The following sample code shows how the ServiceAbility returns itself to the caller: + +```ts +import rpc from "@ohos.rpc" + +class FirstServiceAbilityStub extends rpc.RemoteObject { + constructor(des: any) { + if (typeof des === 'string') { + super(des) + } else { + return + } + } + + onRemoteRequest(code: number, data: any, reply: any, option: any) { + console.info(`onRemoteRequest called`) + if (code === 1) { + let string = data.readString() + console.info(`string=${string}`) + let result = Array.from(string).sort().join('') + console.info(`result=${result}`) + reply.writeString(result) + } else { + console.info(`unknown request code`) + } + return true + } +} +``` diff --git a/en/application-dev/application-models/context-switch.md b/en/application-dev/application-models/context-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..2f52158f5d36be8c59f747376195e9e43078d1f9 --- /dev/null +++ b/en/application-dev/application-models/context-switch.md @@ -0,0 +1,28 @@ +# Context Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API or Field in the Stage Model| +| -------- | -------- | -------- | +| [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) | +| [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) | +| [setDisplayOrientation(orientation:bundle.DisplayOrientation, callback:AsyncCallback<void>):void;](../reference/apis/js-apis-inner-app-context.md#contextsetdisplayorientation7)
[setDisplayOrientation(orientation:bundle.DisplayOrientation):Promise<void>;](../reference/apis/js-apis-inner-app-context.md#contextsetdisplayorientation7-1) | \@ohos.screen.d.ts | [setOrientation(orientation: Orientation, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-screen.md#setorientation)
[setOrientation(orientation: Orientation): Promise<void>;](../reference/apis/js-apis-screen.md#setorientation-1) | +| [setShowOnLockScreen(show:boolean, callback:AsyncCallback<void>):void;](../reference/apis/js-apis-inner-app-context.md#contextsetshowonlockscreen7)
[setShowOnLockScreen(show:boolean):Promise<void>;](../reference/apis/js-apis-inner-app-context.md#contextsetshowonlockscreen7-1) | \@ohos.window.d.ts | [setShowOnLockScreen(showOnLockScreen: boolean): void;](../reference/apis/js-apis-window.md#setshowonlockscreen9) | +| [setWakeUpScreen(wakeUp:boolean, callback:AsyncCallback<void>):void;](../reference/apis/js-apis-inner-app-context.md#contextsetwakeupscreen7)
[setWakeUpScreen(wakeUp:boolean):Promise<void>;](../reference/apis/js-apis-inner-app-context.md#contextsetwakeupscreen7-1) | \@ohos.window.d.ts | [setWakeUpScreen(wakeUp: boolean): void;](../reference/apis/js-apis-window.md#setwakeupscreen9) | +| [getProcessInfo(callback:AsyncCallback<ProcessInfo>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetprocessinfo7)
[getProcessInfo():Promise<ProcessInfo>;](../reference/apis/js-apis-inner-app-context.md#contextgetprocessinfo7-1) | \@ohos.app.ability.abilityManager.d.ts | [getAbilityRunningInfos(callback: AsyncCallback<Array<AbilityRunningInfo>>): void;](../reference/apis/js-apis-app-ability-abilityManager.md#getabilityrunninginfos)
[getAbilityRunningInfos(): Promise<Array<AbilityRunningInfo>>;](../reference/apis/js-apis-app-ability-abilityManager.md#getabilityrunninginfos-1) | +| [getElementName(callback:AsyncCallback<ElementName>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetelementname7)
[getElementName():Promise<ElementName>;](../reference/apis/js-apis-inner-app-context.md#contextgetelementname7-1) | application\UIAbilityContext.d.ts | [abilityInfo.name: string;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)
[abilityInfo.bundleName: string;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)| +| [getProcessName(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetprocessname7)
[getProcessName():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetprocessname7-1) | \@ohos.app.ability.abilityManager.d.ts | [getAbilityRunningInfos(callback: AsyncCallback<Array<AbilityRunningInfo>>): void;](../reference/apis/js-apis-app-ability-abilityManager.md#getabilityrunninginfos)
[getAbilityRunningInfos(): Promise<Array<AbilityRunningInfo>>;](../reference/apis/js-apis-app-ability-abilityManager.md#getabilityrunninginfos-1) | +| [getCallingBundle(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetcallingbundle7)
[getCallingBundle():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetcallingbundle7-1) | There is no corresponding API in the stage model.| Applications developed on the stage model can use the **ohos.aafwk.param.callerUid** parameter of **Want.parameters** to obtain the application information of the caller.| +| [getFilesDir(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetfilesdir)
[getFilesDir():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetfilesdir-1) | application\Context.d.ts | [filesDir: string;](../reference/apis/js-apis-inner-application-context.md#attributes)| +| [getCacheDir(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetcachedir)
[getCacheDir():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetcachedir-1) | application\Context.d.ts | [cacheDir: string;](../reference/apis/js-apis-inner-application-context.md#attributes)| +| [getOrCreateDistributedDir(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetorcreatedistributeddir7)
[getOrCreateDistributedDir():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetorcreatedistributeddir7-1) | application\Context.d.ts | [distributedFilesDir: string;](../reference/apis/js-apis-inner-application-context.md#attributes)| +| [getAppType(callback:AsyncCallback<string>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetapptype7)
[getAppType():Promise<string>;](../reference/apis/js-apis-inner-app-context.md#contextgetapptype7-1) | application\UIAbilityContext.d.ts | The stage model obtains the application type through the **type** attribute of the **abilityInfo** field.
[abilityInfo.type: bundleManager.AbilityType;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)| +| [getHapModuleInfo(callback:AsyncCallback<HapModuleInfo>):void;](../reference/apis/js-apis-inner-app-context.md#contextgethapmoduleinfo7)
[getHapModuleInfo():Promise<HapModuleInfo>;](../reference/apis/js-apis-inner-app-context.md#contextgethapmoduleinfo7-1) | application\UIAbilityContext.d.ts | [currentHapModuleInfo: HapModuleInfo;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)| +| [getAppVersionInfo(callback:AsyncCallback<AppVersionInfo>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetappversioninfo7)
[getAppVersionInfo():Promise<AppVersionInfo>;](../reference/apis/js-apis-inner-app-context.md#contextgetappversioninfo7-1) | bundle\bundleInfo.d.ts | [readonly name: string;](../reference/apis/js-apis-bundleManager-bundleInfo.md#bundleinfo-1)
[readonly versionCode: number;](../reference/apis/js-apis-bundleManager-bundleInfo.md#bundleinfo-1)
[readonly versionName: string;](../reference/apis/js-apis-bundleManager-bundleInfo.md#bundleinfo-1) | +| [getApplicationContext():Context;](../reference/apis/js-apis-inner-app-context.md#contextgetapplicationcontext7) | application\Context.d.ts | [getApplicationContext(): ApplicationContext;](../reference/apis/js-apis-inner-application-context.md#contextgetapplicationcontext) | +| [getAbilityInfo(callback:AsyncCallback<AbilityInfo>):void;](../reference/apis/js-apis-inner-app-context.md#contextgetabilityinfo7)
[getAbilityInfo():Promise<AbilityInfo>;](../reference/apis/js-apis-inner-app-context.md#contextgetabilityinfo7-1) | application\UIAbilityContext.d.ts | [abilityInfo: AbilityInfo;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#attributes)| +| [isUpdatingConfigurations(callback:AsyncCallback<boolean>):void;](../reference/apis/js-apis-inner-app-context.md#contextisupdatingconfigurations7)
[isUpdatingConfigurations():Promise<boolean>;](../reference/apis/js-apis-inner-app-context.md#contextisupdatingconfigurations7-1) | There is no corresponding API in the stage model.| OpenHarmony applications do not restart when the system environment changes. The **onConfigurationUpdated** callback is invoked to notify the applications of the changes. This API provides an empty implementation in the FA model, and the stage model does not provide a corresponding API.| +| [printDrawnCompleted(callback:AsyncCallback<void>):void;](../reference/apis/js-apis-inner-app-context.md#contextprintdrawncompleted7)
[printDrawnCompleted():Promise<void>;](../reference/apis/js-apis-inner-app-context.md#contextprintdrawncompleted7-1) | There is no corresponding API in the stage model.| This API provides an empty implementation in the FA model. The stage model does not provide a corresponding API.| diff --git a/en/application-dev/application-models/create-dataability.md b/en/application-dev/application-models/create-dataability.md new file mode 100644 index 0000000000000000000000000000000000000000..488b0593dbdc23bc1e6ea30c17f9165a92c79f20 --- /dev/null +++ b/en/application-dev/application-models/create-dataability.md @@ -0,0 +1,62 @@ +# Creating a DataAbility + + +To meet the basic requirements of the database storage service, implement the **Insert**, **Query**, **Update**, and **Delete** methods for a DataAbility. The **BatchInsert** and **ExecuteBatch** methods have already implemented the traversal logic, but not batch data processing. + + +The following sample code shows how to create a DataAbility: + +```ts +import featureAbility from '@ohos.ability.featureAbility' +import dataAbility from '@ohos.data.dataAbility' +import dataRdb from '@ohos.data.rdb' + +const TABLE_NAME = 'book' +const STORE_CONFIG = { name: 'book.db' } +const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)' +let rdbStore: dataRdb.RdbStore = undefined + +export default { + onInitialized(abilityInfo) { + console.info('DataAbility onInitialized, abilityInfo:' + abilityInfo.bundleName) + let context = featureAbility.getContext() + dataRdb.getRdbStore(context, STORE_CONFIG, 1, (err, store) => { + console.info('DataAbility getRdbStore callback') + store.executeSql(SQL_CREATE_TABLE, []) + rdbStore = store + }); + }, + insert(uri, valueBucket, callback) { + console.info('DataAbility insert start') + rdbStore.insert(TABLE_NAME, valueBucket, callback) + }, + batchInsert(uri, valueBuckets, callback) { + console.info('DataAbility batch insert start') + for (let i = 0;i < valueBuckets.length; i++) { + console.info('DataAbility batch insert i=' + i) + if (i < valueBuckets.length - 1) { + rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => { + console.info('DataAbility batch insert ret=' + num) + }) + } else { + rdbStore.insert(TABLE_NAME, valueBuckets[i], callback) + } + } + }, + query(uri, columns, predicates, callback) { + console.info('DataAbility query start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.query(rdbPredicates, columns, callback) + }, + update(uri, valueBucket, predicates, callback) { + console.info('DataAbilityupdate start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.update(valueBucket, rdbPredicates, callback) + }, + delete(uri, predicates, callback) { + console.info('DataAbilitydelete start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.delete(rdbPredicates, callback) + } +}; +``` diff --git a/en/application-dev/application-models/create-pageability.md b/en/application-dev/application-models/create-pageability.md new file mode 100644 index 0000000000000000000000000000000000000000..783646ff4cfd5fa2ab193005bfa9d182dc75b70c --- /dev/null +++ b/en/application-dev/application-models/create-pageability.md @@ -0,0 +1,97 @@ +# Creating a PageAbility + + +When you create a PageAbility on DevEco Studio, DevEco Studio automatically generates the **onCreate()** and **onDestroy()** callbacks in **app.js** and **app.ets**. You need to implement the other lifecycle callbacks in **app.js** and **app.ets**. The following code snippet shows how to create a PageAbility: + +```ts +export default { + onCreate() { + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, + onShow() { + console.info('Application onShow') + }, + onHide() { + console.info('Application onHide') + }, + onActive() { + console.info('Application onActive') + }, + onInactive() { + console.info('Application onInactive') + }, + onNewWant() { + console.info('Application onNewWant') + }, +} +``` + + +After the PageAbility is created, its abilities-related configuration items are displayed in the **config.json** file. The following is an example **config.json** file of an ability named EntryAbility: + +```json +{ + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "visible": true, + "srcPath": "EntryAbility", + "name": ".EntryAbility", + "srcLanguage": "ets", + "icon": "$media:icon", + "description": "$string:EntryAbility_desc", + "formsEnabled": false, + "label": "$string:EntryAbility_label", + "type": "page", + "launchType": "singleton" + } + ] +} +``` + + +In the FA model, you can call **getContext** of **featureAbility** to obtain the application context and then use the capabilities provided by the context. + + +**Table 1** featureAbility APIs + +| API| Description| +| -------- | -------- | +| getContext() | Obtains the application context.| + + +The following code snippet shows how to use **getContext()** to obtain the application context and distributed directory: + +```ts +import featureAbility from '@ohos.ability.featureAbility' +import fileIo from '@ohos.fileio' + +(async () => { + let dir: string + try { + console.info('Begin to getOrCreateDistributedDir') + dir = await featureAbility.getContext().getOrCreateDistributedDir() + console.info('distribute dir is ' + dir) + } catch (error) { + console.error('getOrCreateDistributedDir failed with ' + error) + } + + let fd: number; + let path = dir + "/a.txt"; + fd = fileIo.openSync(path, 0o2 | 0o100, 0o666); + fileIo.close(fd); +})() +``` diff --git a/en/application-dev/application-models/create-serviceability.md b/en/application-dev/application-models/create-serviceability.md new file mode 100644 index 0000000000000000000000000000000000000000..78623839266f4e97de26d0a3d66c19236eacf815 --- /dev/null +++ b/en/application-dev/application-models/create-serviceability.md @@ -0,0 +1,61 @@ +# Creating a ServiceAbility + + +1. Create a ServiceAbility. + + Override the ServiceAbility lifecycle callbacks to implement your own logic for processing interaction requests. + + ```ts + import rpc from "@ohos.rpc" + + class FirstServiceAbilityStub extends rpc.RemoteObject { + constructor(des: any) { + if (typeof des === 'string') { + super(des) + } else { + return + } + } + } + + export default { + onStart() { + console.info('ServiceAbility onStart') + }, + onStop() { + console.info('ServiceAbility onStop') + }, + onCommand(want, startId) { + console.info('ServiceAbility onCommand') + }, + onConnect(want) { + console.info('ServiceAbility onConnect' + want) + return new FirstServiceAbilityStub('test') + }, + onDisconnect(want) { + console.info('ServiceAbility onDisconnect' + want) + } + } + ``` + +2. Register the ServiceAbility. + + Declare the ServiceAbility in the **config.json** file by setting its **type** attribute to **service**. The **visible** attribute specifies whether the ServiceAbility can be called by other applications. The value **true** means that the ServiceAbility can be called by other applications, and **false** means that the ServiceAbility can be called only within the application. To enable the ServiceAbility to be called by other applications, set **visible** to **true** when registering the ServiceAbility and enable associated startup. For details about the startup rules, see [Component Startup Rules](component-startup-rules.md). + + ```json + { + "module": { + "abilities": [ + { + "name": ".ServiceAbility", + "srcLanguage": "ets", + "srcPath": "ServiceAbility", + "icon": "$media:icon", + "description": "hap sample empty service", + "type": "service", + "visible": true + } + ] + } + } + ``` diff --git a/en/application-dev/application-models/data-share-via-want.md b/en/application-dev/application-models/data-share-via-want.md new file mode 100644 index 0000000000000000000000000000000000000000..4ecdf35ead5482d4b4b2e0d0a2a4544e75686612 --- /dev/null +++ b/en/application-dev/application-models/data-share-via-want.md @@ -0,0 +1,111 @@ +# Using Want to Share Data Between Applications + + +Users often need to share data (such as a text or an image) from one application to another. The following uses PDF file sharing as an example to describe how to use Want to share data between applications. + + +## Prerequisites + +1. There are two UIAbility components (one for the sharing party and the other for the shared party) and one system component (used as the application selector). When the sharing party initiates data sharing through **startAbility()**, the application selector is started. The system implicitly matches and displays all applications that support the type of data to share. After the user selects an application, the system starts that application to complete data sharing. + +2. In this section, data sharing is triggered by touching a button. You can use other ways to trigger data sharing during application development. This section focuses on the Want configuration used for data sharing. + +3. The following actions are involved in this section: + - **ACTION_SELECT (ohos.want.action.select)**: action of displaying the application selector. + - **ACTION_SEND_DATA (ohos.want.action.sendData)**: action of launching the UI for sending a single data record. It is used to transfer data to the shared party. + + +## How to Develop + +- Sharing party + 1. In the stage mode, the [File Descriptor (FD)](../reference/apis/js-apis-fileio.md#fileioopensync) is used for file transfer. This example assumes that the path of the file to share is obtained. + + ```ts + import fileIO from '@ohos.fileio'; + + // let path = ... + // Open the file whose path is a variable. + let fileFd = fileIO.openSync(path, 0o102, 0o666); + ``` + + 2. As described in the prerequisites, the sharing party starts an application selector and shares the data to the selector, and the selector transfers the data to the shared party. Want of the sharing party must be nested at two layers. At the first layer, implicit Want is used together with the **ohos.want.action.select** action to display the application selector. At the second layer, complete Want is declared in the custom field **parameters** to transfer the data to share. + + ```ts + import wantConstant from '@ohos.app.ability.wantConstant'; + + // let path = ... + // let fileFd = ... + // let fileSize = ... + let want = { + / This action is used to implicitly match the application selector. + action: wantConstant.Action.ACTION_SELECT, + // This is the custom parameter in the first layer of Want, + / which is intended to add information to the application selector. + parameters: { + // MIME type of PDF. + "ability.picker.type": "application/pdf", + "ability.picker.fileNames": [path], + "ability.picker.fileSizes": [fileSize], + // This nested Want ,which will be directly sent to the selected application. + "ability.want.params.INTENT": { + "action": "ohos.want.action.sendData", + "type": "application/pdf", + "parameters": { + "keyFd": {"type": "FD", "value": fileFd} + } + } + } + } + ``` + + In the preceding code, the custom field **parameters** is used. The **ability.picker.\*** fields in the first-layer **parameters** are used to pass the information to be displayed on the application selector. The following fields are involved: + + - **"ability.picker.type"**: The application selector renders the file type icon based on this field. + - **"ability.picker.fileNames"**: The application selector displays the file name based on this field. + - **"ability.picker.fileSizes"**: The application selector displays the file size based on this field. The unit is byte. + - **"ability.picker.fileNames"** and **"ability.picker.fileSizes"** are arrays and have a one-to-one mapping. + + For example, when **"ability.picker.type"** is **"application/pdf"**, **"ability.picker.fileNames"** is **"["APIs.pdf"]"**, and **"ability.picker.fileSizes"** is **"[350 \* 1024]"**, the application selector is displayed as follows: + + stage-want2 + + In the preceding code, the **ability.want.params.INTENT** field is nested Want. In this field, **action** and **type** are used for implicit matching by the application selector. For details about implicit matching, see [Matching Rules of Implicit Want](explicit-implicit-want-mappings.md#matching-rules-of-implicit-want). After the user selects an application, the nested Want of the **ability.want.params.INTENT** field is passed to that application. + +- Shared party + 1. As mentioned above, the application selector performs implicit matching based on the **ability.want.params.INTENT** field. Therefore, you must set **skills** in the ability configuration file (**module.json5** file in the stage model) of the shared party as follows: + + ```ts + "skills": [ + { + "entities": [ + // ... + ], + "actions": [ + "ohos.want.action.sendData" + // ... + ], + "uris": [ + { + "type": "application/pdf" + }, + // ... + ] + }, + ] + ``` + + The **actions** and **type** fields in **uris** match the **action** and **type** fields in **ability.want.params.INTENT**, respectively. + + Files can be transferred in FD mode, but not URI mode. In implicit matching, the **type** field in Want must match the **type** field in **uris** under **skills** of the shared party. Therefore, specify only the **type** field in **uris**. If **host** and **port** are specified, the matching fails. The application selector initiates implicit matching based on **ability.want.params.INTENT**. Therefore, when the **uri** field added to **ability.want.params.INTENT** matches the **uris** field under **skills**, the matching is successful and additional data can be transferred. + 2. After the application selector starts the shared party, the system calls **onCreate** and passes **ability.want.params.INTENT** to the **want** parameter. + + ```ts + onCreate(want, launchParam) { + // When keyFd is undefined, the application crashes. + if (want["parameters"]["keyFd"] !== undefined) { + // Receive the file descriptor. + let fd = want["parameters"]["keyFd"].value; + // ... + } + } + ``` diff --git a/en/application-dev/application-models/dataability-configuration.md b/en/application-dev/application-models/dataability-configuration.md new file mode 100644 index 0000000000000000000000000000000000000000..c8c69c8626cf9872e40931b2f97c431e105cb38f --- /dev/null +++ b/en/application-dev/application-models/dataability-configuration.md @@ -0,0 +1,61 @@ +# DataAbility Component Configuration + + +## URI Introduction + +A Uniform Resource Identifier (URI) is used to identify a specific data item, such as a table in the database or a file on the disk. URIs used in OpenHarmony comply with the commonly used URI standard. A URI consists of the components: + +![fa-dataability-uri](figures/fa-dataability-uri.png) + +- **scheme**: name of the scheme used by the DataAbility. The value is fixed at **dataability**. + +- **authority**: device ID. To access data on a remote device, set this component to the ID of the remote device. To access data on the local device, leave this component empty. + +- **path**: location of the specific resource to access. + +- **query**: query parameters. + +- **fragment**: subordinate resources to access. + +Example URIs: + +- Cross-device communication: dataability://*device*id_/*com.domainname.dataability.persondata*/*person*/*10* + +- Local-device communication: dataability:///*com.domainname.dataability.persondata*/*person*/*1* + +> **NOTE** +> +> In the case of local-device communication, **device_id** is empty, and therefore, there are three slashes (/) after **dataability:**. + + +## Introduction to Certain Configuration Items + +Similar to a PageAbility, a DataAbility is configured in **abilities** under **module** of the **config.json** file. The difference between a DataAbility and PageAbility lies in the **type** and **uri** fields. + +**Table 1** DataAbility configuration items + +| Name| Description| +| -------- | -------- | +| "name" | Ability name.| +| "type" | Type of the ability. The value **data** indicates a DataAbility.| +| "uri" | URI used for communication.| +| "visible" | Whether the ability is visible to other applications. Data sharing is allowed only when the value is **true**.| + +The following is an example **config.json** file: + + +```json +"abilities": [{ + "srcPath": "DataAbility", + "name": ".DataAbility", + "icon": "$media:icon", + "srcLanguage": "ets", + "description": "$string:description_dataability", + "type": "data", + "visible": true, + "uri": "dataability://ohos.samples.etsdataability.DataAbility" +}] +``` + +For details about the configuration items, see [Internal Structure of module](../quick-start/module-structure.md). + diff --git a/en/application-dev/application-models/dataability-lifecycle.md b/en/application-dev/application-models/dataability-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..f35f46ffd9504a29897694054efc15f9a8465a57 --- /dev/null +++ b/en/application-dev/application-models/dataability-lifecycle.md @@ -0,0 +1,23 @@ +# DataAbility Lifecycle + + +You can override lifecycle callbacks (described in the table below) for a DataAbility based on service requirements. + + +**Table 1** DataAbility lifecycle APIs + +| API| Description| +| -------- | -------- | +| onInitialized?(info: AbilityInfo): void | Called during ability initialization to initialize the relational database (RDB).| +| update?(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void | Updates data in the database.| +| query?(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void | Queries data in the database.| +| delete?(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void | Deletes one or more data records from the database.| +| normalizeUri?(uri: string, callback: AsyncCallback<string>): void | Normalizes the URI. A normalized URI applies to cross-device use, persistence, backup, and restore. When the context changes, it ensures that the same data item can be referenced.| +| batchInsert?(uri: string, valueBuckets: Array<rdb.ValuesBucket>, callback: AsyncCallback<number>): void | Inserts multiple data records into the database.| +| denormalizeUri?(uri: string, callback: AsyncCallback<string>): void | Converts a normalized URI generated by **normalizeUri** into a denormalized URI.| +| insert?(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void | Inserts a data record into the database.| +| openFile?(uri: string, mode: string, callback: AsyncCallback<number>): void | Opens a file.| +| getFileTypes?(uri: string, mimeTypeFilter: string, callback: AsyncCallback<Array<string>>): void | Obtains the MIME type of a file.| +| getType?(uri: string, callback: AsyncCallback<string>): void | Obtains the MIME type matching the data specified by the URI.| +| executeBatch?(ops: Array<DataAbilityOperation>, callback: AsyncCallback<Array<DataAbilityResult>>): void | Operates data in the database in batches.| +| call?(method: string, arg: string, extras: PacMap, callback: AsyncCallback<PacMap>): void | Calls a custom API.| diff --git a/en/application-dev/application-models/dataability-overview.md b/en/application-dev/application-models/dataability-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..b89ee68bb5fe6cda341dea332a24cf1010c4935f --- /dev/null +++ b/en/application-dev/application-models/dataability-overview.md @@ -0,0 +1,10 @@ +# DataAbility Component Overview + + +A DataAbility is an ability that uses the Data template. It provides unified data access for external systems, but not a UI for user interaction. A DataAbility can be started by a PageAbility, a ServiceAbility, or other applications. It remains to run in the background even after the user switches to another application. + + +A DataAbility helps applications manage access to data stored by themselves and other applications, and provides methods for sharing data with other applications, either on the same device or across devices. + + +Data can be stored in a database or files on disks. The DataAbility provide methods for inserting, deleting, updating, and querying data, and opening files. You should implement these methods. diff --git a/en/application-dev/application-models/dataability-permission-control.md b/en/application-dev/application-models/dataability-permission-control.md new file mode 100644 index 0000000000000000000000000000000000000000..25c5e82726dbc3a7dba8158a0847b5c59ea0c98e --- /dev/null +++ b/en/application-dev/application-models/dataability-permission-control.md @@ -0,0 +1,60 @@ +# DataAbility Permission Control + + +The DataAbility uses permission control to determine whether an ability can access the data service it provides. There are static and dynamic permission controls. + + +## Static Permission Control + +The DataAbility functions as the server. When being started, the DataAbility verifies the client permissions against the settings of the optional fields **readPermission**, **writePermission**, and **Permission** fields in the **config.json** file. The following is an example: + + +```json +"abilities": [{ + "srcPath": "DataAbility", + "name": ".DataAbility", + "icon": "$media:icon", + "srcLanguage": "ets", + "description": "$string:description_dataability", + "type": "data", + "visible": true, + "uri": "dataability://ohos.samples.etsdataability.DataAbility", + "readPermission":"ohos.permission.READ_CONTACTS", + "writePermission":"ohos.permission.WRITE_CONTACTS" +}] +``` + +The client permission is configured in **reqPermissions** under **module** in the **config.json** file. The following is an example: + + +```json +{ + "module": { + "reqPermissions":{ + { + "name":"ohos.permission.READ_CONTACTS" + }, + { + "name":"ohos.permission.WRITE_CONTACTS" + } + } + } +} +``` + + +## Dynamic Permission Control + +Static permission control determines whether a DataAbility can be started by another ability or application. It does not verify the permission of each read/write interface. + +Dynamic permission control verifies whether the client has the corresponding permission for every read/write interface. The table below lists the permissions required for calling these interfaces. + +**Table 1** Permission configuration for data read/write interfaces + +| Interface with the Read Permission| Interface with the Write Permission| Interface with the Read/Write Permission Based on Actual Requirements| +| -------- | -------- | -------- | +| query, normalizeUri, denormalizeUri, openfile (with **mode** set to **'r'**)| insert, batchInsert, delete, update, openfile (with **mode** set to **'w'**)| executeBatch | + +For interfaces that require the read permission, the server must have **readPermission** specified, and the client must obtain the read permission before calling them. + +For interfaces that require the write permission, the server must have **writePermission** specified, and the client must obtain the write permission before calling them. diff --git a/en/application-dev/application-models/dataability-switch.md b/en/application-dev/application-models/dataability-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..b91d50ca37a97fdc1d4824a93a6093bac7cd0f77 --- /dev/null +++ b/en/application-dev/application-models/dataability-switch.md @@ -0,0 +1,44 @@ +# DataAbility Switching + + +The DataAbility component in the FA model corresponds to the DataShareExtensionAbility component in the stage model. + + +The DataShareExtensionAbility class provides system APIs. Only system applications can create DataShareExtensionAbility instances. Therefore, DataAbility switching adopts different policies for system applications and third-party applications. + + +## Switching a DataAbility of a System Application + +The procedure for switching a DataAbility of a system application is similar to the procedure of PageAbility switching. + +1. Create a DataShareExtensionAbility in the stage model. + +2. Migrate the DataAbility code to the DataShareExtensionAbility. + + The table below describes the lifecycle comparison of the DataAbility and DataShareExtensionAbility. + + | DataAbility| DataShareExtensionAbility| Comparison Description| + | -------- | -------- | -------- | + | onInitialized?(info: AbilityInfo): void | onCreate?(want: Want, callback: AsyncCallback<void>): void
| The two methods have the same invoking time but different input parameters. In the stage model, the **want** parameter is added so that you can obtain parameters during creation.| + | update?(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void | update?(uri: string, predicates: dataSharePredicates.DataSharePredicates, value: ValuesBucket, callback: AsyncCallback<number>): void | The two methods have the same meaning and invoking time, but slightly different parameter sequence and parameter type. A simple reconstruction is required.| + | query?(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void | query?(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: AsyncCallback<Object>): void;| The two methods have the same meaning and invoking time, but slightly different parameter sequence and parameter type. A simple reconstruction is required.| + | delete?(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void | delete?(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>):| The two methods have the same meaning and invoking time, but slightly different parameter type. A simple reconstruction is required.| + | normalizeUri?(uri: string, callback: AsyncCallback<string>): void | normalizeUri?(uri: string, callback: AsyncCallback<string>): void| The two methods have the same meaning, invoking time, and parameters.| + | batchInsert?(uri: string, valueBuckets: Array<rdb.ValuesBucket>, callback: AsyncCallback<number>): void | batchInsert?(uri: string, values: Array<ValuesBucket>, callback: AsyncCallback<number>): void| The two methods have the same meaning and invoking time, but slightly different parameter type. A simple reconstruction is required.| + | denormalizeUri?(uri: string, callback: AsyncCallback<string>): void | denormalizeUri?(uri: string, callback: AsyncCallback<string>): void | The two methods have the same meaning, invoking time, and parameters.| + | insert?(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void | insert?(uri: string, value: ValuesBucket, callback: AsyncCallback<number>): void | The two methods have the same meaning and invoking time, but slightly different parameter type. A simple reconstruction is required.| + | openFile?(uri: string, mode: string, callback: AsyncCallback<number>): void | NA | The stage model does not support cross-process URI access. You are advised to use [the **want** parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| + | getFileTypes?(uri: string, mimeTypeFilter: string, callback: AsyncCallback<Array<string>>): void | NA | The stage model does not support cross-process URI access. You are advised to use [the **want** parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| + | getType?(uri: string, callback: AsyncCallback<string>): void | NA | The stage model does not support cross-process URI access. You are advised to use [the **want** parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| + | executeBatch?(ops: Array<DataAbilityOperation>, callback: AsyncCallback<Array<DataAbilityResult>>): void | NA | This method is not provided in the stage model. You need to implement the functionality based on service functions.| + | call?(method: string, arg: string, extras: PacMap, callback: AsyncCallback<PacMap>): void | NA | This method is not provided in the stage model. You need to implement the functionality based on service functions.| + + +## Switching a DataAbility of a Third-Party Application + +In the stage model, third-party applications cannot provide data services for other third-party applications. You can select a switching solution based on your service requirements. + +| Service Type| Switching Solution| +| -------- | -------- | +| Providing data for third-party applications| Match a scenario-specific [ExtensionAbility](../reference/apis/js-apis-bundleManager.md#extensionabilitytype).| +| Providing data within the application| Extract the component code as a common module for other components to use.| diff --git a/en/application-dev/application-models/dataabilityhelper-switch.md b/en/application-dev/application-models/dataabilityhelper-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..c709e30ae9c25bcbd47f781e1f43a51100960998 --- /dev/null +++ b/en/application-dev/application-models/dataabilityhelper-switch.md @@ -0,0 +1,20 @@ +# DataAbilityHelper Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [openFile(uri: string, mode: string, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperopenfile)
[openFile(uri: string, mode: string): Promise<number>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperopenfile-1) | \@ohos.data.fileAccess.d.ts | [openFile(uri: string, flags: OPENFLAGS) : Promise<number>;](../reference/apis/js-apis-fileAccess.md#fileaccesshelperopenfile)
[openFile(uri: string, flags: OPENFLAGS, callback: AsyncCallback<number>) : void;](../reference/apis/js-apis-fileAccess.md#fileaccesshelperopenfile) | +| [on(type: 'dataChange', uri: string, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperon) | \@ohos.data.dataShare.d.ts | [on(type: 'dataChange', uri: string, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-data-dataShare.md#ondatachange) | +| [off(type: 'dataChange', uri: string, callback?: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperoff) | \@ohos.data.dataShare.d.ts | [off(type: 'dataChange', uri: string, callback?: AsyncCallback<void>): void;](../reference/apis/js-apis-data-dataShare.md#offdatachange) | +| [getType(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpergettype)
[getType(uri: string): Promise<string>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpergettype-1) | There is no corresponding API in the stage model.| The stage model does not support cross-process URI access. You are advised to use [the want parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| +| [getFileTypes(uri: string, mimeTypeFilter: string, callback: AsyncCallback<Array<string>>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpergetfiletypes)
[getFileTypes(uri: string, mimeTypeFilter: string): Promise<Array<string>>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpergetfiletypes-1) | There is no corresponding API in the stage model.| The stage model does not support cross-process URI access. You are advised to use [the want parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| +| [normalizeUri(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpernormalizeuri)
[normalizeUri(uri: string): Promise<string>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpernormalizeuri-1) | \@ohos.data.dataShare.d.ts | [normalizeUri(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-data-dataShare.md#normalizeuri)
[normalizeUri(uri: string): Promise<string>;](../reference/apis/js-apis-data-dataShare.md#normalizeuri-1) | +| [denormalizeUri(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperdenormalizeuri)
[denormalizeUri(uri: string): Promise<string>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperdenormalizeuri-1) | \@ohos.data.dataShare.d.ts | [denormalizeUri(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-data-dataShare.md#denormalizeuri)
[denormalizeUri(uri: string): Promise<string>;](../reference/apis/js-apis-data-dataShare.md#denormalizeuri-1) | +| [notifyChange(uri: string, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpernotifychange)
[notifyChange(uri: string): Promise<void>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpernotifychange-1) | \@ohos.data.dataShare.d.ts | [notifyChange(uri: string, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-data-dataShare.md#notifychange)
[notifyChange(uri: string): Promise<void>;](../reference/apis/js-apis-data-dataShare.md#notifychange-1) | +| [insert(uri: string, valuesBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperinsert)
[insert(uri: string, valuesBucket: rdb.ValuesBucket): Promise<number>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperinsert-1) | \@ohos.data.dataShare.d.ts | [insert(uri: string, value: ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-data-dataShare.md#insert)
[insert(uri: string, value: ValuesBucket): Promise<number>;](../reference/apis/js-apis-data-dataShare.md#insert-1) | +| [batchInsert(uri: string, valuesBuckets: Array<rdb.ValuesBucket>, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperbatchinsert)
[batchInsert(uri: string, valuesBuckets: Array<rdb.ValuesBucket>): Promise<number>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperbatchinsert-1) | \@ohos.data.dataShare.d.ts | [batchInsert(uri: string, values: Array<ValuesBucket>, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-data-dataShare.md#batchinsert)
[batchInsert(uri: string, values: Array<ValuesBucket>): Promise<number>;](../reference/apis/js-apis-data-dataShare.md#batchinsert-1) | +| [delete(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperdelete)
[delete(uri: string, predicates?: dataAbility.DataAbilityPredicates): Promise<number>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperdelete-1)
[delete(uri: string, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperdelete) | \@ohos.data.dataShare.d.ts | [delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-data-dataShare.md#delete)
[delete(uri: string, predicates: dataSharePredicates.DataSharePredicates): Promise<number>;](../reference/apis/js-apis-data-dataShare.md#delete-1) | +| [update(uri: string, valuesBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperupdate)
[update(uri: string, valuesBucket: rdb.ValuesBucket, predicates?: dataAbility.DataAbilityPredicates): Promise<number>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperupdate-1)
[update(uri: string, valuesBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperupdate) | \@ohos.data.dataShare.d.ts | [update(uri: string, predicates: dataSharePredicates.DataSharePredicates, value: ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-data-dataShare.md#update)
[update(uri: string, predicates: dataSharePredicates.DataSharePredicates, value: ValuesBucket): Promise<number>;](../reference/apis/js-apis-data-dataShare.md#update-1) | +| [query(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperquery)
[query(uri: string, callback: AsyncCallback<ResultSet>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperquery)
[query(uri: string, columns: Array<string>, callback: AsyncCallback<ResultSet>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperquery)
[query(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperquery)
[query(uri: string, columns?: Array<string>, predicates?: dataAbility.DataAbilityPredicates): Promise<ResultSet>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperquery-1) | \@ohos.data.dataShare.d.ts | [query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: AsyncCallback<DataShareResultSet>): void;](../reference/apis/js-apis-data-dataShare.md#query)
[query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>): Promise<DataShareResultSet>;](../reference/apis/js-apis-data-dataShare.md#query-1) | +| [call(uri: string, method: string, arg: string, extras: PacMap, callback: AsyncCallback<PacMap>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpercall-1)
[call(uri: string, method: string, arg: string, extras: PacMap): Promise<PacMap>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelpercall) | There is no corresponding API in the stage model.| No corresponding API is provided.| +| [executeBatch(uri: string, operations: Array<DataAbilityOperation>, callback: AsyncCallback<Array<DataAbilityResult>>): void;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperexecutebatch)
[executeBatch(uri: string, operations: Array<DataAbilityOperation>): Promise<Array<DataAbilityResult>>;](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md#dataabilityhelperexecutebatch-1) | There is no corresponding API in the stage model.| No corresponding API is provided.| diff --git a/en/application-dev/application-models/datashareextensionability.md b/en/application-dev/application-models/datashareextensionability.md new file mode 100644 index 0000000000000000000000000000000000000000..5b07ba68180fbcc2a51047d37ca9a82addd89cd8 --- /dev/null +++ b/en/application-dev/application-models/datashareextensionability.md @@ -0,0 +1,4 @@ +# DataShareExtensionAbility + + +DataShareExtensionAbility is available only for system application. It 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). diff --git a/en/application-dev/application-models/explicit-implicit-want-mappings.md b/en/application-dev/application-models/explicit-implicit-want-mappings.md new file mode 100644 index 0000000000000000000000000000000000000000..ccf33e07d1b389eb1246a89a377febb1e7d24a78 --- /dev/null +++ b/en/application-dev/application-models/explicit-implicit-want-mappings.md @@ -0,0 +1,160 @@ +# Matching Rules of Explicit Want and Implicit Want + +Both explicit Want and implicit Want can be used to match an ability to start based on certain rules. These rules determine how the parameters set in Want match the configuration file declared by the target ability. + +## Matching Rules of Explicit Want + + +The table below describes the matching rules of explicit Want. + +| Name| Type| Matching Item| Mandatory| Rule Description| +| -------- | -------- | -------- | -------- | -------- | +| deviceId | string | Yes| No| If this field is unspecified, only abilities on the local device are matched.| +| bundleName | string | Yes| Yes| If **abilityName** is specified but **bundleName** is unspecified, the matching fails.| +| moduleName | string | Yes| No| If this field is unspecified and multiple modules with the same ability name exist in the application, the first ability is matched by default.| +| abilityName | string | Yes| Yes| To use explicit Want, this field must be specified.| +| uri | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.| +| type | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.| +| action | string | No| No| This field is not used for matching. It is passed to the target ability as a parameter.| +| entities | Array<string> | No| No| This field is not used for matching. It is passed to the target ability as a parameter.| +| flags | number | No| No| This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.| +| parameters | {[key: string]: any} | No| No| This field is not used for matching. It is passed to the target ability as a parameter.| + +## Matching Rules for Implicit Want + +The table below describes the matching rules of implicit Want. + +| Name | Type | Matching Item| Mandatory| Rule Description | +| ----------- | ------------------------------ | ------ | ---- | ------------------------------------------------------------ | +| deviceId | string | Yes | No | Implicit invoking is not supported across devices. | +| abilityName | string | No | No | To use implicit Want, this field must be left unspecified. | +| bundleName | string | Yes | No | - When only **bundleName** is specified, matching is limited to that application.
- When both **bundleName** and **moduleName** are specified, matching is limited to that module in that application.
- When only **moduleName** is specified, the setting is invalid.

These fields will be used for implicit matching.| +| moduleName | string | Yes | No | | +| uri | string | Yes | No | | +| type | string | Yes | No | | +| action | string | Yes | No | | +| entities | Array<string> | Yes | No | | +| flags | number | No | No | This field is not used for matching and is directly transferred to the system for processing. It is generally used to set runtime information, such as URI data authorization.| +| parameters | {[key: string]: any} | No | No | This field is not used for matching. It is passed to the target ability as a parameter. | + +Get familiar with the following about implicit Want: + + +- The **want** parameter passed by the caller indicates the operation to be performed by the caller. It also provides data and application type restrictions. + +- The **skills** field declares the capabilities of the target ability. For details, see [the skills tag](../quick-start/module-configuration-file.md#skills) in the [module.json5 file](../quick-start/module-configuration-file.md). + + +The system matches the **want** parameter (including the **action**, **entities**, **uri**, and **type** attributes) passed by the caller against the **skills** configuration (including the **actions**, **entities**, **uris**, and **type** attributes) of the abilities one by one. When all the four attributes are matched, a dialog box is displayed for users to select a matched application. + + +### Matching Rules of action in the want Parameter + +The system matches the [action](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction) attribute in the **want** parameter passed by the caller against **actions** under **skills** of the abilities. + +- If **action** in the passed **want** parameter is specified but **actions** under **skills** of an ability is unspecified, the matching fails. + +- If **action** in the passed **want** parameter is unspecified but **actions** under **skills** of an ability is specified, the matching is successful. + +- If **action** in the passed **want** parameter is specified, and **actions** under **skills** of an ability is specified and contains **action** in the passed **want** parameter, the matching is successful. + +- If **action** in the passed **want** parameter is specified, and **actions** under **skills** of an ability is specified but does not contain **action** in the passed **want** parameter, the matching fails. + + **Figure 1** Matching rules of action in the want parameter + want-action + + +### Matching Rules of entities in the want Parameter + +The system matches the [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) attribute in the **want** parameter passed by the caller against **entities** under **skills** of the abilities. + +- If **entities** in the passed **want** parameter is unspecified but **entities** under **skills** of an ability is specified, the matching is successful. + +- If **entities** in the passed **want** parameter is unspecified but **entities** under **skills** of an ability is unspecified, the matching is successful. + +- If **entities** in the passed **want** parameter is specified but **entities** under **skills** of an ability is unspecified, the matching fails. + +- If **entities** in the passed **want** parameter is specified, and **entities** under **skills** of an ability is specified and contains **entities** in the passed **want** parameter, the matching is successful. + +- If **entities** in the passed **want** parameter is specified, and **entities** under **skills** of an ability is specified but does not contain **entities** in the passed **want** parameter, the matching fails. + + Figure 2 Matching rule of entities in the want parameter +want-entities + + +### Matching Rules of uri and type in the want Parameter + +When the **uri** and **type** parameters are specified in the **want** parameter to initiate a component startup request, the system traverses the list of installed components and matches the **uris** array under **skills** of the abilities one by one. If one of the **uris** arrays under **skills** matches the **uri** and **type** in the passed **want**, the matching is successful. + +Figure 3 Matching rules when uri and type are specified in the want parameter +want-uri-type1 + +There are four combinations of **uri** and **type** settings. The matching rules are as follows: + +- Neither **uri** or **type** is specified in the **want** parameter. + - If the **uris** array under **skills** of an ability is unspecified, the matching is successful. + - If the **uris** array under **skills** of an ability contains an URI element whose **scheme** and **type** are unspecified, the matching is successful. + - In other cases, the matching fails. + +- Only **uri** is specified in the **want** parameter. + - If the **uris** array under **skills** of an ability is unspecified, the matching fails. + - If the **uris** array under **skills** of an ability contains an element whose [uri is matched](#matching-rules-of-uri) and **type** is unspecified, the matching is successful. Otherwise, the matching fails. + +- Only **type** is specified in the **want** parameter. + - If the **uris** array under **skills** of an ability is unspecified, the matching fails. + - If the **uris** array under **skills** of an ability contains an URI element whose **scheme** is unspecified and [type is matched](#matching-rules-of-type), the matching is successful. Otherwise, the matching fails. + +- Both **uri** and **type** are specified in the **want** parameter, as shown in Figure 3. + - If the **uris** array under **skills** of an ability is unspecified, the matching fails. + - If the **uris** array under **skills** of an ability contains an element whose [uri is matched](#matching-rules-of-uri) and [type is matched](#matching-rules-of-type), the matching is successful. Otherwise, the matching fails. + + +To simplify the description, **uri** and **type** passed in the **want** parameter are called **w_uri** and **w_type**, respectively; the **uris** array under **skills** of an ability to match is called **s_uris**; each element in the array is called **s_uri**. Matching is performed from top to bottom. + + +Figure 4 Matching rules of uri and type in the want parameter +want-uri-type2 + + +### Matching Rules of uri + +To simplify the description, **uri** in the passed **want** parameter is called **w_uri**; **uri** under **skills** of an ability to match is called **s_uri**. The matching rules are as follows: + +- If **scheme** of **s_uri** is unspecified and **w_uri** is unspecified, the matching is successful. Otherwise, the matching fails. + +- If **host** of **s_uri** is unspecified and **scheme** of **w_uri** and **scheme** of **s_uri** are the same, the matching is successful. Otherwise, the matching fails. + +- If **path**, **pathStartWith**, and **pathRegex** of **s_uri** are unspecified and **w_uri** and **s_uri** are the same, the matching is successful. Otherwise, the matching fails. + +- If **path** of **s_uri** is specified and the **full path expressions** of **w_uri** and **s_uri** are the same, the matching is successful. Otherwise, the matching of **pathStartWith** continues. + +- If **pathStartWith** of **s_uri** is specified and **w_uri** contains the prefix expression of **s_uri**, the matching is successful. Otherwise, **pathRegex** matching continues. + +- If **pathRegex** of **s_uri** is specified and **w_uri** meets the regular expression of **s_uri**, the matching is successful. Otherwise, the matching fails. + +> **NOTE** +> +> The **scheme**, **host**, **port**, **path**, **pathStartWith**, and **pathRegex** attributes of **uris** under **skills** of an ability are concatenated. If **path**, **pathStartWith**, and **pathRegex** are declared in sequence, **uris** can be concatenated into the following expressions: +> +> - **Full path expression**: `scheme://host:port/path` +> +> - **Prefix expression**: `scheme://host:port/pathStartWith` +> +> - **Regular expression**: `scheme://host:port/pathRegex` + + +### Matching Rules of type + +> **NOTE** +> +> The matching rules of **type** described in this section are based on the fact that **type** in the **want** parameter is specified. If **type** is unspecified, follow the [matching rules of uri and type in the want parameter](#matching-rules-of-uri-and-type-in-the-want-parameter). + +To simplify the description, **uri** in the passed **want** parameter is called **w_type**, and **type** of **uris** under **skills** of an ability to match is called **s_type**. The matching rules are as follows: + +- If **s_type** is unspecified, the matching fails. + +- If **s_type** or **w_type** contains the wildcard `*/*`, the matching is successful. + +- If the last character of **s_type** is the wildcard `*`, for example, `prefixType/*`, the matching is successful only when **w_type** contains `prefixType/`. + +- If the last character of **w_type** is the wildcard `*`, for example, `prefixType/*`, the matching is successful only when **s_type** contains `prefixType/`. diff --git a/en/application-dev/application-models/extensionability-overview.md b/en/application-dev/application-models/extensionability-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..d85f02ace879e409a8d42d6f09408680a99f8056 --- /dev/null +++ b/en/application-dev/application-models/extensionability-overview.md @@ -0,0 +1,58 @@ +# ExtensionAbility Component Overview + + +The ExtensionAbility component is used for specific scenarios such as widgets and input methods. + + +An [ExtensionAbilityType](../reference/apis/js-apis-bundleManager.md#extensionabilitytype) is provided for every specific scenario. All types of ExtensionAbility components are managed by the corresponding system services in a unified manner. For example, the InputMethodExtensionAbility component is managed by the input method management service. The following ExtensionAbility types are supported: + + +- [FormExtensionAbility](../reference/apis/js-apis-app-form-formExtensionAbility.md): ExtensionAbility component of the form type, which provides APIs related to widgets. + +- [WorkSchedulerExtensionAbility](../reference/apis/js-apis-resourceschedule-workScheduler.md): ExtensionAbility component of the work_scheduler type, which provides APIs for registering, canceling, and querying Work Scheduler tasks. + +- [InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod.md): ExtensionAbility component of the input_method type, which provides an input method framework that can be used to hide the keyboard, obtain the list of installed input methods, display the dialog box for input method selection, and more. + +- [ServiceExtensionAbility](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md): ExtensionAbility component of the service type, which provides APIs related to background service scenarios. + +- [AccessibilityExtensionAbility](../reference/apis/js-apis-application-accessibilityExtensionAbility.md): ExtensionAbility component of the accessibility type, which provides APIs related to the accessibility feature. + +- [DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md): ExtensionAbility component of the data_share type, which provides APIs for data sharing. + +- [StaticSubscriberExtensionAbility](../reference/apis/js-apis-application-staticSubscriberExtensionAbility.md): ExtensionAbility component of the static_subscriber type, which provides APIs for static broadcast. + +- [WindowExtensionAbility](../reference/apis/js-apis-application-windowExtensionAbility.md): ExtensionAbility component of the window type, which allows system applications to display UIs of other applications. + +- [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. + + +## Using ExtensionAbility of the Specified Type + +All types of ExtensionAbility components are started by the corresponding system management service, rather than applications, so that their lifecycles are under control by the system. The caller of the ExtensionAbility component does not need to care about its lifecycle. + +The following uses [InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod.md) as an example. As shown in the figure below, when an application calls the InputMethodExtensionAbility component, the input method management service is called first. The input method management service starts the InputMethodExtensionAbility component, returns the component to the application, and starts to manage its lifecycle. + +**Figure 1** Using the InputMethodExtensionAbility component +![ExtensionAbility-start](figures/ExtensionAbility-start.png) + + +## 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). + +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. + +![form_extension](figures/form_extension.png) + + +> **NOTE** +> +> For an application, all ExtensionAbility components of the same type run in an independent process, whereas UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility run in another independent process. For details, see [Process Model (Stage Model)](process-model-stage.md). +> +> For example, an application has one UIAbility component, one ServiceExtensionAbility, one DataShareExtensionAbility, two FormExtensionAbility, and one ImeExtensionAbility. When the application is running, there are three processes: +> +> - UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility run in an independent process. +> +> - The two FormExtensionAbility components run in an independent process. +> +> - The two ImeExtensionAbility components run in an independent process. diff --git a/en/application-dev/application-models/fa-model-development-overview.md b/en/application-dev/application-models/fa-model-development-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..07e7ef8a0bdaea927762c15e4123ae728c026cb7 --- /dev/null +++ b/en/application-dev/application-models/fa-model-development-overview.md @@ -0,0 +1,15 @@ +# FA Model Development Overview + + +During application development based on the Feature Ability (FA) model, the following tasks are involved in the application model. + + + **Table 1** FA model development process + +| Task| Introduction| Guide| +| -------- | -------- | -------- | +| Application component development| Use the PageAbility, ServiceAbility, DataAbility, and widgets of the FA model to develop applications.| - [Application- or Component-Level Configuration](application-component-configuration-fa.md)
- [PageAbility Component](pageability-overview.md)
- [ServiceAbility Component](serviceability-overview.md)
- [DataAbility Component](dataability-overview.md)
- [Widget Development](Widget-development-fa.md)
- [Context](application-context-fa.md)
- [Want](want-fa.md) | +| Inter-process communication (IPC)| Learn the process model and common IPC modes of the FA model.| [Common Events](common-event-fa.md)
[Background Services](rpc.md) | +| Inter-thread communication| Learn the thread model and common inter-thread communication modes of the FA model.| [Inter-Thread Communication](itc-fa-overview.md)| +| Mission management| Learn the basic concepts and typical scenarios of mission management in the FA model.| [Mission Management](mission-management-fa.md)| +| Application configuration file| Learn the requirements for developing application configuration files in the FA model.| [Application Configuration File](config-file-fa.md) | diff --git a/en/application-dev/application-models/fa-stage-interaction-overview.md b/en/application-dev/application-models/fa-stage-interaction-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..0d1ed27f0df2d4964b0d69faf48afcb42e32bf91 --- /dev/null +++ b/en/application-dev/application-models/fa-stage-interaction-overview.md @@ -0,0 +1,25 @@ +# Component Interaction Between the FA Model and Stage Model + + +The FA model is supported by API version 8 and earlier versions, and the stage model is recommended since API version 9. The FA model and stage model have their respective components. The FA model provides three types of application components: PageAbility, ServiceAbility, and DataAbility. The stage model provides two types of application components: UIAbility and ExtensionAbility. + + +You cannot use both models for the development of an application (see the figure below). However, a device (system) can contain applications developed on both models (scenario 3 in the figure below). In this case, their components may interact with each other. + +Figure 1 Coexistent application components of the FA model and stage model +![coexistence-of-FAandStage](figures/coexistence-of-FAandStage.png) + + +The following table lists the possible interaction scenarios. You must pay attention to the concerns listed below during your application development. + + +Table 1 Application component interaction scenarios + +| Interaction Scenario| Concerns| +| -------- | -------- | +| [Starting a UIAbility from the FA Model](start-uiability-from-fa.md) | Set **bundleName** and **abilityName** in the **want** parameter to the bundle name and ability name of the UIAbility in the stage model.| +| [Connecting to a ServiceExtensionAbility from the FA Model](bind-serviceextensionability-from-fa.md) | Set **bundleName** and **abilityName** in the **want** parameter to the bundle name and ability name of the ServiceExtensionAbility in the stage model.| +| [Accessing a DataShareExtensionAbility from the FA Model](access-datashareextensionability-from-fa.md) | No code modification is required. However, you need to understand the API compatibility of **DataShareHelper** and **DataAbilityHelper**.| +| [Starting a PageAbility from the Stage Model](start-pageability-from-stage.md) | Set **bundleName** and **abilityName** in the **want** parameter to the bundle name and ability name of the PageAbility in the FA model.| +| [Connecting to a ServiceAbility from the Stage Model](bind-serviceability-from-stage.md) | Set **bundleName** and **abilityName** in the **want** parameter to the bundle name and ability name of the ServiceAbility in the FA model.| +| Accessing a DataAbility from the Stage Model | This type of access is not supported.| diff --git a/en/application-dev/application-models/featureability-switch.md b/en/application-dev/application-models/featureability-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..f7db8056ea156650e11b55a78137de194ce9d43f --- /dev/null +++ b/en/application-dev/application-models/featureability-switch.md @@ -0,0 +1,16 @@ +# featureAbility Switching + + +| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [getWant(callback: AsyncCallback<Want>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitygetwant)
[getWant(): Promise<Want>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitygetwant-1) | \@ohos.app.ability.UIAbility.d.ts | [launchWant: Want;](../reference/apis/js-apis-app-ability-uiAbility.md#attributes)| +| [startAbility(parameter: StartAbilityParameter, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitystartability)
[startAbility(parameter: StartAbilityParameter): Promise<number>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitystartability-1) | application\UIAbilityContext.d.ts | [startAbility(want: Want, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartability)
[startAbility(want: Want, options: StartOptions, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartability-1)
[startAbility(want: Want, options?: StartOptions): Promise<void>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartability-2) | +| [getContext(): Context;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitygetcontext) | \@ohos.app.ability.UIAbility.d.ts | [context: UIAbilityContext;](../reference/apis/js-apis-app-ability-uiAbility.md#attributes)| +| [startAbilityForResult(parameter: StartAbilityParameter, callback: AsyncCallback<AbilityResult>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitystartabilityforresult7)
[startAbilityForResult(parameter: StartAbilityParameter): Promise<AbilityResult>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitystartabilityforresult7-1) | application\UIAbilityContext.d.ts | [startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilityforresult)
[startAbilityForResult(want: Want, options: StartOptions, callback: AsyncCallback<AbilityResult>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilityforresult-1)
[startAbilityForResult(want: Want, options?: StartOptions): Promise<AbilityResult>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilityforresult-2) | +| [terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityterminateselfwithresult7)
[terminateSelfWithResult(parameter: AbilityResult): Promise<void>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityterminateselfwithresult7-1) | application\UIAbilityContext.d.ts | [terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextterminateselfwithresult)
[terminateSelfWithResult(parameter: AbilityResult): Promise<void>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextterminateselfwithresult-1) | +| [terminateSelf(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityterminateself7)
[terminateSelf(): Promise<void>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityterminateself7-1) | application\UIAbilityContext.d.ts | [terminateSelf(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextterminateself)
[terminateSelf(): Promise<void>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextterminateself-1) | +| [acquireDataAbilityHelper(uri: string): DataAbilityHelper;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityacquiredataabilityhelper7) | \@ohos.data.dataShare.d.ts
\@ohos.data.fileAccess.d.ts | [createDataShareHelper(context: Context, uri: string, callback: AsyncCallback<DataShareHelper>): void;](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper)
[createDataShareHelper(context: Context, uri: string): Promise<DataShareHelper>;](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper-1)
[createFileAccessHelper(context: Context): FileAccessHelper;](../reference/apis/js-apis-fileAccess.md#fileaccesscreatefileaccesshelper-1)
[createFileAccessHelper(context: Context, wants: Array<Want>): FileAccessHelper;](../reference/apis/js-apis-fileAccess.md#fileaccesscreatefileaccesshelper) | +| [hasWindowFocus(callback: AsyncCallback<boolean>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityhaswindowfocus7)
[hasWindowFocus(): Promise<boolean>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityhaswindowfocus7-1) | \@ohos.window.d.ts | [on(eventType: 'windowStageEvent', callback: Callback<WindowStageEventType>): void;](../reference/apis/js-apis-window.md#onwindowstageevent9)
Checks whether the [active window](../reference/apis/js-apis-window.md#windowstageeventtype9) has the focus.| +| [connectAbility(request: Want, options:ConnectOptions ): number;](../reference/apis/js-apis-ability-featureAbility.md#featureabilityconnectability7) | application\UIAbilityContext.d.ts | [connectServiceExtensionAbility(want: Want, options: ConnectOptions): number;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability) | +| [disconnectAbility(connection: number, callback:AsyncCallback<void>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitydisconnectability7)
[disconnectAbility(connection: number): Promise<void>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitydisconnectability7-1) | application\UIAbilityContext.d.ts | [disconnectAbility(connection: number, callback:AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextdisconnectserviceextensionability-1)
[disconnectAbility(connection: number): Promise<void>;](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextdisconnectserviceextensionability) | +| [getWindow(callback: AsyncCallback<window.Window>): void;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitygetwindow7)
[getWindow(): Promise<window.Window>;](../reference/apis/js-apis-ability-featureAbility.md#featureabilitygetwindow7-1) | \@ohos.window.d.ts | [getLastWindow(ctx: BaseContext, callback: AsyncCallback<Window>): void;](../reference/apis/js-apis-window.md#windowgetlastwindow9)
[getLastWindow(ctx: BaseContext): Promise<Window>;](../reference/apis/js-apis-window.md#windowgetlastwindow9-1) | diff --git a/en/application-dev/application-models/figures/Ability-Life-Cycle-WindowStage.png b/en/application-dev/application-models/figures/Ability-Life-Cycle-WindowStage.png new file mode 100644 index 0000000000000000000000000000000000000000..e140763dfda32a5ad168e8a6daa38a9c51baf147 Binary files /dev/null and b/en/application-dev/application-models/figures/Ability-Life-Cycle-WindowStage.png differ diff --git a/en/application-dev/application-models/figures/Ability-Life-Cycle.png b/en/application-dev/application-models/figures/Ability-Life-Cycle.png new file mode 100644 index 0000000000000000000000000000000000000000..cc0681f5f2678ca15008d7b98d7ddc34d20dcf83 Binary files /dev/null and b/en/application-dev/application-models/figures/Ability-Life-Cycle.png differ diff --git a/en/application-dev/application-models/figures/ExtensionAbility-start.png b/en/application-dev/application-models/figures/ExtensionAbility-start.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd844f462199d5b7792cc5229fa763eb851a2d3 Binary files /dev/null and b/en/application-dev/application-models/figures/ExtensionAbility-start.png differ diff --git a/en/application-dev/application-models/figures/FAvsStage-uri.png b/en/application-dev/application-models/figures/FAvsStage-uri.png new file mode 100644 index 0000000000000000000000000000000000000000..132c1ba0f09f7da7344d6edcfae3c59fe355e7f9 Binary files /dev/null and b/en/application-dev/application-models/figures/FAvsStage-uri.png differ diff --git a/en/application-dev/application-models/figures/ServiceExtensionAbility-lifecycle.png b/en/application-dev/application-models/figures/ServiceExtensionAbility-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..fd3a15c8b1588e19d88938b39dbbc12b98d3c723 Binary files /dev/null and b/en/application-dev/application-models/figures/ServiceExtensionAbility-lifecycle.png differ diff --git a/en/application-dev/application-models/figures/api-switch-overview.png b/en/application-dev/application-models/figures/api-switch-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..c17f5d3deb13d9c2d31d1b1d8b8569c7bc842676 Binary files /dev/null and b/en/application-dev/application-models/figures/api-switch-overview.png differ diff --git a/en/application-dev/application-models/figures/application-component-configuration-stage.png b/en/application-dev/application-models/figures/application-component-configuration-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..9ddf0c3892998aa5391de99775db5965f66bd4b1 Binary files /dev/null and b/en/application-dev/application-models/figures/application-component-configuration-stage.png differ diff --git a/en/application-dev/application-models/figures/application-context-stage.png b/en/application-dev/application-models/figures/application-context-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..0d4c6cdfd040b4df9930d8bc639deff32f033824 Binary files /dev/null and b/en/application-dev/application-models/figures/application-context-stage.png differ diff --git a/en/application-dev/application-models/figures/call.png b/en/application-dev/application-models/figures/call.png new file mode 100644 index 0000000000000000000000000000000000000000..5a374f942e7754fa7b4e9303c89ee53d4ff8ee2b Binary files /dev/null and b/en/application-dev/application-models/figures/call.png differ diff --git a/en/application-dev/application-models/figures/coexistence-of-FAandStage.png b/en/application-dev/application-models/figures/coexistence-of-FAandStage.png new file mode 100644 index 0000000000000000000000000000000000000000..02e09b48b3f146371ddb6acac7e4a259be4448fb Binary files /dev/null and b/en/application-dev/application-models/figures/coexistence-of-FAandStage.png differ diff --git a/en/application-dev/application-models/figures/common-event.png b/en/application-dev/application-models/figures/common-event.png new file mode 100644 index 0000000000000000000000000000000000000000..24b51ff8718ae504ba69c1e12656d4daad797a62 Binary files /dev/null and b/en/application-dev/application-models/figures/common-event.png differ diff --git a/en/application-dev/application-models/figures/comparison-of-configuration-file.png b/en/application-dev/application-models/figures/comparison-of-configuration-file.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a2b47835f7814511049807f8582c50057bb459 Binary files /dev/null and b/en/application-dev/application-models/figures/comparison-of-configuration-file.png differ diff --git a/en/application-dev/application-models/figures/component-startup-inner-fa.png b/en/application-dev/application-models/figures/component-startup-inner-fa.png new file mode 100644 index 0000000000000000000000000000000000000000..f6ed21c09d9ae0d409a180885c172918a123c728 Binary files /dev/null and b/en/application-dev/application-models/figures/component-startup-inner-fa.png differ diff --git a/en/application-dev/application-models/figures/component-startup-inner-stage.png b/en/application-dev/application-models/figures/component-startup-inner-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..00514276f4ac3eb8ead650e5858cebb0a344d2c6 Binary files /dev/null and b/en/application-dev/application-models/figures/component-startup-inner-stage.png differ diff --git a/en/application-dev/application-models/figures/component-startup-inter-fa.png b/en/application-dev/application-models/figures/component-startup-inter-fa.png new file mode 100644 index 0000000000000000000000000000000000000000..2d50fb61e502ae2d2af917931d579ca2404d19b0 Binary files /dev/null and b/en/application-dev/application-models/figures/component-startup-inter-fa.png differ diff --git a/en/application-dev/application-models/figures/component-startup-inter-stage.png b/en/application-dev/application-models/figures/component-startup-inter-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..a6f79e6803edc160e5570729456569f46cc80967 Binary files /dev/null and b/en/application-dev/application-models/figures/component-startup-inter-stage.png differ diff --git a/en/application-dev/application-models/figures/context-dir.png b/en/application-dev/application-models/figures/context-dir.png new file mode 100644 index 0000000000000000000000000000000000000000..f16b56b43fbd0f493a10acecfb9b1edb79b2421f Binary files /dev/null and b/en/application-dev/application-models/figures/context-dir.png differ diff --git a/en/application-dev/application-models/figures/context-holding.png b/en/application-dev/application-models/figures/context-holding.png new file mode 100644 index 0000000000000000000000000000000000000000..fe4fbd4a4dff7024e3d5d35bd46d304d23e1f8c9 Binary files /dev/null and b/en/application-dev/application-models/figures/context-holding.png differ diff --git a/en/application-dev/application-models/figures/context-inheritance.png b/en/application-dev/application-models/figures/context-inheritance.png new file mode 100644 index 0000000000000000000000000000000000000000..2619daca03187d58db5b3690734704c66fb70d06 Binary files /dev/null and b/en/application-dev/application-models/figures/context-inheritance.png differ diff --git a/en/application-dev/application-models/figures/fa-dataability-uri.png b/en/application-dev/application-models/figures/fa-dataability-uri.png new file mode 100644 index 0000000000000000000000000000000000000000..d89ada0ee9b2f9f655a6c3d8b0df17d6b1ca9326 Binary files /dev/null and b/en/application-dev/application-models/figures/fa-dataability-uri.png differ diff --git a/en/application-dev/application-models/figures/fa-pageAbility-lifecycle.png b/en/application-dev/application-models/figures/fa-pageAbility-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..59a06741053c85cab6ea90b41bd16a6f2e1ff508 Binary files /dev/null and b/en/application-dev/application-models/figures/fa-pageAbility-lifecycle.png differ diff --git a/en/application-dev/application-models/figures/form-extension.png b/en/application-dev/application-models/figures/form-extension.png new file mode 100644 index 0000000000000000000000000000000000000000..ce47308856c4d41baff5dbaefdcefe9561b383b7 Binary files /dev/null and b/en/application-dev/application-models/figures/form-extension.png differ diff --git a/en/application-dev/application-models/figures/form_extension.png b/en/application-dev/application-models/figures/form_extension.png new file mode 100644 index 0000000000000000000000000000000000000000..daf36c75dae010492fa57ac05c85eaed58fbe00c Binary files /dev/null and b/en/application-dev/application-models/figures/form_extension.png differ diff --git a/en/application-dev/application-models/figures/globalThis1.png b/en/application-dev/application-models/figures/globalThis1.png new file mode 100644 index 0000000000000000000000000000000000000000..128f79d3437304845ac822d32377dab4cf0c9e05 Binary files /dev/null and b/en/application-dev/application-models/figures/globalThis1.png differ diff --git a/en/application-dev/application-models/figures/globalThis2.png b/en/application-dev/application-models/figures/globalThis2.png new file mode 100644 index 0000000000000000000000000000000000000000..11e015286489df52d5b9cd3ed35a564223b7ab4c Binary files /dev/null and b/en/application-dev/application-models/figures/globalThis2.png differ diff --git a/en/application-dev/application-models/figures/hop-cross-device-migration.png b/en/application-dev/application-models/figures/hop-cross-device-migration.png new file mode 100644 index 0000000000000000000000000000000000000000..1623bc94af414539f6634aea6d583e205eccf409 Binary files /dev/null and b/en/application-dev/application-models/figures/hop-cross-device-migration.png differ diff --git a/en/application-dev/application-models/figures/hop-multi-device-collaboration.png b/en/application-dev/application-models/figures/hop-multi-device-collaboration.png new file mode 100644 index 0000000000000000000000000000000000000000..28fa0a6e269a4266236898e19ce7bca4e670027d Binary files /dev/null and b/en/application-dev/application-models/figures/hop-multi-device-collaboration.png differ diff --git a/en/application-dev/application-models/figures/hop-structure.png b/en/application-dev/application-models/figures/hop-structure.png new file mode 100644 index 0000000000000000000000000000000000000000..96b82de856fcbc7db6d7668791a668ec152141fc Binary files /dev/null and b/en/application-dev/application-models/figures/hop-structure.png differ diff --git a/en/application-dev/application-models/figures/mission-and-singleton.png b/en/application-dev/application-models/figures/mission-and-singleton.png new file mode 100644 index 0000000000000000000000000000000000000000..eee0a39644d7080e9f9f26f30b184d679a5bff3c Binary files /dev/null and b/en/application-dev/application-models/figures/mission-and-singleton.png differ diff --git a/en/application-dev/application-models/figures/mission-and-specified.png b/en/application-dev/application-models/figures/mission-and-specified.png new file mode 100644 index 0000000000000000000000000000000000000000..6af8c28d4277b3582fed2cfc313cc301086e6314 Binary files /dev/null and b/en/application-dev/application-models/figures/mission-and-specified.png differ diff --git a/en/application-dev/application-models/figures/mission-and-standard.png b/en/application-dev/application-models/figures/mission-and-standard.png new file mode 100644 index 0000000000000000000000000000000000000000..feeed48f41371bf22abbee8dbae4695b11ed2514 Binary files /dev/null and b/en/application-dev/application-models/figures/mission-and-standard.png differ diff --git a/en/application-dev/application-models/figures/mission-chain1.png b/en/application-dev/application-models/figures/mission-chain1.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9ce7dd3c74b26e0dd8d1b12e00d6414e3cdadb Binary files /dev/null and b/en/application-dev/application-models/figures/mission-chain1.png differ diff --git a/en/application-dev/application-models/figures/mission-chain2.png b/en/application-dev/application-models/figures/mission-chain2.png new file mode 100644 index 0000000000000000000000000000000000000000..7ed2b6f0052a08445c53ec2882a7f474fa5a4763 Binary files /dev/null and b/en/application-dev/application-models/figures/mission-chain2.png differ diff --git a/en/application-dev/application-models/figures/mission-chain3.png b/en/application-dev/application-models/figures/mission-chain3.png new file mode 100644 index 0000000000000000000000000000000000000000..e02c135ad4a90f99bb65bdccd821d29990b9536e Binary files /dev/null and b/en/application-dev/application-models/figures/mission-chain3.png differ diff --git a/en/application-dev/application-models/figures/mission-list-manager.png b/en/application-dev/application-models/figures/mission-list-manager.png new file mode 100644 index 0000000000000000000000000000000000000000..792745f100e6ba3613c3a496421b00bbb5f6db8f Binary files /dev/null and b/en/application-dev/application-models/figures/mission-list-manager.png differ diff --git a/en/application-dev/application-models/figures/mission-record.png b/en/application-dev/application-models/figures/mission-record.png new file mode 100644 index 0000000000000000000000000000000000000000..77f9c156d83876524977a139308046a6acfed711 Binary files /dev/null and b/en/application-dev/application-models/figures/mission-record.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview1.png b/en/application-dev/application-models/figures/model-switch-overview1.png new file mode 100644 index 0000000000000000000000000000000000000000..e9d8a120dedcda4f27f5f92e52c826b900a105d9 Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview1.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview2.png b/en/application-dev/application-models/figures/model-switch-overview2.png new file mode 100644 index 0000000000000000000000000000000000000000..522656745c55d165208be94b23d264c334421722 Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview2.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview3.png b/en/application-dev/application-models/figures/model-switch-overview3.png new file mode 100644 index 0000000000000000000000000000000000000000..e7fe19489d38bf971619dbb41294c5287377b8dc Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview3.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview4.png b/en/application-dev/application-models/figures/model-switch-overview4.png new file mode 100644 index 0000000000000000000000000000000000000000..e455ae9333e73b0898d6dd1700e79cbe529b7163 Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview4.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview5.png b/en/application-dev/application-models/figures/model-switch-overview5.png new file mode 100644 index 0000000000000000000000000000000000000000..82d5dbc6fee5b3b393e0a1abd8f4e7fbbeb0c4ac Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview5.png differ diff --git a/en/application-dev/application-models/figures/model-switch-overview6.png b/en/application-dev/application-models/figures/model-switch-overview6.png new file mode 100644 index 0000000000000000000000000000000000000000..c17f5d3deb13d9c2d31d1b1d8b8569c7bc842676 Binary files /dev/null and b/en/application-dev/application-models/figures/model-switch-overview6.png differ diff --git a/en/application-dev/application-models/figures/multi-process.png b/en/application-dev/application-models/figures/multi-process.png new file mode 100644 index 0000000000000000000000000000000000000000..55ab9a514c3fd1136747efc1bbb80ec900891bce Binary files /dev/null and b/en/application-dev/application-models/figures/multi-process.png differ diff --git a/en/application-dev/application-models/figures/page-ability-lifecycle.png b/en/application-dev/application-models/figures/page-ability-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..b35954967bb9c733725da2f0700481932619ae45 Binary files /dev/null and b/en/application-dev/application-models/figures/page-ability-lifecycle.png differ diff --git a/en/application-dev/application-models/figures/pageability-switch.png b/en/application-dev/application-models/figures/pageability-switch.png new file mode 100644 index 0000000000000000000000000000000000000000..4b68d46e529715a7258eb295bef1648da0b8ebbd Binary files /dev/null and b/en/application-dev/application-models/figures/pageability-switch.png differ diff --git a/en/application-dev/application-models/figures/process-model-fa.png b/en/application-dev/application-models/figures/process-model-fa.png new file mode 100644 index 0000000000000000000000000000000000000000..2a71de2389970a63d0a9dc2ec7d3c5b44e58a9ca Binary files /dev/null and b/en/application-dev/application-models/figures/process-model-fa.png differ diff --git a/en/application-dev/application-models/figures/process-model.png b/en/application-dev/application-models/figures/process-model.png new file mode 100644 index 0000000000000000000000000000000000000000..f6f3b22381539ac73371b4c7f6025a5c3127838b Binary files /dev/null and b/en/application-dev/application-models/figures/process-model.png differ diff --git a/en/application-dev/application-models/figures/stage-concepts.png b/en/application-dev/application-models/figures/stage-concepts.png new file mode 100644 index 0000000000000000000000000000000000000000..42e99447a780b167adaf6ddd196bea4437dfa1a7 Binary files /dev/null and b/en/application-dev/application-models/figures/stage-concepts.png differ diff --git a/en/application-dev/application-models/figures/stage-want1.png b/en/application-dev/application-models/figures/stage-want1.png new file mode 100644 index 0000000000000000000000000000000000000000..558f0a8588d7785eaad1402e68d6ba60c3118f27 Binary files /dev/null and b/en/application-dev/application-models/figures/stage-want1.png differ diff --git a/en/application-dev/application-models/figures/stage-want2.png b/en/application-dev/application-models/figures/stage-want2.png new file mode 100644 index 0000000000000000000000000000000000000000..72829adade52ee11419d726f19e218ec4de15220 Binary files /dev/null and b/en/application-dev/application-models/figures/stage-want2.png differ diff --git a/en/application-dev/application-models/figures/standard-mode.png b/en/application-dev/application-models/figures/standard-mode.png new file mode 100644 index 0000000000000000000000000000000000000000..fc903e6c1be80d3c00281d00d9ab0a1e334d7724 Binary files /dev/null and b/en/application-dev/application-models/figures/standard-mode.png differ diff --git a/en/application-dev/application-models/figures/startAbilityWtExplicitWant.PNG b/en/application-dev/application-models/figures/startAbilityWtExplicitWant.PNG new file mode 100644 index 0000000000000000000000000000000000000000..1d9e25f148d08a58a0ac45b703e08072f52fc300 Binary files /dev/null and b/en/application-dev/application-models/figures/startAbilityWtExplicitWant.PNG differ diff --git a/en/application-dev/application-models/figures/thread-model-stage.png b/en/application-dev/application-models/figures/thread-model-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..eb407a10616ce3eb1584f81ad80c4f29a7e95c10 Binary files /dev/null and b/en/application-dev/application-models/figures/thread-model-stage.png differ diff --git a/en/application-dev/application-models/figures/uiability-intra-device-interaction.png b/en/application-dev/application-models/figures/uiability-intra-device-interaction.png new file mode 100644 index 0000000000000000000000000000000000000000..92292f2c6ef4c9cbd06da2a523f27b571a957e2b Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-intra-device-interaction.png 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 new file mode 100644 index 0000000000000000000000000000000000000000..c4f5aa4b9a988d8e7148b504c4dcc163961cb103 Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-launch-type1.png 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 new file mode 100644 index 0000000000000000000000000000000000000000..6f0e43d24f745aee41601cc48f4bc138572fbeb5 Binary files /dev/null and b/en/application-dev/application-models/figures/uiability-launch-type2.png differ diff --git a/en/application-dev/application-models/figures/uiability_not_first_started.png b/en/application-dev/application-models/figures/uiability_not_first_started.png new file mode 100644 index 0000000000000000000000000000000000000000..5cff262167ce720b736d6ea554f2355efa0c928e Binary files /dev/null and b/en/application-dev/application-models/figures/uiability_not_first_started.png differ diff --git a/en/application-dev/application-models/figures/usage-of-want.png b/en/application-dev/application-models/figures/usage-of-want.png new file mode 100644 index 0000000000000000000000000000000000000000..86b41b256ee8358c0fa87899b18ae249d28668c7 Binary files /dev/null and b/en/application-dev/application-models/figures/usage-of-want.png differ diff --git a/en/application-dev/application-models/figures/want-action.png b/en/application-dev/application-models/figures/want-action.png new file mode 100644 index 0000000000000000000000000000000000000000..0d8e18ce5870bea777c26b832d3f29674c2fa261 Binary files /dev/null and b/en/application-dev/application-models/figures/want-action.png differ diff --git a/en/application-dev/application-models/figures/want-entities.png b/en/application-dev/application-models/figures/want-entities.png new file mode 100644 index 0000000000000000000000000000000000000000..bf1b85594f1d34c966c061574f6bf6c3cb75bf2f Binary files /dev/null and b/en/application-dev/application-models/figures/want-entities.png differ diff --git a/en/application-dev/application-models/figures/want-uri-type1.png b/en/application-dev/application-models/figures/want-uri-type1.png new file mode 100644 index 0000000000000000000000000000000000000000..e0fe40d1a3cd40b72379bd947aaf2e3977021b32 Binary files /dev/null and b/en/application-dev/application-models/figures/want-uri-type1.png differ diff --git a/en/application-dev/application-models/figures/want-uri-type2.png b/en/application-dev/application-models/figures/want-uri-type2.png new file mode 100644 index 0000000000000000000000000000000000000000..9a64d865066e381536a268023918975e783ddf5e Binary files /dev/null and b/en/application-dev/application-models/figures/want-uri-type2.png differ diff --git a/en/application-dev/application-models/figures/widget-development-fa.png b/en/application-dev/application-models/figures/widget-development-fa.png new file mode 100644 index 0000000000000000000000000000000000000000..795e96171e6d890e72a09382906302dd0fa45fab Binary files /dev/null and b/en/application-dev/application-models/figures/widget-development-fa.png differ diff --git a/en/application-dev/application-models/figures/widget-development-stage.png b/en/application-dev/application-models/figures/widget-development-stage.png new file mode 100644 index 0000000000000000000000000000000000000000..795e96171e6d890e72a09382906302dd0fa45fab Binary files /dev/null and b/en/application-dev/application-models/figures/widget-development-stage.png differ diff --git a/en/application-dev/application-models/figures/widget-switch1.png b/en/application-dev/application-models/figures/widget-switch1.png new file mode 100644 index 0000000000000000000000000000000000000000..71aaf2e41cdf012820c121e5bf538b8c5b8b0784 Binary files /dev/null and b/en/application-dev/application-models/figures/widget-switch1.png differ diff --git a/en/application-dev/application-models/figures/widget-switch2.png b/en/application-dev/application-models/figures/widget-switch2.png new file mode 100644 index 0000000000000000000000000000000000000000..230836fd2c992de1d434e506bf48ff7876f1a5e8 Binary files /dev/null and b/en/application-dev/application-models/figures/widget-switch2.png differ diff --git a/en/application-dev/application-models/figures/widget-switch3.png b/en/application-dev/application-models/figures/widget-switch3.png new file mode 100644 index 0000000000000000000000000000000000000000..1e62fb7ca3be5fa73fb11d809d929b319ce05666 Binary files /dev/null and b/en/application-dev/application-models/figures/widget-switch3.png differ diff --git a/en/application-dev/application-models/figures/widget-switch4.png b/en/application-dev/application-models/figures/widget-switch4.png new file mode 100644 index 0000000000000000000000000000000000000000..65a63969a29dbf9c108618a9ea02db201ec3307d Binary files /dev/null and b/en/application-dev/application-models/figures/widget-switch4.png differ diff --git a/en/application-dev/application-models/hop-cross-device-migration.md b/en/application-dev/application-models/hop-cross-device-migration.md new file mode 100644 index 0000000000000000000000000000000000000000..6d30435a819da49855cf9ae818bac419a1c0b614 --- /dev/null +++ b/en/application-dev/application-models/hop-cross-device-migration.md @@ -0,0 +1,151 @@ +# Cross-Device Migration + + +## When to Use + +Cross-device migration is available only for system applications. The main task is to migrate the current task (including the page control status) of an application to the target device so that the task can continue on it. Cross-device migration supports the following functionalities: + +- Storage and restoration of custom data + +- Storage and restoration of page routing information and page control status data + +- Application compatibility detection + + +## Cross-Device Migration Process + +The following figure shows the cross-device migration process. + +**Figure 1** Cross-device migration process +![hop-cross-device-migration](figures/hop-cross-device-migration.png) + + +## Constraints + +- Since cross-device migration task management is not available, you can only develop applications that support cross-device migration. Your application cannot initiate migration. + +- Cross-device migration can be performed between the same UIAbility component. In other words, the components must have the same **bundleName**, **abilityName**, and **signature**. + + +## Best Practices + +For better user experience, you are advised to use the **wantParam** parameter to transmit data smaller than 100 KB. + + +## Available APIs + +The table below describes the main APIs used for cross-device migration. For details, see [API Reference](../reference/apis/js-apis-app-ability-uiAbility.md). + +**Table 1** Cross-device migration APIs + +| **API**| Description| +| -------- | -------- | +| onContinue(wantParam : {[key: string]: any}): OnContinueResult | Called by the initiator to store the data required for migration and indicate whether the migration is accepted.
- **AGREE**: The migration is accepted.
- **REJECT**: The migration is rejected.
- **MISMATCH**: The version does not match.| +| onCreate(want: Want, param: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the multi-instance migration scenario.| +| onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the singleton migration scenario.| + + +## How to Develop + +1. Configure the data synchronization permission in the **module.json5** file. The sample code is as follows: + + ```json + { + "module": { + "requestPermissions":[ + { + "name" : "ohos.permission.DISTRIBUTED_DATASYNC", + } + ] + } + } + ``` + +2. Configure the fields related to cross-device migration in the configuration file. + - Configure the application to support migration. + + + Set the **continuable** field in the **module.json5** file to **true**. The default value is **false**. If this parameter is set to **false**, the application cannot be continued on the target device. + ```json + { + "module": { + // ... + "abilities": [ + { + // ... + "continuable": true, + } + ] + } + } + ``` + + - Configure the application launch type. For details, see [UIAbility Component Launch Type](uiability-launch-type.md). + +3. Request the data synchronization permission. The sample code for displaying a dialog box to request the permission is as follows: + + ```ts + requestPermission() { + let context = this.context + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC'] + context.requestPermissionsFromUser(permissions).then((data) => { + console.info("Succeed to request permission from user with data: "+ JSON.stringify(data)) + }).catch((error) => { + console.info("Failed to request permission from user with error: "+ JSON.stringify(error)) + }) + } + ``` + +4. Implement [onContinue()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncontinue) in the UIAbility of the initiator. + + [onContinue()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityoncontinue) is called on the initiator. You can save the data in this method to implement application compatibility check and migration decision. + + - Saving migrated data: You can save the data to be migrated in key-value pairs in **wantParam**. + + - Checking application compatibility: You can obtain the version number of the target application from **wantParam** and check the compatibility between the target application and the current application. + + - Making a migration decision: You can determine whether to support the migration based on the return value of **onContinue()**. For details about the return value, see [Available APIs](#available-apis). + + The sample code is as follows: + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + import AbilityConstant from '@ohos.app.ability.AbilityConstant'; + + onContinue(wantParam : {[key: string]: any}) { + console.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`) + let workInput = AppStorage.Get('ContinueWork'); + // Set the user input data into wantParam. + wantParam["work"] = workInput // set user input data into want params + console.info(`onContinue input = ${wantParam["input"]}`); + return AbilityConstant.OnContinueResult.AGREE + } + ``` + +5. Implement **onCreate()** and **onNewWant()** in the UIAbility of the target application to implement data restoration. + - Implementation example of **onCreate** in the multi-instance scenario + - The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate()**. + - You can obtain the saved migration data from the **want** parameter. + - After data restoration is complete, call **restoreWindowStage()** to trigger page restoration. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + import AbilityConstant from '@ohos.app.ability.AbilityConstant'; + import distributedObject from '@ohos.data.distributedDataObject'; + + export default class EntryAbility extends UIAbility { + storage : LocalStorage; + onCreate(want, launchParam) { + console.info(`EntryAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`) + if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { + // Obtain the user data from the want parameter. + let workInput = want.parameters.work + console.info(`work input ${workInput}`) + AppStorage.SetOrCreate('ContinueWork', workInput) + this.storage = new LocalStorage(); + this.context.restoreWindowStage(this.storage); + } + } + } + ``` + - For a singleton ability, use **onNewWant()** to achieve the same implementation. diff --git a/en/application-dev/application-models/hop-multi-device-collaboration.md b/en/application-dev/application-models/hop-multi-device-collaboration.md new file mode 100644 index 0000000000000000000000000000000000000000..3a6fa2646a37785d41793407d4803d60743342dd --- /dev/null +++ b/en/application-dev/application-models/hop-multi-device-collaboration.md @@ -0,0 +1,536 @@ +# Multi-device Collaboration + + +## When to Use + +Multi-device coordination is available only for system applications. It involves the following scenarios: + +- [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned) + +- [Starting UIAbility Across Devices (Data Returned)](#starting-uiability-across-devices-data-returned) + +- [Connecting to ServiceExtensionAbility Across Devices](#connecting-to-serviceextensionability-across-devices) + +- [Using Cross-Device Ability Call](#using-cross-device-ability-call) + + +## Multi-Device Collaboration Process + +The figure below shows the multi-device collaboration process. + +**Figure 1** Multi-device collaboration process +![hop-multi-device-collaboration](figures/hop-multi-device-collaboration.png) + + +## Constraints + +- Since multi-device collaboration task management is not available, you can obtain the device list by developing system applications. Access to third-party applications is not supported. + +- Multi-device collaboration must comply with [Inter-Device Component Startup Rules](component-startup-rules.md#inter-device-component-startup-rules). + +- For better user experience, you are advised to use the **want** parameter to transmit data smaller than 100 KB. + + +## Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned) + +On device A, touch the **Start** button provided by the initiator application to start a specified UIAbility on device B. + + +### Available APIs + +**Table 1** Cross-device startup APIs + +| **API**| **Description**| +| -------- | -------- | +| startAbility(want: Want, callback: AsyncCallback<void>): void; | Starts UIAbility and ServiceExtensionAbility. This API uses an asynchronous callback to return the result.| + + +### How to Develop + +1. Request the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + +2. Request the data synchronization permission. The sample code for displaying a dialog box to request the permission is as follows: + + ```ts + requestPermission() { + let context = this.context; + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; + context.requestPermissionsFromUser(permissions).then((data) => { + console.info("Succeed to request permission from user with data: "+ JSON.stringify(data)); + }).catch((error) => { + console.info("Failed to request permission from user with error: "+ JSON.stringify(error)); + }) + } + ``` + +3. Obtain the device ID of the target device. + + ```ts + import deviceManager from '@ohos.distributedHardware.deviceManager'; + + let dmClass; + function initDmClass() { + // createDeviceManager is a system API. + deviceManager.createDeviceManager('ohos.samples.demo', (err, dm) => { + if (err) { + // ... + return + } + dmClass = dm + }) + } + function getRemoteDeviceId() { + if (typeof dmClass === 'object' && dmClass !== null) { + let list = dmClass.getTrustedDeviceListSync() + if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') { + console.info('EntryAbility onButtonClick getRemoteDeviceId err: list is null') + return; + } + return list[0].deviceId + } else { + console.info('EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null') + } + } + ``` + +4. Set the target component parameters, and call **startAbility()** to start UIAbility or ServiceExtensionAbility. + + ```ts + let want = { + deviceId: getRemoteDeviceId(), + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', // moduleName is optional. + } + // context is the ability-level context of the initiator UIAbility. + this.context.startAbility(want).then(() => { + // ... + }).catch((err) => { + // ... + }) + ``` + + +## Starting UIAbility Across Devices (Data Returned) + +On device A, touch the **Start** button provided by the initiator application to start a specified UIAbility on device B. When the UIAbility on device B exits, a value is sent back to the initiator application. + + +### Available APIs + +**Table 2** APIs for starting an ability across devices and returning the result data + +| API| Description| +| -------- | -------- | +| startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void; | Starts a UIAbility. This API uses an asynchronous callback to return the result when the UIAbility is terminated.| +| terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void;| Terminates this UIAbility. This API uses an asynchronous callback to return the ability result information. It is used together with **startAbilityForResult**.| +| terminateSelfWithResult(parameter: AbilityResult): Promise<void>; | Terminates this UIAbility. This API uses a promise to return the ability result information. It is used together with **startAbilityForResult**.| + + +### How to Develop + +1. Request the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + +2. Request the data synchronization permission. The sample code for displaying a dialog box to request the permission is as follows: + + ```ts + requestPermission() { + let context = this.context; + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; + context.requestPermissionsFromUser(permissions).then((data) => { + console.info("Succeed to request permission from user with data: "+ JSON.stringify(data)); + }).catch((error) => { + console.info("Failed to request permission from user with error: "+ JSON.stringify(error)); + }) + } + ``` + +3. Set the target component parameters on the initiator, and call **startAbilityForResult()** to start the target UIAbility. **data** in the asynchronous callback is used to receive the information returned by the target UIAbility to the initiator UIAbility after the target UIAbility terminates itself. For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned). + + ```ts + let want = { + deviceId: getRemoteDeviceId(), + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', // moduleName is optional. + } + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(want).then((data) => { + // ... + }).catch((err) => { + // ... + }) + ``` + +4. After the UIAbility task at the target device is complete, call **terminateSelfWithResult()** to return the data to the initiator UIAbility. + + ```ts + const RESULT_CODE: number = 1001; + let abilityResult = { + resultCode: RESULT_CODE, + want: { + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', + }, + } + // context is the ability-level context of the target UIAbility. + this.context.terminateSelfWithResult(abilityResult, (err) => { + // ... + }); + ``` + +5. The initiator UIAbility receives the information returned by the target UIAbility and processes the information. + + ```ts + const RESULT_CODE: number = 1001; + + // ... + + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(want).then((data) => { + if (data?.resultCode === RESULT_CODE) { + // Parse the information returned by the target UIAbility. + let info = data.want?.parameters?.info + // ... + } + }).catch((err) => { + // ... + }) + ``` + + +## Connecting to ServiceExtensionAbility Across Devices + +A system application can connect to a service on another device by calling [connectServiceExtensionAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextconnectserviceextensionability). For example, in the distributed game scenario, a tablet is used as the remote control and a smart TV is used as the display. + + +### Available APIs + +**Table 3** APIs for cross-device connection + +| API| Description| +| -------- | -------- | +| connectServiceExtensionAbility(want: Want, options: ConnectOptions): number; | Connects to a ServiceExtensionAbility.| +| disconnectServiceExtensionAbility(connection: number, callback: AsyncCallback<void>): void; | Disconnects a connection. This API uses an asynchronous callback to return the result.| +| disconnectServiceExtensionAbility(connection: number): Promise<void>; | Disconnects a connection. This API uses a promise to return the result.| + + +### How to Develop + +1. Request the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + +2. Request the data synchronization permission. The sample code for displaying a dialog box to request the permission is as follows: + + ```ts + requestPermission() { + let context = this.context; + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; + context.requestPermissionsFromUser(permissions).then((data) => { + console.info("Succeed to request permission from user with data: "+ JSON.stringify(data)); + }).catch((error) => { + console.info("Failed to request permission from user with error: "+ JSON.stringify(error)); + }) + } + ``` + +3. (Optional) [Implement a background service](serviceextensionability.md#implementing-a-background-service). Perform this operation only if no background service is available. + +4. Connect to the background service. + - Implement the **IAbilityConnection** class. **IAbilityConnection** provides the following callbacks that you should implement: **onConnect()**, **onDisconnect()**, and **onFailed()**. The **onConnect()** callback is invoked when a service is connected, **onDisconnect()** is invoked when a service is unexpectedly disconnected, and **onFailed()** is invoked when the connection to a service fails. + - Set the target component parameters, including the target device ID, bundle name, and ability name. + - Call **connectServiceExtensionAbility** to initiate a connection. + - Receive the service handle returned by the target device when the connection is successful. + - Perform cross-device invoking and obtain the result returned by the target service. + + ```ts + import rpc from '@ohos.rpc'; + + const REQUEST_CODE = 99; + let want = { + "deviceId": getRemoteDeviceId(), + "bundleName": "com.example.myapplication", + "abilityName": "ServiceExtAbility" + }; + let options = { + onConnect(elementName, remote) { + console.info('onConnect callback'); + if (remote === null) { + console.info(`onConnect remote is null`); + return; + } + let option = new rpc.MessageOption(); + let data = new rpc.MessageParcel(); + let reply = new rpc.MessageParcel(); + data.writeInt(1); + data.writeInt(99); // You can send data to the target application for corresponding operations. + + // @param code Indicates the service request code sent by the client. + // @param data Indicates the {@link MessageParcel} 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) => { + let msg = reply.readInt(); // Receive the information (100) returned by the target device if the connection is successful. + console.info(`sendRequest ret:${ret} msg:${msg}`); + }).catch((error) => { + console.info('sendRequest failed'); + }); + }, + 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); + ``` + + For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned). + +5. Disconnect the connection. Use **disconnectServiceExtensionAbility()** to disconnect from the background service. + + ```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'); + }) + ``` + + +## Using Cross-Device Ability Call + +The basic principle of cross-device ability call is the same as that of intra-device ability call. For details, see [Using Ability Call to Implement UIAbility Interaction](uiability-intra-device-interaction.md#using-ability-call-to-implement-uiability-interaction). + +The following describes how to implement multi-device collaboration through cross-device ability call. + + +### Available APIs + +**Table 4** Ability call APIs + +| API| Description| +| -------- | -------- | +| startAbilityByCall(want: Want): Promise<Caller>; | Starts a UIAbility in the foreground or background and obtains the caller object for communicating with the UIAbility.| +| on(method: string, callback: CalleeCallBack): void | Callback invoked when the callee ability registers a method.| +| off(method: string): void | Callback invoked when the callee ability deregisters a method.| +| call(method: string, data: rpc.Sequenceable): Promise<void> | Sends agreed sequenceable data to the callee ability.| +| callWithResult(method: string, data: rpc.Sequenceable): Promise<rpc.MessageParcel> | Sends agreed sequenceable data to the callee ability and obtains the agreed sequenceable data returned by the callee ability.| +| release(): void | Releases the caller object.| +| on(type: "release", callback: OnReleaseCallback): void | Callback invoked when the caller object is released.| + + +### How to Develop + +1. Request the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + +2. Request the data synchronization permission. The sample code for displaying a dialog box to request the permission is as follows: + + ```ts + requestPermission() { + let context = this.context; + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC']; + context.requestPermissionsFromUser(permissions).then((data) => { + console.info("Succeed to request permission from user with data: "+ JSON.stringify(data)); + }).catch((error) => { + console.info("Failed to request permission from user with error: "+ JSON.stringify(error)); + }) + } + ``` + +3. Create the callee ability. + + For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use **on()** to register a listener. When data does not need to be received, use **off()** to deregister the listener. + + 1. Configure the launch type of the UIAbility. + + Set **launchType** of the callee ability to **singleton** in the **module.json5** file. + + | JSON Field| Description| + | -------- | -------- | + | "launchType"| Ability launch type. Set this parameter to **singleton**.| + + An example of the UIAbility configuration is as follows: + + + ```json + "abilities":[{ + "name": ".CalleeAbility", + "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", + "launchType": "singleton", + "description": "$string:CalleeAbility_desc", + "icon": "$media:icon", + "label": "$string:CalleeAbility_label", + "visible": true + }] + ``` + + 2. Import the **UIAbility** module. + + ```ts + import Ability from '@ohos.app.ability.UIAbility'; + ``` + + 3. Define the agreed sequenceable data. + + The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string. + + ```ts + export default class MySequenceable { + num: number = 0 + str: string = "" + + constructor(num, string) { + this.num = num + this.str = string + } + + marshalling(messageParcel) { + messageParcel.writeInt(this.num) + messageParcel.writeString(this.str) + return true + } + + unmarshalling(messageParcel) { + this.num = messageParcel.readInt() + this.str = messageParcel.readString() + return true + } + } + ``` + + 4. Implement **Callee.on** and **Callee.off**. + + In the following example, the **MSG_SEND_METHOD** listener is registered in **onCreate()** of the ability and deregistered in **onDestroy()**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. + + ```ts + const TAG: string = '[CalleeAbility]' + const MSG_SEND_METHOD: string = 'CallSendMsg' + + function sendMsgCallback(data) { + console.info('CalleeSortFunc called') + + // Obtain the sequenceable data sent by the caller ability. + let receivedData = new MySequenceable(0, '') + data.readSequenceable(receivedData) + console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`) + + // Process the data. + // Return the sequenceable data result to the caller ability. + return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`) + } + + export default class CalleeAbility extends Ability { + onCreate(want, launchParam) { + try { + this.callee.on(MSG_SEND_METHOD, sendMsgCallback) + } catch (error) { + console.info(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) + } + } + + onDestroy() { + try { + this.callee.off(MSG_SEND_METHOD) + } catch (error) { + console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`) + } + } + } + ``` + +4. Obtain the caller object and access the callee ability. + 1. Import the **UIAbility** module. + + ```ts + import Ability from '@ohos.app.ability.UIAbility'; + ``` + + 2. Obtain the caller object. + + The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the caller object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements. + + + ```ts + async onButtonGetRemoteCaller() { + var caller = undefined + var context = this.context + + context.startAbilityByCall({ + deviceId: getRemoteDeviceId(), + bundleName: 'com.samples.CallApplication', + abilityName: 'CalleeAbility' + }).then((data) => { + if (data != null) { + caller = data + console.info('get remote caller success') + // Register the onRelease() listener of the caller ability. + caller.onRelease((msg) => { + console.info(`remote caller onRelease is called ${msg}`) + }) + console.info('remote caller register OnRelease succeed') + } + }).catch((error) => { + console.error(`get remote caller failed with ${error}`) + }) + } + ``` + + For details about how to implement **getRemoteDeviceId()**, see [Starting UIAbility and ServiceExtensionAbility Across Devices (No Data Returned)](#starting-uiability-and-serviceextensionability-across-devices-no-data-returned). + +5. Sends agreed sequenceable data to the callee ability. + 1. The sequenceable data can be sent to the callee ability with or without a return value. The method and sequenceable data must be consistent with those of the callee ability. The following example describes how to send data to the callee ability. + + ```ts + const MSG_SEND_METHOD: string = 'CallSendMsg'; + async onButtonCall() { + try { + let msg = new MySequenceable(1, 'origin_Msg'); + await this.caller.call(MSG_SEND_METHOD, msg); + } catch (error) { + console.info(`caller call failed with ${error}`); + } + } + ``` + 2. In the following, **CallWithResult** is used to send data **originMsg** to the callee ability and assign the data processed by the **CallSendMsg** method to **backMsg**. + + ```ts + const MSG_SEND_METHOD: string = 'CallSendMsg'; + originMsg: string = ''; + backMsg: string = ''; + async onButtonCallWithResult(originMsg, backMsg) { + try { + let msg = new MySequenceable(1, originMsg); + const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg); + console.info('caller callWithResult succeed'); + + let result = new MySequenceable(0, ''); + data.readSequenceable(result); + backMsg(result.str); + console.info(`caller result is [${result.num}, ${result.str}]`); + } catch (error) { + console.info(`caller callWithResult failed with ${error}`); + } + } + ``` + +6. Release the caller object. + + When the caller object is no longer required, use **release()** to release it. + + ```ts + releaseCall() { + try { + this.caller.release(); + this.caller = undefined + console.info('caller release succeed'); + } catch (error) { + console.info(`caller release failed with ${error}`); + } + } + ``` diff --git a/en/application-dev/application-models/inter-device-interaction-hop-overview.md b/en/application-dev/application-models/inter-device-interaction-hop-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1fd28b489f0d6d891abd9dffa0bcaf0f1b9ead --- /dev/null +++ b/en/application-dev/application-models/inter-device-interaction-hop-overview.md @@ -0,0 +1,49 @@ +# Continuation Overview + + +## When to Use + +As the all-scenario, multi-device lifestyle becomes popular, users have an increasing number of devices. Each device provides users with what they need in a certain scenario. For example, watches allow users to view information in a timely manner, and smart TVs bring them an immersive watching experience. However, each device has its limitation, for example, typing text on a smart TV is frustrating as it is much more difficult than on a mobile device. If multiple devices can sense each other through a distributed OS and together form a super device, the strengths of each device can be fully exerted to provide a more natural and smoother distributed experience for users. + +In OpenHarmony, distributed operations across devices are called continuation (previously named hopping), which is further classified into [cross-device migration](hop-cross-device-migration.md) and [multi-device collaboration](hop-multi-device-collaboration.md). To implement continuation, cross-device interaction capabilities of application components are required. Currently, these capabilities are open only to system applications. + + +## Basic Concepts + +- **Continuation** + + Continuation refers to distributed operations across devices. It breaks device boundaries and makes applications modular. For example, a user can edit the same email, carry out fitness, or play a game across devices. Continuation provides broad application scenarios, innovative product perspectives, enhanced product advantages, and superior experience. + +- **Cross-device migration** + + When the environment changes, for example, when a user goes outdoors or when a more appropriate device is detected, the user can migrate an ongoing task to another device for better experience. The original device exits the task. A typical cross-device migration scenario is as follows: You migrate a video playback task from your tablet to a smart TV. The video application on the tablet exits. From the perspective of application development, cross-device migration migrates the UIAbility component running on device A to device B. After the migration is complete, the UIAbility component on device B continues the task, whereas that on device A exits. + +- **Multi-device collaboration** + + Multi-device collaboration enables collaboration between multiple devices, providing users with more efficient and immersive experience than with a single device. A typical multi-device collaboration scenario is as follows: Application A on the tablet is used as the answer board, and application B on the smart TV is used for live broadcast, delivering a better online class experience. From the perspective of application development, multi-device collaboration enables different UIAbility or ServiceExtensionAbility components to run simultaneously or alternately on multiple devices to provide a complete service, or enables the same UIAbility and ServiceExtensionAbility component to run simultaneously on multiple devices to provide a complete service. + + +## Continuation Architecture + +OpenHarmony provides a set of APIs for you to implement continuation in your applications. The continuation architecture has the following advantages: + +- Capabilities such as remote service invocation to facilitate service design + +- Simultaneous continuation of multiple applications + +- Different device forms supported, such as tablets, smart TVs, and watches + +The following figure shows the continuation architecture. + + **Figure 1** Continuation architecture +hop-structure + +- Cross-device migration task management: The initiator accepts a migration request from the user, provides a migration entry, and displays the migration result. (This capability is unavailable yet.) + +- Multi-device collaboration task management: The initiator accepts an application registration request and provides management capabilities such as starting or stopping collaboration and status display. (This capability is unavailable yet.) + +- Distributed component management: provides capabilities such as remote service startup, remote service connection, and remote migration, and enables cross-device migration or multi-device collaboration of applications based on a combination of these capabilities. + +- Distributed security authentication: provides an E2E encrypted channel for cross-device transmission between applications to ensure that the right person uses the right data through the right device. + +- DSoftBus: functions as a unified communication base for a wide range of devices such as tablets, wearables, and smart TVs, and enables unified distributed communication between these devices. diff --git a/en/application-dev/application-models/itc-fa-overview.md b/en/application-dev/application-models/itc-fa-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..112a89edd8ba8236fca714a65d6f93287dcbe41d --- /dev/null +++ b/en/application-dev/application-models/itc-fa-overview.md @@ -0,0 +1,4 @@ +# Inter-Thread Communication (FA Model) + + +For details, see [Inter-Thread Communication](thread-model-stage.md) in the stage model. diff --git a/en/application-dev/application-models/itc-with-emitter.md b/en/application-dev/application-models/itc-with-emitter.md new file mode 100644 index 0000000000000000000000000000000000000000..2966bd8eea41e04893814f20a3c5b2f9e4e456c9 --- /dev/null +++ b/en/application-dev/application-models/itc-with-emitter.md @@ -0,0 +1,49 @@ +# Using Emitter for Inter-Thread Communication + +[Emitter](../reference/apis/js-apis-emitter.md) provides APIs for sending and processing events between threads, including the APIs for processing events that are subscribed to in persistent or one-shot manner, unsubscribing from events, and emitting events to the event queue. + + +To develop the Emitter mode, perform the following steps: + + +1. Subscribe to an event. + + ```ts + import emitter from "@ohos.events.emitter"; + + // Define an event with eventId 1. + let event = { + eventId: 1 + }; + + // Trigger the callback after the event with eventId 1 is received. + let callback = (eventData) => { + console.info('event callback'); + }; + + // Subscribe to the event with eventId 1. + emitter.on(event, callback); + ``` + +2. Emit the event. + + ```ts + import emitter from "@ohos.events.emitter"; + + // Define an event with eventId 1 and priority Low. + let event = { + eventId: 1, + priority: emitter.EventPriority.LOW + }; + + let eventData = { + data: { + "content": "c", + "id": 1, + "isEmpty": false, + } + }; + + // Emit the event with eventId 1 and event content eventData. + emitter.emit(event, eventData); + ``` diff --git a/en/application-dev/application-models/itc-with-worker.md b/en/application-dev/application-models/itc-with-worker.md new file mode 100644 index 0000000000000000000000000000000000000000..8cbe53eeea067ae1875a8ff4b73bc4cde7bdd629 --- /dev/null +++ b/en/application-dev/application-models/itc-with-worker.md @@ -0,0 +1,79 @@ +# Using Worker for Inter-Thread Communication + +[Worker](../reference/apis/js-apis-worker.md) is an independent thread running in parallel with the main thread. The thread that creates the worker thread is referred to as the host thread. The script file passed in during worker creation is executed in the worker thread. Generally, time-consuming operations are processed in the worker thread. However, pages cannot be directly updated in the worker thread. + + +To develop the Worker mode, perform the following steps: + + +1. Configure the **buildOption** field in the [module-level build-profile.json5](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-building-configuration-0000001218440654#section6887184182020) file of the project. + + ```ts + "buildOption": { + "sourceOption": { + "workers": [ + "./src/main/ets/workers/worker.ts" + ] + } + } + ``` + +2. Create the **worker.js** file based on the configuration in **build-profile.json5**. + + ```ts + import worker from '@ohos.worker'; + + let parent = worker.workerPort; + + // Process messages from the main thread. + parent.onmessage = function(message) { + console.info("onmessage: " + message) + // Send a message to the main thread. + parent.postMessage("message from worker thread.") + } + ``` + +3. In the main thread, use the following method to initialize and use the worker thread. + - Stage model: + + ```ts + import worker from '@ohos.worker'; + + let wk = new worker.ThreadWorker("entry/ets/workers/worker.ts"); + + // Send a message to the worker thread. + wk.postMessage("message from main thread.") + + // Process messages from the worker thread. + wk.onmessage = function(message) { + console.info("message from worker: " + message) + + // Stop the worker thread based on service requirements. + wk.terminate() + } + ``` + + - FA model: + + ```ts + import worker from '@ohos.worker'; + + let wk = new worker.ThreadWorker("../workers/worker.js"); + + // Send a message to the worker thread. + wk.postMessage("message from main thread.") + + // Process messages from the worker thread. + wk.onmessage = function(message) { + console.info("message from worker: " + message) + + // Stop the worker thread based on service requirements. + wk.terminate() + } + ``` + +> **NOTE** +> +> - If the relative path of **worker.ts** configured in **build-profile.json5** is **./src/main/ets/workers/worker.ts**, pass in the path **entry/ets/workers/worker.ts** when creating a worker thread in the stage model, and pass in the path **../workers/worker.js** when creating a worker thread in the FA model. +> +> - For details about the data types supported between the main thread and worker thread, see [Sequenceable Data Types](../reference/apis/js-apis-worker.md#sequenceable-data-types). diff --git a/en/application-dev/application-models/lifecycleapp-switch.md b/en/application-dev/application-models/lifecycleapp-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..892a8915bfed9927c2707364bdaffa1547f71bf6 --- /dev/null +++ b/en/application-dev/application-models/lifecycleapp-switch.md @@ -0,0 +1,21 @@ +# LifecycleApp Switching + + + | 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) | +| 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.| +| 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.| +| onInactive?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onBackground(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonbackground) | +| onActive?(): void; | \@ohos.app.ability.UIAbility.d.ts | [onForeground(): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonforeground) | +| onNewWant?(want: Want): void; | \@ohos.app.ability.UIAbility.d.ts | [onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) | +| onMemoryLevel?(level: number): void | \@ohos.app.ability.UIAbility.d.ts | [onMemoryLevel(level: AbilityConstant.MemoryLevel): void;](../reference/apis/js-apis-app-ability-ability.md#abilityonmemorylevel) | diff --git a/en/application-dev/application-models/lifecycledata-switch.md b/en/application-dev/application-models/lifecycledata-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..be96421a92161deeb26c9e99af9ec5de332d9e25 --- /dev/null +++ b/en/application-dev/application-models/lifecycledata-switch.md @@ -0,0 +1,18 @@ +# LifecycleData Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| update?(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [update?(uri: string, predicates: dataSharePredicates.DataSharePredicates, valueBucket: ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#update) | +| query?(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [query?(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: AsyncCallback<Object>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#query) | +| delete?(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [delete?(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#delete) | +| normalizeUri?(uri: string, callback: AsyncCallback<string>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [normalizeUri?(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#normalizeuri) | +| batchInsert?(uri: string, valueBuckets: Array<rdb.ValuesBucket>, callback: AsyncCallback<number>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [batchInsert?(uri: string, valueBuckets: Array<ValuesBucket>, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#batchinsert) | +| denormalizeUri?(uri: string, callback: AsyncCallback<string>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [denormalizeUri?(uri: string, callback: AsyncCallback<string>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#denormalizeuri) | +| insert?(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [insert?(uri: string, valueBucket: ValuesBucket, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#insert) | +| openFile?(uri: string, mode: string, callback: AsyncCallback<number>): void; | There is no corresponding API in the stage model.| The stage model does not support cross-process URI access. You are advised to use [the want parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| +| getFileTypes?(uri: string, mimeTypeFilter: string, callback: AsyncCallback<Array<string>>): void; | There is no corresponding API in the stage model.| The stage model does not support cross-process URI access. You are advised to use [the want parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| +| onInitialized?(info: AbilityInfo): void; | \@ohos.application.DataShareExtensionAbility.d.ts | [onCreate?(want: Want, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-application-dataShareExtensionAbility.md#oncreate) | +| getType?(uri: string, callback: AsyncCallback<string>): void; | There is no corresponding API in the stage model.| The stage model does not support cross-process URI access. You are advised to use [the want parameter to carry the file descriptor and file information](data-share-via-want.md) for cross-process file access.| +| executeBatch?(ops: Array<DataAbilityOperation>, callback: AsyncCallback<Array<DataAbilityResult>>): void; | There is no corresponding API in the stage model.| No corresponding API is provided.| +| call?(method: string, arg: string, extras: PacMap, callback: AsyncCallback<PacMap>): void; | There is no corresponding API in the stage model.| No corresponding API is provided.| diff --git a/en/application-dev/application-models/lifecycleform-switch.md b/en/application-dev/application-models/lifecycleform-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..80e577eeac759f589cb53c6b367ae17ba8b98e8c --- /dev/null +++ b/en/application-dev/application-models/lifecycleform-switch.md @@ -0,0 +1,13 @@ +# LifecycleForm Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| onCreate?(want: Want): formBindingData.FormBindingData; | \@ohos.app.form.FormExtensionAbility.d.ts | [onAddForm(want: Want): formBindingData.FormBindingData;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onaddform) | +| onCastToNormal?(formId: string): void; | \@ohos.app.form.FormExtensionAbility.d.ts | [onCastToNormalForm(formId: string): void;](../reference/apis/js-apis-app-form-formExtensionAbility.md#oncasttonormalform) | +| onUpdate?(formId: string): void; | \@ohos.app.form.FormExtensionAbility.d.ts | [onUpdateForm(formId: string): void;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onupdateform) | +| onVisibilityChange?(newStatus: { [key: string]: number }): void; | \@ohos.app.form.FormExtensionAbility.d.ts | [onChangeFormVisibility(newStatus: { [key: string]: number }): void;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onchangeformvisibility) | +| onEvent?(formId: string, message: string): void; | \@ohos.app.form.FormExtensionAbility.d.ts | [onFormEvent(formId: string, message: string): void;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onformevent) | +| onDestroy?(formId: string): void; | \@ohos.app.form.FormExtensionAbility.d.ts | [onRemoveForm(formId: string): void;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onremoveform) | +| onAcquireFormState?(want: Want): formInfo.FormState; | \@ohos.app.form.FormExtensionAbility.d.ts | [onAcquireFormState?(want: Want): formInfo.FormState;](../reference/apis/js-apis-app-form-formExtensionAbility.md#onacquireformstate) | +| onShare?(formId: string): {[key: string]: any}; | \@ohos.app.form.FormExtensionAbility.d.ts | [onShareForm?(formId: string): { [key: string]: any };](../reference/apis/js-apis-app-form-formExtensionAbility.md#onshareform) | diff --git a/en/application-dev/application-models/lifecycleservice-switch.md b/en/application-dev/application-models/lifecycleservice-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..d1fcdc7a30efb0114e092ac5a6233566270312fa --- /dev/null +++ b/en/application-dev/application-models/lifecycleservice-switch.md @@ -0,0 +1,11 @@ +# LifecycleService Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| onStart?(): void; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onCreate(want: Want): void;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityoncreate) | +| onCommand?(want: Want, startId: number): void; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onRequest(want: Want, startId: number): void;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonrequest) | | +| onStop?(): void; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onDestroy(): void;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityondestroy) | | +| onConnect?(want: Want): rpc.RemoteObject; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onConnect(want: Want): rpc.RemoteObject;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonconnect) | | +| onDisconnect?(want: Want): void; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onDisconnect(want: Want): void;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityondisconnect) | | +| onReconnect?(want: Want): void; | \@ohos.app.ability.ServiceExtensionAbility.d.ts | [onReconnect(want: Want): void;](../reference/apis/js-apis-app-ability-serviceExtensionAbility.md#serviceextensionabilityonreconnect) | | diff --git a/en/application-dev/application-models/medialibrary-switch.md b/en/application-dev/application-models/medialibrary-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..29e9b10964d2b9c967960f6c2ad802a942aa0ac3 --- /dev/null +++ b/en/application-dev/application-models/medialibrary-switch.md @@ -0,0 +1,6 @@ +# mediaLibrary Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [getMediaLibrary(): MediaLibrary;](../reference/apis/js-apis-medialibrary.md#medialibrarygetmedialibrary) | \@ohos.multimedia.mediaLibrary.d.ts | [getMediaLibrary(context: Context): MediaLibrary;](../reference/apis/js-apis-medialibrary.md#medialibrarygetmedialibrary8) | diff --git a/en/application-dev/application-models/mission-management-fa.md b/en/application-dev/application-models/mission-management-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..07641af7d736f298c99908805a5493cadadd4b00 --- /dev/null +++ b/en/application-dev/application-models/mission-management-fa.md @@ -0,0 +1,4 @@ +# Mission Management (FA Model) + + +For details, see [Mission Management](mission-management-overview.md) in the stage model. diff --git a/en/application-dev/application-models/mission-management-launch-type.md b/en/application-dev/application-models/mission-management-launch-type.md new file mode 100644 index 0000000000000000000000000000000000000000..72b6dbf80df2628119ebcc29339ed7e4b70e9a50 --- /dev/null +++ b/en/application-dev/application-models/mission-management-launch-type.md @@ -0,0 +1,33 @@ +# Mission Management and Launch Type + + +One UIAbility instance corresponds to one mission. The number of UIAbility instances is related to the UIAbility launch type, specified by **launchType**, which is configured in the **config.json** file in the FA model and the [module.json5](../quick-start/module-configuration-file.md) file in the stage model. + + +The following describes how the mission list manager manages the UIAbility instanced started in different modes. +- **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. + + **Figure 2** Missions and standard mode + ![mission-and-standard](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. + + **Figure 3** Missions and specified mode + ![mission-and-specified](figures/mission-and-specified.png) + + +Each UIAbility instance corresponds to a mission displayed in **Recents**. + + +Every mission retains a snapshot of the UIAbility instance. After the UIAbility instance is destroyed, the mission information (including the ability information and mission snapshot) is retained until the mission is deleted. + + +> **NOTE** +> +> The **specified** mode is supported in the stage model only. + diff --git a/en/application-dev/application-models/mission-management-overview.md b/en/application-dev/application-models/mission-management-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..b6f6668f7ce56a9de0b5a3d0182b14ec189703c9 --- /dev/null +++ b/en/application-dev/application-models/mission-management-overview.md @@ -0,0 +1,129 @@ +# Mission Management Scenarios + + +Before getting started with the development of mission management, be familiar with the following concepts related to mission management: + + +- AbilityRecord: minimum unit for the system service to manage a UIAbility instance. It corresponds to a UIAbility component instance of an application. + +- MissionRecord: minimum unit for mission management. One MissionRecord has only one AbilityRecord. In other words, a UIAbility component instance corresponds to a mission. + +- MissionList: a list of missions started from the home screen. It records the startup relationship between missions. In a MissionList, an above mission is started by the mission under it, and the mission at the bottom is started by the home screen. + +- 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) + + +Missions are managed by system applications (such as home screen), rather than third-party applications. Users interact with missions through **Recents**. After creating a mission, users can perform the following operations on **Recents**: + + +- Delete a mission. + +- Lock or unlock a mission. (Locked missions are not cleared when users attempt to clear all missions in **Recents**.) + +- Clear all missions in **Recents**. + +- Switch a mission to the foreground. + + +A UIAbility instance corresponds to an independent mission. Therefore, when an application calls the **startAbility()** method to start a UIAbility, a mission is created. + + +To call [missionManager](../reference/apis/js-apis-application-missionManager.md) to manage missions, the home screen application must request the **ohos.permission.MANAGE_MISSIONS** permission. For details about the configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + + +You can use **missionManager** to manage missions, for example, listening for mission changes, obtaining mission information or snapshots, and clearing, locking, or unlocking missions. The sample code is as follows: + +```ts +import missionManager from '@ohos.app.ability.missionManager' + +let listener = { + // Listen for mission creation. + onMissionCreated: function (mission) { + console.info("--------onMissionCreated-------") + }, + // Listen for mission destruction. + onMissionDestroyed: function (mission) { + console.info("--------onMissionDestroyed-------") + }, + // Listen for mission snapshot changes. + onMissionSnapshotChanged: function (mission) { + console.info("--------onMissionSnapshotChanged-------") + }, + // Listen for switching the mission to the foreground. + onMissionMovedToFront: function (mission) { + console.info("--------onMissionMovedToFront-------") + }, + // Listen for mission icon changes. + onMissionIconUpdated: function (mission, icon) { + console.info("--------onMissionIconUpdated-------") + }, + // Listen for mission name changes. + onMissionLabelUpdated: function (mission) { + console.info("--------onMissionLabelUpdated-------") + }, + // Listen for mission closure events. + onMissionClosed: function (mission) { + console.info("--------onMissionClosed-------") + } +}; + +// 1. Register a mission change listener. +let listenerId = missionManager.on('mission', listener); + +// 2. Obtain the latest 20 missions in the system. +missionManager.getMissionInfos("", 20, (error, missions) => { + console.info("getMissionInfos is called, error.code = " + error.code); + console.info("size = " + missions.length); + console.info("missions = " + JSON.stringify(missions)); +}); + +// 3. Obtain the detailed information about a mission. +let missionId = 11; // The mission ID 11 is only an example. +let mission = missionManager.getMissionInfo("", missionId).catch(function (err) { + console.info(err); +}); + +// 4. Obtain the mission snapshot. +missionManager.getMissionSnapShot("", missionId, (error, snapshot) => { + console.info("getMissionSnapShot is called, error.code = " + error.code); + console.info("bundleName = " + snapshot.ability.bundleName); +}) + +// 5. Obtain the low-resolution mission snapshot. +missionManager.getLowResolutionMissionSnapShot("", missionId, (error, snapshot) => { + console.info("getLowResolutionMissionSnapShot is called, error.code = " + error.code); + console.info("bundleName = " + snapshot.ability.bundleName); +}) + +// 6. Lock or unlock the mission. +missionManager.lockMission(missionId).then(() => { + console.info("lockMission is called "); +}); + +missionManager.unlockMission(missionId).then(() => { + console.info("unlockMission is called "); +}); + +// 7. Switch the mission to the foreground. +missionManager.moveMissionToFront(missionId).then(() => { + console.info("moveMissionToFront is called "); +}); + +// 8. Clear a single mission. +missionManager.clearMission(missionId).then(() => { + console.info("clearMission is called "); +}); + +// 9. Clear all missions. +missionManager.clearAllMissions().catch(function (err) { + console.info(err); +}); + +// 10. Deregister the mission change listener. +missionManager.off('mission', listenerId, (error) => { + console.info("unregisterMissionListener"); +}) +``` diff --git a/en/application-dev/application-models/model-switch-overview.md b/en/application-dev/application-models/model-switch-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..e42882ca59b33c65fe6591510954d95e2c49453b --- /dev/null +++ b/en/application-dev/application-models/model-switch-overview.md @@ -0,0 +1,23 @@ +# Model Switching Overview + + +Perform the following operations to switch a declarative paradigm-based application developed based on the FA model to the stage model. + + +- Project switch: Create an application project of the stage model. + ![model-switch-overview1](figures/model-switch-overview1.png) + +- [Configuration file switch](configuration-file-diff.md): Switch **config.json** to **app.json5** and **module.json5**. + ![model-switch-overview2](figures/model-switch-overview2.png) + +- [Component switch](pageability-switch.md): Switch the PageAbility, ServiceAbility, and DataAbility components of the FA model to the UIAbility and ExtensionAbility components of the stage model. The figure below shows only the switching from PageAbility to UIAbility. The left part is the FA model, and **app.ets** is the PageAbility component. The right part is the stage model, and **EntryAbility.ts** is the UIAbility component. + +![model-switch-overview3](figures/model-switch-overview3.png) + +- [Widget switch](widget-switch.md): Switch the FormAbility component of the FA model to the FormExtensionAbility component of the stage model. In the figure below, **Service Widget** is FormAbility in the FA model and FormExtensionAbility in the stage model. + ![model-switch-overview4](figures/model-switch-overview4.png) + + ![model-switch-overview5](figures/model-switch-overview5.png) + +- [API switch](api-switch-overview.md): Switch the APIs with the **FAModelOnly** tag used in the FA model to the recommended APIs in the stage model. + ![model-switch-overview6](figures/model-switch-overview6.png) diff --git a/en/application-dev/application-models/module-switch.md b/en/application-dev/application-models/module-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..a6e532e94827198880cb772c174725b2a89c469b --- /dev/null +++ b/en/application-dev/application-models/module-switch.md @@ -0,0 +1,75 @@ +# Switching of module + + +When switching an application from the FA model to the stage model, you must migrate the configurations under the **module** tag in the **config.json** file to the **module** tag in the **module.json5** file. + +### **Table 1** module comparison + +| 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.| +| 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.| +| moduleType in the distro object| Type of the HAP file. The value can be **entry** or **feature**. For the HAR type, set this field to **har**.| type | The field name is changed.| +| installationFree in the distro object| Whether the HAP file supports the installation-free feature.| installationFree | The field name is changed.| +| deliveryWithInstall in the distro object| Whether the HAP file is installed with the application.| deliveryWithInstall | The field name is changed.| +| metaData | Metadata of the HAP file.| metadata | See [Table 2](#table-2-metadata-comparison).| +| abilities | All abilities in the current module.| abilities | See [Table 5](#table-5-abilities-comparison).| +| js | A set of JS modules developed using ArkUI. Each element in the set represents the information about a JS module.| pages | The stage model retains **pages** under the **module** tag. The window configuration is the lower level of **pages**.| +| 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.| +| 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| +| -------- | -------- | -------- | -------- | +| parameters | Metadata of the parameters to be passed for calling the ability.| / | This configuration is not supported in the stage model.| +| results | Metadata of the ability return value.| / | This configuration is not supported in the stage model.| +| customizeData | Custom metadata of the parent component. **parameters** and **results** cannot be configured in **application**.| metadata | See [Table 3](#table-3-comparison-between-customizedata-under-metadata-in-the-fa-model-and-metadata-in-the-stage-model).| + +### Table 3 Comparison between customizeData under metaData in the FA model and metadata in the stage model + +| Field Name Under customizeData in metaData in the FA Model| Field Description| Field Name Under metaData in the Stage Model| Difference| +| -------- | -------- | -------- | -------- | +| 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).| + + +### Table 4 metaData examples + +| Example in the FA Model| Example in the Stage Model| +| -------- | -------- | +| "meteData": {
"customizeDate": [{
"name": "label",
"value": "string",
"extra": "$string:label",
}]
} | "meteData": [{
"name": "label",
"value": "string",
"resource": "$string:label",
}] | + + +### Table 5 abilities comparison + +| Field Name Under abilities in the FA Model| Field Description| Field Name Under abilities in the Stage Model| Difference| +| -------- | -------- | -------- | -------- | +| process | Name of the process running the application or ability.| / | The stage model does not support configuration of **process** under **abilities**. The configuration of **process** is available under the **module** tag.| +| uri | URI of the ability.| / | This configuration is not supported in the stage model.| +| deviceCapability | Device capabilities required to run the ability.| / | This configuration is not supported in the stage model.| +| metaData | Metadata of the ability.| metadata | See [Table 2](#table-2-metadata-comparison).| +| type | Ability type.| / | This configuration is not supported in the stage model.| +| grantPermission | Whether permissions can be granted for any data in the ability.| / | The stage model does not support such a configuration under **abilities**.| +| readPermission | Permission required for reading data in the ability. This field applies only to the ability using the Data template.| / | In the stage model, this configuration is available under **extensionAbilities**, but not **abilities**.| +| writePermission | Permission required for writing data to the ability.| / | In the stage model, this configuration is available under **extensionAbilities**, but not **abilities**.| +| configChanges | System configurations that the ability concerns.| / | This configuration is not supported in the stage model.| +| mission | Mission stack of the ability.| / | This configuration is not supported in the stage model.| +| targetAbility | Target ability that this ability alias points to.| / | This configuration is not supported in the stage model.| +| multiUserShared | Whether the ability supports data sharing among multiple users. This field applies only to the ability using the Data template.| / | This configuration is not supported in the stage model.| +| supportPipMode | Whether the ability allows the user to enter the Picture in Picture (PiP) mode. The PiP mode enables the user to watch a video in a small window that hovers on top of a full screen window (main window).| / | This configuration is not supported in the stage model.| +| 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.| +| 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/page-mission-stack.md b/en/application-dev/application-models/page-mission-stack.md new file mode 100644 index 0000000000000000000000000000000000000000..702cb9ba928d5266ce6720d10538df6109b0cbeb --- /dev/null +++ b/en/application-dev/application-models/page-mission-stack.md @@ -0,0 +1,51 @@ +# Page Stack and MissionList + + +## Page Stack + +A single UIAbility component can implement multiple pages and redirection between these pages. The redirection relationship inside the UIAbility component is called page stack, which is managed by the ArkUI framework. For example, Page1 -> Page2 -> Page3 of UIAbility1 and PageA -> PageB -> PageC of UIAbility2 in the figure below are two page stacks. + + **Figure 1** Page stack +![mission-record](figures/mission-record.png) + +- A page stack is formed as follows (Steps 2, 3, 5, and 6 are page redirection and managed by ArkUI): + 1. Touch the icon on the home screen. The [startAbility](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartability) method is called to start UIAbility1, whose initial page is Page1. + + 2. Touch a button on Page1. The [Navigator](../reference/arkui-ts/ts-container-navigator.md) method is called to redirect you to Page2. + + 3. Touch a button on Page2. The [Navigator](../reference/arkui-ts/ts-container-navigator.md) method is called to redirect you to Page3. + + 4. Touch a button on Page3. The [startAbility](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartability) method is called to start UIAbility2, whose initial page is PageA. + + 5. Touch a button on PageA. The [Navigator](../reference/arkui-ts/ts-container-navigator.md) method is called to redirect you to PageB. + + 6. Touch a button on PageB. The [Navigator](../reference/arkui-ts/ts-container-navigator.md) method is called to redirect you to PageC. + +- The page stack return is as follows (Steps 1, 2, 4, and 5 are page redirection and managed by ArkUI): + 1. Touch the **Back** button on PageC of UIAbility2 to return to PageB. + + 2. Touch the **Back** button on PageB of UIAbility2 to return to PageA. + + 3. Touch the **Back** button on PageA of UIAbility2 to return to Page3 of UIAbility1. + + 4. Touch the **Back** button on Page3 of UIAbility1 to return to Page2. + + 5. Touch the **Back** button on Page2 of UIAbility1 to return to Page1 of UIAbility1. + + 6. Touch the **Back** button on Page1 of UIAbility1 to return to the home screen. + + +## MissionList + +As described above, you can keep touching the **Back** button on the page of Ability2 to return to a page of Ability1. The MissionList records the startup relationship between missions. If Ability1 starts Ability2 through **startAbility()**, a MissionList is formed: Ability1 -> Ability2. Therefore, when you touch the **Back** button on the initial page of Ability2, a page of Ability1 is displayed. + +The mission startup relationship recorded by the MissionList may be broken in the following cases: + +- A user moves a mission in the middle of the MissionList to the foreground. + ![mission-chain1](figures/mission-chain1.png) + +- A user deletes a mission in the MissionList. + ![mission-chain2](figures/mission-chain2.png) + +- A UIAbility singleton is repeatedly started by different missions. For example, AbilityB in the figure below is a singleton. + ![mission-chain3](figures/mission-chain3.png) diff --git a/en/application-dev/application-models/pageability-configuration.md b/en/application-dev/application-models/pageability-configuration.md new file mode 100644 index 0000000000000000000000000000000000000000..c11e7b17554844d21e024228bbec51e621d6383d --- /dev/null +++ b/en/application-dev/application-models/pageability-configuration.md @@ -0,0 +1,12 @@ +# PageAbility Component Configuration + + +The PageAbility is configured in **abilities** under **module** in the **config.json** file. The **icon** field indicates the index of the ability icon resource file, and the **label** field indicates the ability name presented to users, and the **skills** field indicates the type of Want that is acceptable to the ability. + +**Table 1** PageAbility configuration items + +| Name| Description| Data Type| Initial Value Allowed| +| -------- | -------- | -------- | -------- | +| icon | Index to the ability icon file. Example value: **$media:ability_icon**. In the **skills** attribute of the ability, if the **actions** value contains **action.system.home** and the **entities** value contains **entity.system.home**, the icon of the ability is also used as the icon of the application. If multiple abilities address this condition, the icon of the first candidate ability is used as the application icon.
Note: The **icon** and **label** values of an application are visible to users. Ensure that at least one of them is different from any existing icons or labels.| String| Yes (initial value: left empty)| +| label | Ability name visible to users. The value can be a name string or a resource index to names in multiple languages. In the **skills** attribute of the ability, if the **actions** value contains **action.system.home** and the **entities** value contains **entity.system.home**, the label of the ability is also used as the label of the application. If multiple abilities address this condition, the label of the first candidate ability is used as the application label.
Note: The **icon** and **label** values of an application are visible to users. Ensure that at least one of them is different from any existing icons or labels. The value can be a reference to a string defined in a resource file or a string enclosed in brackets ({}). The value can contain a maximum of 255 characters.| String| Yes (initial value: left empty)| +| skills | Types of the Want that can be accepted by the ability.| Object array| Yes (initial value: left empty)| diff --git a/en/application-dev/application-models/pageability-launch-type.md b/en/application-dev/application-models/pageability-launch-type.md new file mode 100644 index 0000000000000000000000000000000000000000..5241a7cabefbf3e68e6a3f413b8892ef5f6ff8d3 --- /dev/null +++ b/en/application-dev/application-models/pageability-launch-type.md @@ -0,0 +1,39 @@ +# PageAbility Launch Type + + +Depending on the launch type, the action performed when the PageAbility starts differs, as described in the table below. + +**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**.| + + +You can set **launchType** in the **config.json** file to configure the launch type. The sample code is as follows: + +```json +{ + "module": { + // ... + "abilities": [ + { + // singleton mode. + // standard mode. + "launchType": "standard", + // ... + } + ] + } +} +``` + + +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. + +**Table 2** Callbacks specific to the singleton mode + +| API| Description| +| -------- | -------- | +| onNewWant(want: Want) | **onNewWant()** is triggered when the PageAbility is not started for the first time in singleton mode. You can obtain Want from this callback and perform further processing based on Want. For example, in the singleton PageAbility migration scenario, you can specify a page to start the PageAbility.| diff --git a/en/application-dev/application-models/pageability-lifecycle.md b/en/application-dev/application-models/pageability-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..3608346ec5403735a79fdf9a01478be9b86745d9 --- /dev/null +++ b/en/application-dev/application-models/pageability-lifecycle.md @@ -0,0 +1,45 @@ +# PageAbility Lifecycle + + +The PageAbility lifecycle defines all states of a PageAbility, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**. The figure below shows the lifecycle state transition. + +**Figure 1** PageAbility lifecycle + +![page-ability-lifecycle](figures/page-ability-lifecycle.png) + +**Table 1** PageAbility lifecycle states + +| State| Description| +| -------- | -------- | +| UNINITIALIZED | The PageAbility is not initialized. This is a temporary state, from which a PageAbility changes directly to the **INITIAL** state upon its creation.| +| INITIAL | The PageAbility is initialized but not running. The PageAbility enters the **INACTIVE** state after it is started.| +| INACTIVE | The PageAbility is visible but does not gain focus.| +| ACTIVE | The PageAbility runs in the foreground and has focus.| +| BACKGROUND | The PageAbility runs in the background. After being re-activated, the PageAbility enters the **ACTIVE** state. After being destroyed, it enters the **INITIAL** state.| + + +You can override the lifecycle callbacks (as described in the table below) in **app.js** or **app.ets**. + +**Table 2** PageAbility lifecycle callbacks + +| API| Description| +| -------- | -------- | +| onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.| +| onDestroy() | Called when the ability is destroyed. In this callback, you can make preparations for application exit, such as recycling resources and clearing the cache.| +| onActive() | Called when the ability is switched to the foreground and gains focus.| +| onInactive() | Called when the ability loses focus. An ability loses focus when it is about to enter the background state.| +| onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.| +| onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible to users.| + + +The following figure shows the relationship between lifecycle callbacks and lifecycle states of the PageAbility. + +Figure 2 Relationship between lifecycle callbacks and lifecycle states + +![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) + + +> **NOTE** +> +> - The PageAbility lifecycle callbacks are synchronous. +> - The **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. diff --git a/en/application-dev/application-models/pageability-overview.md b/en/application-dev/application-models/pageability-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..00370ca29056fcb8d23e93de54a38b2003bc6941 --- /dev/null +++ b/en/application-dev/application-models/pageability-overview.md @@ -0,0 +1,7 @@ +# PageAbility Component Overview + + +PageAbility is an application component that has the UI and supports user interaction. + + +When you create a PageAbility in DevEco Studio, DevEco Studio automatically creates template code. The capabilities related to the PageAbility are implemented through the **featureAbility** class, and the lifecycle callbacks are implemented through the callbacks in **app.js** or **app.ets**. diff --git a/en/application-dev/application-models/pageability-switch.md b/en/application-dev/application-models/pageability-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..1953c02c8067a38d1633ae9eb9f768dc60a87e0f --- /dev/null +++ b/en/application-dev/application-models/pageability-switch.md @@ -0,0 +1,56 @@ +# PageAbility Switching + + +The PageAbility component in the FA model corresponds to the UIAbility component in the stage model. To switch a PageAbility to a UIAbility, perform the following operations: + + +1. [Create a UIAbility](uiability-usage.md) in the stage model. + +2. Migrate the PageAbility code to the UIAbility. + +The PageAbility lifecycle is basically the same as the UIAbility lifecycle. The table below describes the details. + + | PageAbility| UIAbility| Mapping Description| + | -------- | -------- | -------- | + | onCreate(): void| onCreate(want: Want, param: AbilityConstant.LaunchParam): void | The two methods have the same meaning and invoking time. In the stage model, parameters are added to the callback so that you can obtain startup-related data during creation.| + | NA | onWindowStageCreate(windowStage: window.WindowStage): void| This method is available only in the stage model. The callback is invoked when a window is created.| + | onActive(): void | on(eventType: 'windowStageEvent', callback: Callback<WindowStageEventType>): void;
WindowStageEventType.ACTIVE | The two methods have the same meaning and invoking time. In the stage model, this method is moved to the window object.| + | onShow(): void | onForeground(): void | The two methods have the same meaning, invoking time, and parameters.| + | onNewWant(want: Want): void| onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void| The two methods have the same meaning and invoking time. In the stage model, the **LaunchParam** parameter is added to notify the application of the startup cause.| + | onInactive(): void| on(eventType: 'windowStageEvent', callback: Callback<WindowStageEventType>): void;
WindowStageEventType.INACTIVE | The two methods have the same meaning and invoking time. In the stage model, this method is moved to the window object.| + | onHide(): void | onBackground(): void | The two methods have the same meaning, invoking time, and parameters.| + | NA | onWindowStageDestroy(): void | This method is available only in the stage model. The callback is invoked when a window is destroyed.| +| onDestroy(): void | onDestroy(): void | The two methods have the same meaning, invoking time, and parameters.| + +![pageability-switch](figures/pageability-switch.png) + +3. Adjust the migrated code, since the methods of loading pages are different. + + - In the FA model, you can configure the page to be loaded by setting page information in **config.json**. + - In the stage model, you must call **windowStage.loadContent** in the **onWindowStageCreate** callback to load a page. + + For example, to load the **pages/Index** page after the ability is started, use the following code in the **config.json** file in the FA model: + + + ```json + "pages" : [ + "pages/Index" + ] + ``` + + In the stage model, implement the following method in **MainAbility**: + + + ```ts + import Window from '@ohos.window' + + onWindowStageCreate(windowStage: Window.WindowStage) { + // Main window is created. Set a main page for this ability. + windowStage.loadContent('pages/Index', (err, data) => { + if (err.code) { + console.error("loadContent failed") + return; + } + }); + } + ``` diff --git a/en/application-dev/application-models/particleability-switch.md b/en/application-dev/application-models/particleability-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..21ecd96c9a24f1328c20da14abf5cc8f8d079b95 --- /dev/null +++ b/en/application-dev/application-models/particleability-switch.md @@ -0,0 +1,12 @@ +# particleAbility Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [startAbility(parameter: StartAbilityParameter, callback: AsyncCallback<number>): void;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitystartability)
[startAbility(parameter: StartAbilityParameter): Promise<number>;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitystartability-1) | application\ServiceExtensionContext.d.ts | [startAbility(want: Want, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartability)
[startAbility(want: Want, options: StartOptions, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartability-2)
[startAbility(want: Want, options?: StartOptions): Promise<void>;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartability-1)
[startServiceExtensionAbility(want: Want, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartserviceextensionability)
[startServiceExtensionAbility(want: Want): Promise<void>;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartserviceextensionability-1) | +| [terminateSelf(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-ability-particleAbility.md#particleabilityterminateself)
[terminateSelf(): Promise<void>;](../reference/apis/js-apis-ability-particleAbility.md#particleabilityterminateself-1) | application\ServiceExtensionContext.d.ts | [terminateSelf(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself)
[terminateSelf(): Promise<void>;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextterminateself-1) | +| [connectAbility(request: Want, options:ConnectOptions ): number;](../reference/apis/js-apis-ability-particleAbility.md#particleabilityconnectability) | application\ServiceExtensionContext.d.ts | [connectAbility(want: Want, options: ConnectOptions): number;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextconnectserviceextensionability)
[connectServiceExtensionAbility(want: Want, options: ConnectOptions): number;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextconnectserviceextensionability) | +| [disconnectAbility(connection: number, callback:AsyncCallback<void>): void;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitydisconnectability)
[disconnectAbility(connection: number): Promise<void>;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitydisconnectability-1) | application\ServiceExtensionContext.d.ts | [disconnectAbility(connection: number, callback:AsyncCallback<void>): void; ](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextdisconnectserviceextensionability)
[disconnectAbility(connection: number): Promise<void>;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextdisconnectserviceextensionability-1)
[disconnectServiceExtensionAbility(connection: number, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextdisconnectserviceextensionability)
[disconnectServiceExtensionAbility(connection: number): Promise<void>;](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextdisconnectserviceextensionability-1) | +| [acquireDataAbilityHelper(uri: string): DataAbilityHelper;](../reference/apis/js-apis-ability-particleAbility.md#particleabilityacquiredataabilityhelper) | \@ohos.data.dataShare.d.ts
[\@ohos.data.fileAccess.d.ts | [createDataShareHelper(context: Context, uri: string, callback: AsyncCallback<DataShareHelper>): void;](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper)
[createDataShareHelper(context: Context, uri: string): Promise<DataShareHelper>;](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper-1)
[createFileAccessHelper(context: Context): FileAccessHelper;](../reference/apis/js-apis-fileAccess.md#fileaccesscreatefileaccesshelper-1)
[createFileAccessHelper(context: Context, wants: Array<Want>): FileAccessHelper;](../reference/apis/js-apis-fileAccess.md#fileaccesscreatefileaccesshelper) | +| [startBackgroundRunning(id: number, request: NotificationRequest, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitystartbackgroundrunning)
[startBackgroundRunning(id: number, request: NotificationRequest): Promise<void>;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitystartbackgroundrunning-1) | \@ohos.resourceschedule.backgroundTaskManager.d.ts | [startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: WantAgent, callback: AsyncCallback): void;](../reference/apis/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstartbackgroundrunningcallback)
[startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: WantAgent): Promise<void>;](../reference/apis/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstartbackgroundrunningpromise) | +| [cancelBackgroundRunning(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitycancelbackgroundrunning)
[cancelBackgroundRunning(): Promise<void>;](../reference/apis/js-apis-ability-particleAbility.md#particleabilitycancelbackgroundrunning-1) | \@ohos.resourceschedule.backgroundTaskManager.d.ts | [stopBackgroundRunning(context: Context, callback: AsyncCallback): void;](../reference/apis/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstopbackgroundrunningcallback)
[stopBackgroundRunning(context: Context): Promise<void>;](../reference/apis/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstopbackgroundrunningpromise) | diff --git a/en/application-dev/application-models/process-model-fa.md b/en/application-dev/application-models/process-model-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..699643031121521fbf95d26a949df906fa175a18 --- /dev/null +++ b/en/application-dev/application-models/process-model-fa.md @@ -0,0 +1,22 @@ +# Process Model (FA Model) + + +The OpenHarmony process model is shown below. + + +- All PageAbility, ServiceAbility, DataAbility, and FormAbility components of an application (with the same bundle name) run in an independent process, which is **Main process** in green in the figure. + +- WebView has an independent rendering process, which is **Render process** in yellow in the figure. + + **Figure 1** Process model + + ![process-model-fa](figures/process-model-fa.png) + + +OpenHarmony provides two inter-process communication (IPC) mechanisms. + + +- [Common Events](common-event-fa.md): This mechanism is used in one-to-many communication scenarios. Multiple subscribers may receive events at the same time. + +- [Background Services](rpc.md): This mechanism is implemented through [ServiceAbility](serviceability-overview.md). + diff --git a/en/application-dev/application-models/process-model-stage.md b/en/application-dev/application-models/process-model-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..bbfa0602aecb127c5e484f0ebbdcb166f81310f7 --- /dev/null +++ b/en/application-dev/application-models/process-model-stage.md @@ -0,0 +1,31 @@ +# Process Model (Stage Model) + + +The OpenHarmony process model is shown below. + + +- All UIAbility, ServiceExtensionAbility, and DataShareExtensionAbility components of an application (with the same bundle name) run in an independent process, which is **Main process** in green in the figure. + +- The ExtensionAbility components of the same type (except ServiceExtensionAbility and DataShareExtensionAbility) of an application (with the same bundle name) run in an independent process, which is **FormExtensionAbility process**, **InputMethodExtensionAbility process**, and other **ExtensionAbility process** in blue in the figure. + +- WebView has an independent rendering process, which is **Render process** in yellow in the figure. + + **Figure 1** Process model +![process-model](figures/process-model.png) + +> NOTE +> +> You can create ServiceExtensionAbility and DataShareExtensionAbility only for system applications. + +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. + +**Figure 2** Multi-process +![multi-process](figures/multi-process.png) + + +OpenHarmony provides two inter-process communication (IPC) mechanisms. + + +- [Common Events](common-event-overview.md): This mechanism is used in one-to-many communication scenarios. Multiple subscribers may receive events at the same time. + +- [Background Services](background-services.md): This mechanism is implemented through [ServiceExtensionAbility](serviceextensionability.md). diff --git a/en/application-dev/application-models/public_sys-resources/icon-caution.gif b/en/application-dev/application-models/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-caution.gif differ diff --git a/en/application-dev/application-models/public_sys-resources/icon-danger.gif b/en/application-dev/application-models/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-danger.gif differ diff --git a/en/application-dev/application-models/public_sys-resources/icon-note.gif b/en/application-dev/application-models/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-note.gif differ diff --git a/en/application-dev/application-models/public_sys-resources/icon-notice.gif b/en/application-dev/application-models/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-notice.gif differ diff --git a/en/application-dev/application-models/public_sys-resources/icon-tip.gif b/en/application-dev/application-models/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-tip.gif differ diff --git a/en/application-dev/application-models/public_sys-resources/icon-warning.gif b/en/application-dev/application-models/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/en/application-dev/application-models/public_sys-resources/icon-warning.gif differ diff --git a/en/application-dev/application-models/redirection-rules.md b/en/application-dev/application-models/redirection-rules.md new file mode 100644 index 0000000000000000000000000000000000000000..d7456653640942bca333a28f7f6d5262ec4d63f3 --- /dev/null +++ b/en/application-dev/application-models/redirection-rules.md @@ -0,0 +1,36 @@ +# Redirection Rules + + +Generally, UI redirection within an application is triggered by users. However, an application can call **startAbility()** to implement UI redirection. + + +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. + +**Table 1** Description of visible + +| 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**)| + + +To enable an ability to be called by any application, configure the **config.json** file as follows: + +```ts +{ + "module": { + // ... + "abilities": [ + { + "visible": "true", + // ... + } + ] + } +} +``` + + +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. diff --git a/en/application-dev/application-models/request-permissions.md b/en/application-dev/application-models/request-permissions.md new file mode 100644 index 0000000000000000000000000000000000000000..670860d87dbb56adceb02f4ca350c24b61260d30 --- /dev/null +++ b/en/application-dev/application-models/request-permissions.md @@ -0,0 +1,45 @@ +# Requesting Permissions + + +If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from users. + + +During application development, you must declare the required permission in the **config.json** file and call **requestPermissionsFromUser** to request the permission from users in the form of a dialog box. + + +To declare a permission in **config.json**, add **reqPermissions** under **module** and list the permission. + + +For example, to declare the permission to access the calendar, request the **ohos.permission.READ_CALENDAR** permission. For details, see [Permission Application Guide](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). + + +The sample code in the **config.json** file is as follows: + +```json +{ + "module": { + // ... + "reqPermissions": [ + { + "name": "ohos.permission.READ_CALENDAR" + // ... + } + ] + } +} +``` + + +Request the permission from uses in the form of a dialog box: + +```ts +import featureAbility from '@ohos.ability.featureAbility'; + +let context = featureAbility.getContext(); +let permissions: Array = ['ohos.permission.READ_CALENDAR'] +context.requestPermissionsFromUser(permissions, 1).then((data) => { + console.info("Succeed to request permission from user with data: " + JSON.stringify(data)) +}).catch((error) => { + console.info("Failed to request permission from user with error: " + JSON.stringify(error)) +}) +``` diff --git a/en/application-dev/application-models/request-switch.md b/en/application-dev/application-models/request-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..5c9e2f49d48aaba203a6207de37992823ab5ae97 --- /dev/null +++ b/en/application-dev/application-models/request-switch.md @@ -0,0 +1,7 @@ +# request Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [download(config: DownloadConfig, callback: AsyncCallback<DownloadTask>): void;](../reference/apis//js-apis-request.md#requestdownload-1)
[download(config: DownloadConfig): Promise<DownloadTask>;](../reference/apis/js-apis-request.md#requestdownload) | \@ohos.request.d.ts | [downloadFile(context: BaseContext, config: DownloadConfig, callback: AsyncCallback<DownloadTask>): void;](../reference/apis/js-apis-request.md#requestdownloadfile9-1)
[downloadFile(context: BaseContext, config: DownloadConfig): Promise<DownloadTask>;](../reference/apis/js-apis-request.md#requestdownloadfile9) | +| [upload(config: UploadConfig, callback: AsyncCallback<UploadTask>): void;](../reference/apis/js-apis-request.md#requestupload-1)
[upload(config: UploadConfig): Promise<UploadTask>;](../reference/apis/js-apis-request.md#requestupload) | \@ohos.request.d.ts | [uploadFile(context: BaseContext, config: UploadConfig, callback: AsyncCallback<UploadTask>): void;](../reference/apis/js-apis-request.md#requestuploadfile9-1)
[uploadFile(context: BaseContext, config: UploadConfig): Promise<UploadTask>;](../reference/apis/js-apis-request.md#requestuploadfile9) | diff --git a/en/application-dev/application-models/resourcemanager-switch.md b/en/application-dev/application-models/resourcemanager-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..34eedb16597e30c76ccaed2c01a3b4c7206c0dfd --- /dev/null +++ b/en/application-dev/application-models/resourcemanager-switch.md @@ -0,0 +1,6 @@ +# resourceManager Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding Field in the Stage Model| +| -------- | -------- | -------- | +| [getResourceManager(callback: AsyncCallback<ResourceManager>): void;](../reference/apis/js-apis-resource-manager.md#resourcemanagergetresourcemanager)
[getResourceManager(bundleName: string, callback: AsyncCallback<ResourceManager>): void;](../reference/apis/js-apis-resource-manager.md#resourcemanagergetresourcemanager-1)
[getResourceManager(): Promise<ResourceManager>;](../reference/apis/js-apis-resource-manager.md#resourcemanagergetresourcemanager-2)
[getResourceManager(bundleName: string): Promise<ResourceManager>;](../reference/apis/js-apis-resource-manager.md#resourcemanagergetresourcemanager-3) | application\Context.d.ts | [resourceManager: resmgr.ResourceManager;](../reference/apis/js-apis-inner-application-context.md#attributes)| diff --git a/en/application-dev/application-models/rpc.md b/en/application-dev/application-models/rpc.md new file mode 100644 index 0000000000000000000000000000000000000000..69fd10c315c9f3ec007358dad86fef71c4363d53 --- /dev/null +++ b/en/application-dev/application-models/rpc.md @@ -0,0 +1,4 @@ +# Background Services (FA Model) + + +For details, see [Background Services](background-services.md) in the stage model. diff --git a/en/application-dev/application-models/serviceability-configuration.md b/en/application-dev/application-models/serviceability-configuration.md new file mode 100644 index 0000000000000000000000000000000000000000..2c8e009a10937140e013d030cf21a1167b1fd3e8 --- /dev/null +++ b/en/application-dev/application-models/serviceability-configuration.md @@ -0,0 +1,16 @@ +# ServiceAbility Component Configuration + + +Similar to a PageAbility, a ServiceAbility is configured in **abilities** under **module** of the **config.json** file. The difference between a ServiceAbility and PageAbility lies in the **type** and **backgroundModes** fields. + + + **Table 1** ServiceAbility configuration items + +| Name| Description| Data Type| Initial Value Allowed| +| -------- | -------- | -------- | -------- | +| type | Type of the ability. The value **service** indicates that the ability is developed based on the Service template.| String| No| +| backgroundModes | Background service type of the ability. You can assign multiple background service types to a specific ability. This field applies only to the ability using the Service template. The value can be:
**dataTransfer**: service for downloading, backing up, sharing, or transferring data from the network or peer devices.
**audioPlayback**: audio playback service.
**audioRecording**: audio recording service.
**pictureInPicture**: picture in picture (PiP) and small-window video playback services.
**voip**: voice/video call and VoIP services.
**location**: location and navigation services.
**bluetoothInteraction**: Bluetooth scanning, connection, and transmission services.
**wifiInteraction**: WLAN scanning, connection, and transmission services.
**screenFetch**: screen recording and screenshot services.
**multiDeviceConnection**: multi-device interconnection service.| String array| Yes (initial value: left empty)| + + +For details about the configuration items, see [Internal Structure of module](../quick-start/module-structure.md). + diff --git a/en/application-dev/application-models/serviceability-lifecycle.md b/en/application-dev/application-models/serviceability-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..cc541c77ea0bec412eee09b7b7b3fe4e7e1008d0 --- /dev/null +++ b/en/application-dev/application-models/serviceability-lifecycle.md @@ -0,0 +1,15 @@ +# ServiceAbility Lifecycle + + +You can override lifecycle callbacks (described in the table below) for ServiceAbility based on service requirements. + + + **Table 1** ServiceAbility lifecycle callbacks + +| API| Description| +| -------- | -------- | +| onStart(): void | Called to initialize a ServiceAbility when the ServiceAbility is being created. This callback is invoked only once in the entire lifecycle of a ServiceAbility.| +| onCommand(want: Want, startId: number): void | Called every time a ServiceAbility is started on the client. You can collect calling statistics and perform initialization operations in this callback.| +| onConnect(want: Want): rpc.RemoteObject | Called when the ServiceAbility is connected.| +| onDisconnect(want: Want): void | Called when the connection to the ServiceAbility is disconnected.| +| onStop(): void | Called when the ServiceAbility is being destroyed. You should override this callback for your ServiceAbility to clear its resources, such as threads and registered listeners.| diff --git a/en/application-dev/application-models/serviceability-overview.md b/en/application-dev/application-models/serviceability-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..ba57633f7bd489dd75ddba4cf8d7e829fa97dae4 --- /dev/null +++ b/en/application-dev/application-models/serviceability-overview.md @@ -0,0 +1,4 @@ +# ServiceAbility Component Overview + + +An ability using the Service template (ServiceAbility for short) is used to run tasks in the background, such as playing music or downloading files. It does not provide a UI for user interaction. A ServiceAbility can be started by another application or a PageAbility. It remains to run in the background even after the user switches to another application. diff --git a/en/application-dev/application-models/serviceability-switch.md b/en/application-dev/application-models/serviceability-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..9752a4a11be4982ab65b4fc17262a39b6190b00b --- /dev/null +++ b/en/application-dev/application-models/serviceability-switch.md @@ -0,0 +1,35 @@ +# ServiceAbility Switching + + +The ServiceAbility component in the FA model corresponds to the ServiceExtensionAbility component in the stage model. The ServiceExtensionAbility class provides system APIs. Only system applications can create ServiceExtensionAbility instances. Therefore, ServiceAbility switching adopts different policies for system applications and third-party applications. + + +## Switching a ServiceAbility of a System Application + +The procedure for switching a ServiceAbility of a system application is similar to the procedure of PageAbility switching. + +1. [Create a ServiceExtensionAbility](serviceextensionability.md) in the stage model. + +2. Migrate the ServiceAbility code to the ServiceExtensionAbility. + +The table below describes the lifecycle comparison of the ServiceAbility and ServiceExtensionAbility. + + | ServiceAbility| ServiceExtensionAbility| Comparison Description| + | -------- | -------- | -------- | + | onStart(): void | onCreate(want: Want): void | The two methods have the same invoking time. In the stage model, the **want** parameter is added so that you can obtain parameters during creation.| + | onCommand(want: Want, startId: number): void | onRequest(want: Want, startId: number): void | The two methods have the same meaning, invoking time, and parameters.| + | onConnect(want: Want): rpc.RemoteObject | onConnect(want: Want): rpc.RemoteObject | The two methods have the same meaning, invoking time, and parameters.| + | onDisconnect(want: Want): void | onDisconnect(want: Want): void | The two methods have the same meaning, invoking time, and parameters.| + | onReconnect(want: Want): void| onReconnect(want: Want): void| The two methods have the same meaning, invoking time, and parameters.| + | onStop(): void | onDestroy(): void | The two methods have the same meaning, invoking time, and parameters.| + + +## Switching a ServiceAbility of a Third-Party Application + +In the stage model, third-party applications cannot provide services for other third-party applications. You can select a switching solution based on your service requirements. + +| Service Type| Switching Solution| +| -------- | -------- | +| Providing services for other third-party applications| Match a scenario-specific [ExtensionAbility](extensionability-overview.md).| +| In-application: providing public use when it is running in the foreground| Extract the component code as a common module for other components to use.| +| In-application: continuing running when it switches to the background| Switch the service to [a background service](serviceextensionability.md).| diff --git a/en/application-dev/application-models/serviceextensionability.md b/en/application-dev/application-models/serviceextensionability.md new file mode 100644 index 0000000000000000000000000000000000000000..c4ffdbd980fff4ce568115f92af884da06739ad2 --- /dev/null +++ b/en/application-dev/application-models/serviceextensionability.md @@ -0,0 +1,295 @@ +# ServiceExtensionAbility + +[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 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: + + +- In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB can still exist. + +- In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also 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](#implementing-a-background-service) + +- [Starting a Background Service](#starting-a-background-service) + +- [Connecting to a Background Service](#connecting-to-a-background-service) + + +> **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). +> +> - 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 + +This feature applies only to system applications. [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 +![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. + + > **NOTE** +> + > If a service 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. + +- **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. + +- **onDisconnect** + + +This callback is triggered when a component calls the **disconnectServiceExtensionAbility()** method to disconnect from the service. + +- **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. + + +## How to Develop + +To implement a background service, manually create a ServiceExtensionAbility component in DevEco Studio. 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 **serviceextability**. + +2. In the **serviceextability** directory, right-click and choose **New > TypeScript File** to create a file named **ServiceExtAbility.ts**. + +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; + } + } + ``` + +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; + + class StubTest extends rpc.RemoteObject { + // ... + } + + export default class ServiceExtAbility extends ServiceExtensionAbility { + onCreate(want) { + console.info(TAG, `onCreate, want: ${want.abilityName}`); + } + + onRequest(want, startId) { + console.info(TAG, `onRequest, want: ${want.abilityName}`); + } + + onConnect(want) { + console.info(TAG, `onConnect, want: ${want.abilityName}`); + return new StubTest("test"); + } + + onDisconnect(want) { + console.info(TAG, `onDisconnect, want: ${want.abilityName}`); + } + + onDestroy() { + console.info(TAG, `onDestroy`); + } + } + ``` + +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. + + ```json + { + "module": { + // ... + "extensionAbilities": [ + { + "name": "ServiceExtAbility", + "icon": "$media:icon", + "description": "service", + "type": "service", + "visible": true, + "srcEntrance": "./ets/serviceextability/ServiceExtAbility.ts" + } + ] + } + } + ``` + + +## Starting a Background Service + +This feature applies only to system applications. 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. + +> **NOTE** +> +> [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": "", + "bundleName": "com.example.myapplication", + "abilityName": "ServiceExtAbility" + }; + this.context.startServiceExtensionAbility(want).then(() => { + console.info('startServiceExtensionAbility success'); + }).catch((error) => { + console.info('startServiceExtensionAbility failed'); + }) + ``` + +2. Stop ServiceExtensionAbility in the system application. + + ```ts + let want = { + "deviceId": "", + "bundleName": "com.example.myapplication", + "abilityName": "ServiceExtAbility" + }; + this.context.stopServiceExtensionAbility(want).then(() => { + console.info('stopServiceExtensionAbility success'); + }).catch((error) => { + console.info('stopServiceExtensionAbility failed'); + }) + ``` + +3. ServiceExtensionAbility stops itself. + + ```ts + // this is the current ServiceExtensionAbility component. + this.context.terminateSelf().then(() => { + console.info('terminateSelf success'); + }).catch((error) => { + console.info('terminateSelf failed'); + }) + ``` + + +> **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. + +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) { + console.info('onConnect callback'); + if (remote === null) { + console.info(`onConnect remote is null`); + return; + } + let option = new rpc.MessageOption(); + let data = new rpc.MessageParcel(); + let reply = new rpc.MessageParcel(); + 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 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) => { + let msg = reply.readInt(); + console.info(`sendRequest ret:${ret} msg:${msg}`); + }).catch((error) => { + console.info('sendRequest failed'); + }); + }, + 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 + 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'); + }) + ``` + diff --git a/en/application-dev/application-models/stage-model-development-overview.md b/en/application-dev/application-models/stage-model-development-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..6fbf06baa44d4c0f2196fa3c1b00a0761a71a161 --- /dev/null +++ b/en/application-dev/application-models/stage-model-development-overview.md @@ -0,0 +1,43 @@ +# Stage Model Development Overview + + +## Basic Concepts + +The following figure shows the basic concepts used in the stage model. + +**Figure 1** Concepts used in the stage model +![stage-concepts](figures/stage-concepts.png) + +- [UIAbility component](uiability-overview.md) and [ExtensionAbility component](extensionability-overview.md) + + The stage model provides two types of application components: UIAbility and ExtensionAbility. Both have specific classes and support object-oriented development. They are the specific implementation of the abstract ability concept on the stage model. They are also units scheduled by the Ability Manager Service (AMS), which schedules their lifecycles as well. + + - UIAbility has the UI and is mainly used for user interaction. For example, with UIAbility, the Gallery application can display images in the liquid layout. After a user selects an image, it uses a new UI to display the image details. The user can touch the **Back** button to return to the liquid layout. The lifecycle of the UIAbility component contains the creation, destruction, foreground, and background states. Display-related states are exposed through WindowStage events. + + - ExtensionAbility is oriented to specific scenarios. You cannot derive directly from ExtensionAbility. Instead, use the derived classes of ExtensionAbility for your scenarios, such as FormExtensionAbility for widget scenarios, InputMethodExtensionAbility for input method scenarios, and WorkSchedulerExtensionAbility for Work Scheduled task scenarios. For example, to enable a user to create an application widget on the home screen, you must derive FormExtensionAbility, implement the callback functions, and configure the capability in the configuration file. The derived class instances are created by developers and their lifecycles are managed by the system. In the stage model, you must use the derived classes of ExtensionAbility to develop custom services based on your service scenarios. +- [WindowStage](../windowmanager/application-window-stage.md) + + Each UIAbility class instance is bound to a WindowStage class instance, which functions as the window manager in the application process. The WindowStage class instance contains a main window. That is, UIAbility holds a main window through WindowStage, and this window provides an area for ArkUI to render. + +- [Context](application-context-stage.md) + + In the stage model, Context and its derived classes provide a variety of capabilities that can be called during the runtime. The UIAbility component and ExtensionAbility derived classes have different Context classes. These classes, which all inherit from the base class Context, provide different capabilities. + +- [AbilityStage](abilitystage.md) + + Each HAP of the Entry or Feature type has an AbilityStage class instance during the runtime. When the code in the HAP is loaded to the process for the first time, the system creates an AbilityStage class instance first. Each UIAbility class defined in the HAP is associated with this class instance after instantiation. Through this class instance, you can obtain the runtime information of the UIAbility instances in the HAP. + + +## How to Develop + +During application development based on the stage model, the following tasks are involved in the application model. + +**Table 1** Stage model development process + +| Task| Introduction| Guide| +| -------- | -------- | -------- | +| Application component development| Use the UIAbility and ExtensionAbility components of the stage model to develop applications.| - [Application- or Component-Level Configuration](application-component-configuration-stage.md)
- [UIAbility Component](uiability-overview.md)
- [ExtensionAbility Component](extensionability-overview.md)
- [AbilityStage Container Component](abilitystage.md)
- [Context](application-context-stage.md)
- [Component Startup Rules](component-startup-rules.md)| +| Inter-process communication (IPC)| Learn the process model and common IPC modes of the stage model.| - [Common Events](common-event-overview.md)
- [Background Services](background-services.md)| +| Inter-thread communication| Learn the thread model and common inter-thread communication modes of the stage model.| - [Emitter](itc-with-emitter.md)
- [Worker](itc-with-worker.md)| +| Mission management| Learn the basic concepts and typical scenarios of mission management in the stage model.| - [Mission Management Scenarios](mission-management-overview.md)
- [Mission Management and Launch Type](mission-management-launch-type.md)
- [Page Stack and Mission List](page-mission-stack.md)| +| Application configuration file| Learn the requirements for developing application configuration files in the stage model.| [Application Configuration File](config-file-stage.md)| diff --git a/en/application-dev/application-models/start-dataability.md b/en/application-dev/application-models/start-dataability.md new file mode 100644 index 0000000000000000000000000000000000000000..786a14f91007672e395ed5b754fbaeccb55b3770 --- /dev/null +++ b/en/application-dev/application-models/start-dataability.md @@ -0,0 +1,12 @@ +# Starting a DataAbility + + +When a DataAbility is started, a **DataAbilityHelper** object is obtained. The sample code for starting a DataAbility is as follows: + +```ts +// Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), three slashes in total. +import featureAbility from '@ohos.ability.featureAbility' + +let urivar = "dataability:///com.ix.DataAbility" +let DAHelper = featureAbility.acquireDataAbilityHelper(urivar); +``` diff --git a/en/application-dev/application-models/start-local-pageability.md b/en/application-dev/application-models/start-local-pageability.md new file mode 100644 index 0000000000000000000000000000000000000000..425566ab88d66aecd4690c569dd84d94c46cd568 --- /dev/null +++ b/en/application-dev/application-models/start-local-pageability.md @@ -0,0 +1,35 @@ +# Starting a Local PageAbility + + +The capabilities related to the PageAbility are provided through the **featureAbility** class. For example, **startAbility()** in **featureAbility** is used to the PageAbility. + +**Table 1** featureAbility APIs + +| API| Description| +| -------- | -------- | +| startAbility(parameter: StartAbilityParameter) | Starts an ability.| +| startAbilityForResult(parameter: StartAbilityParameter) | Starts an ability and returns the execution result when the ability is terminated.| + + +The following code snippet shows how to explicitly start a PageAbility through **startAbility()**. The parameters passed in for starting an ability include **want**. For details about the **want** parameter as well as implicit startup and explicit startup, see [Want](want-fa.md). + +```ts +import featureAbility from '@ohos.ability.featureAbility' +(async () => { + try { + console.info('Begin to start ability') + let param = { + want: { + bundleName: "com.example.myapplication", + moduleName: "entry", + abilityName: "com.example.myapplication.EntryAbility" + } + } + await featureAbility.startAbility(param) + console.info(`Start ability succeed`) + } + catch (error) { + console.error('Start ability failed with ' + error) + } +})() +``` diff --git a/en/application-dev/application-models/start-page.md b/en/application-dev/application-models/start-page.md new file mode 100644 index 0000000000000000000000000000000000000000..58966d93cba037eaad141caaed0feaaaa672cde1 --- /dev/null +++ b/en/application-dev/application-models/start-page.md @@ -0,0 +1,142 @@ +# Starting a Specified Page + + +When the launch type of a PageAbility is set to **singleton** (default), the **onNewWant()** callback is triggered if the PageAbility is not started for the first time. For details about the launch type, see [PageAbility Launch Type](pageability-launch-type.md). In this case, you can use the **want** parameter to transfer startup information. For example, if you want to start a PageAbility with a specified page, pass the pages information in **parameters** of **want**. + + +In **app.ets** or **page** of the caller PageAbility, use **startAbility()** to start the PageAbility again, with the page information passed in the **uri** parameter in **want**. + +```ts +import featureAbility from '@ohos.ability.featureAbility'; + +async function restartAbility() { + let wantInfo = { + bundleName: "com.sample.MyApplication", + abilityName: "EntryAbility", + parameters: { + page: "pages/second" + } + }; + featureAbility.startAbility({ + want: wantInfo + }).then((data) => { + console.info('restartAbility success.'); + }); +} +``` + + +Obtain the **want** parameter that contains the page information from the **onNewWant()** callback of the target PageAbility. + +```ts +export default { + onNewWant(want) { + globalThis.newWant = want + } +} +``` + + +Obtain the **want** parameter that contains the page information from the custom component of the target PageAbility and process the route based on the URI. + +```ts +import router from '@ohos.router' +@Entry +@Component +struct Index { + @State message: string = 'Router Page' + newWant = undefined + onPageShow() { + console.info('Index onPageShow') + let newWant = globalThis.newWant + if (newWant.hasOwnProperty("page")) { + router.push({ url: newWant.page }); + globalThis.newWant = undefined + } + } + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} +``` + + +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 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. + +```ts +import featureAbility from '@ohos.ability.featureAbility' +@Entry +@Component +struct Index { + @State message: string = 'Hello World' + + build() { + // ... + Button("startAbility") + .onClick(() => { + featureAbility.startAbility({ + want: { + bundleName: "com.exm.myapplication", + abilityName: "com.exm.myapplication.EntryAbility", + parameters: { page: "pages/page1" } + } + }).then((data) => { + console.info("startAbility finish"); + }).catch((err) => { + console.info("startAbility failed errcode:" + err.code) + }) + }) + // ... + Button("page2") + .onClick(() => { + featureAbility.startAbility({ + want: { + bundleName: "com.exm.myapplication", + abilityName: "com.exm.myapplication.EntryAbility", + parameters: { page: "pages/page2" } + } + }).then((data) => { + console.info("startAbility finish"); + }).catch((err) => { + console.info("startAbility failed errcode:" + err.code) + }) + }) + // ... + } +} +``` + + +In the **onCreate()** callback of the target PageAbility, use the **featureAbility.getWant()** method to obtain the **want** parameter, parse the parameter, and start the specified page. + +```ts +import featureAbility from '@ohos.ability.featureAbility'; +import router from '@ohos.router'; + +export default { + onCreate() { + featureAbility.getWant().then((want) => { + if (want.parameters.page) { + router.push({ + url: want.parameters.page + }) + } + }) + }, + onDestroy() { + // ... + }, +} +``` diff --git a/en/application-dev/application-models/start-pageability-from-stage.md b/en/application-dev/application-models/start-pageability-from-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..9d1b7ed27f6780ce56d1e90b3be5d196cf3b1187 --- /dev/null +++ b/en/application-dev/application-models/start-pageability-from-stage.md @@ -0,0 +1,122 @@ +# Starting a PageAbility from the Stage Model + + +This topic describes how the two application components of the stage model start the PageAbility component of the FA model. + + +## UIAbility Starting a PageAbility + +A UIAbility starts a PageAbility in the same way as it starts another UIAbility. + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + console.info("EntryAbility onCreate") + } + onDestroy() { + console.info("EntryAbility onDestroy") + } + onWindowStageCreate(windowStage) { + console.info("EntryAbility onWindowStageCreate") + windowStage.loadContent('pages/Index', (err, data) => { + // ... + }); + let want = { + bundleName: "com.ohos.fa", + abilityName: "EntryAbility", + }; + this.context.startAbility(want).then(() => { + console.info('Start Ability successfully.'); + }).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); + }); + } + onWindowStageDestroy() { + console.info("EntryAbility onWindowStageDestroy") + } + onForeground() { + console.info("EntryAbility onForeground") + } + onBackground() { + console.info("EntryAbility onBackground") + } +} +``` + + +## UIAbility Accessing a PageAbility (startAbilityForResult) + +Different from **startAbility()**, **startAbilityForResult()** obtains the execution result when the PageAbility is destroyed. + +A UIAbility starts a PageAbility through **startAbilityForResult()** in the same way as it starts another UIAbility through **startAbilityForResult()**. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + console.info("EntryAbility onCreate") + } + onDestroy() { + console.info("EntryAbility onDestroy") + } + onWindowStageCreate(windowStage) { + console.info("EntryAbility onWindowStageCreate") + windowStage.loadContent('pages/Index', (err, data) => { + // ... + }); + let want = { + bundleName: "com.ohos.fa", + abilityName: "EntryAbility", + }; + this.context.startAbilityForResult(want).then((result) => { + console.info('Ability verify result: ' + JSON.stringify(result)); + }).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); + }); + } + onWindowStageDestroy() { + console.info("EntryAbility onWindowStageDestroy") + } + onForeground() { + console.info("EntryAbility onForeground") + } + onBackground() { + console.info("EntryAbility onBackground") + } +} +``` + + +## ExtensionAbility Starting a PageAbility + +The following uses the ServiceExtensionAbility component as an example to describe how an ExtensionAbility starts a PageAbility. A ServiceExtensionAbility starts a PageAbility in the same way as it starts a UIAbility. + + +```ts +import Extension from '@ohos.app.ability.ServiceExtensionAbility' + +export default class ServiceExtension extends Extension { + onCreate(want) { + console.info("ServiceExtension onCreate") + } + onDestroy() { + console.info("ServiceExtension onDestroy") + } + onRequest(want, startId) { + console.info("ServiceExtension onRequest") + let wantFA = { + bundleName: "com.ohos.fa", + abilityName: "EntryAbility", + }; + this.context.startAbility(wantFA).then(() => { + console.info('Start Ability successfully.'); + }).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); + }); + } +} +``` diff --git a/en/application-dev/application-models/start-remote-pageability.md b/en/application-dev/application-models/start-remote-pageability.md new file mode 100644 index 0000000000000000000000000000000000000000..4e998a15d23d298bfdb402bd18ea0db2a9f819eb --- /dev/null +++ b/en/application-dev/application-models/start-remote-pageability.md @@ -0,0 +1,136 @@ +# Starting a Remote PageAbility + + +This feature applies only to system applications. The **startAbility()** method in the **featureAbility** class is used to start a remote PageAbility. + + +In addition to **'\@ohos.ability.featureAbility'**, you must import **'\@ohos.distributedHardware.deviceManager'**, which provides account-independent distributed device networking capabilities. Then you can use **getTrustedDeviceListSync** of the **DeviceManager** module to obtain the remote device ID and pass the remote device ID in the **want** parameter for starting the remote PageAbility. + + +The **getTrustedDeviceListSync** method is available only for system applications. Therefore, non-system applications cannot obtain remote device information or start a remote ability. + +**Table 1** featureAbility APIs + +| API| Description| +| -------- | -------- | +| startAbility(parameter: StartAbilityParameter)| Starts an ability.| +| startAbilityForResult(parameter: StartAbilityParameter)| Starts an ability and returns the execution result when the ability is terminated.| + +**Table 2** deviceManager APIs + +| API| Description| +| -------- | -------- | +| getTrustedDeviceListSync(): Array<DeviceInfo> | Obtains all trusted devices synchronously.| + + +In the cross-device scenario, before starting a remote PageAbility, you must request the data synchronization permission. The related APIs are described in the table below. + +**Table 3** AtManager APIs + +| API| Description| +| -------- | -------- | +| checkAccessToken(tokenID: number, permissionName: string): Promise<GrantStatus> | Verifies whether a permission is granted to an application. This API uses a promise to return the result **GrantStatus**. You are advised to use **checkAccessToken** instead of **verifyAccessToken**, which is deprecated since API version 9.| + +**Table 4** context APIs + +| API| Description| +| -------- | -------- | +| requestPermissionsFromUser(permissions: Array<string>, requestCode: number, resultCallback: AsyncCallback< PermissionRequestResult>): void | Requests permissions from the system. This API uses an asynchronous callback to return the result. For details, see [API Reference](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7-1).| + + +The following sample code shows how to request the data synchronization permission from users: + +```ts +import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; +import featureAbility from '@ohos.ability.featureAbility'; +import bundle from '@ohos.bundle.bundleManager'; +async function RequestPermission() { + console.info('RequestPermission begin'); + let array: Array = ["ohos.permission.DISTRIBUTED_DATASYNC"]; + let bundleFlag = 0; + let tokenID = undefined; + let userID = 100; + let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); + tokenID = appInfo.accessTokenId; + let atManager = abilityAccessCtrl.createAtManager(); + let requestPermissions: Array = []; + for (let i = 0;i < array.length; i++) { + let result = await atManager.verifyAccessToken(tokenID, array[i]); + console.info("checkAccessToken result:" + JSON.stringify(result)); + if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { + requestPermissions.push(array[i]); + } + } + console.info("requestPermissions:" + JSON.stringify(requestPermissions)); + if (requestPermissions.length == 0 || requestPermissions == []) { + return; + } + let context = featureAbility.getContext(); + context.requestPermissionsFromUser(requestPermissions, 1, (error, data)=>{ + console.info("data:" + JSON.stringify(data)); + console.info("data requestCode:" + data.requestCode); + console.info("data permissions:" + data.permissions); + console.info("data authResults:" + data.authResults); + }); + console.info('RequestPermission end'); +} +``` + + +After obtaining the data synchronization permission, obtain the trusted device list for device selection. + + +The following sample code shows how to use **getTrustedDeviceListSync()** to obtain the trusted device list. + +```ts +import deviceManager from '@ohos.distributedHardware.deviceManager'; +let dmClass; +function getDeviceManager() { + deviceManager.createDeviceManager('ohos.example.distributedService', (error, dm) => { + if (error) { + console.info('create device manager failed with ' + error) + } + dmClass = dm; + }) +} +function getRemoteDeviceId() { + if (typeof dmClass === 'object' && dmClass != null) { + let list = dmClass.getTrustedDeviceListSync(); + if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { + console.info("EntryAbility onButtonClick getRemoteDeviceId err: list is null"); + return; + } + console.info("EntryAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); + return list[0].deviceId; + } else { + console.info("EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null"); + } +} +``` + + +After a device is selected, call **startAbility()** to explicitly start the remote PageAbility. + + +The following sample code shows how to explicitly start a remote PageAbility through **startAbility()**. + +```ts +import featureAbility from '@ohos.ability.featureAbility'; +function onStartRemoteAbility() { + console.info('onStartRemoteAbility begin'); + let params; + let wantValue = { + bundleName: 'ohos.samples.etsDemo', + abilityName: 'ohos.samples.etsDemo.RemoteAbility', + deviceId: getRemoteDeviceId(), // getRemoteDeviceId is defined in the preceding sample code. + parameters: params + }; + console.info('onStartRemoteAbility want=' + JSON.stringify(wantValue)); + featureAbility.startAbility({ + want: wantValue + }).then((data) => { + console.info('onStartRemoteAbility finished, ' + JSON.stringify(data)); + }); + console.info('onStartRemoteAbility end'); +} +``` diff --git a/en/application-dev/application-models/start-serviceability.md b/en/application-dev/application-models/start-serviceability.md new file mode 100644 index 0000000000000000000000000000000000000000..f3b0f6aeabc8a3ea35c1f6c390ec53239730443c --- /dev/null +++ b/en/application-dev/application-models/start-serviceability.md @@ -0,0 +1,35 @@ +# Starting a ServiceAbility + + +A ServiceAbility is started in the same way other abilities. You can start a ServiceAbility by calling **featureAbility.startAbility()** in the PageAbility or calling **particleAbility.startAbility()** in another ServiceAbility. For details about the startup rules, see [Component Startup Rules](component-startup-rules.md). + + +The following example shows how to use **startAbility()** to start the ServiceAbility whose **bundleName** is **com.example.myapplication** and **abilityName** is **ServiceAbility** in a PageAbility. When starting the ServiceAbility, concatenate the **bundleName** string before **abilityName**. + +```ts +import featureAbility from '@ohos.ability.featureAbility' + +async function startServiceAbility() { + try { + console.info('Begin to start ability') + let param = { + want: { + bundleName: "com.example.myapplication", + abilityName: "com.example.myapplication.ServiceAbility" + } + } + await featureAbility.startAbility(param) + console.info(`Start ability succeed`) + } catch (error) { + console.error('Start ability failed with ' + error) + } +} +``` + + +In the preceding code, **startAbility()** is used to start the ServiceAbility. + + +- If the ServiceAbility is not running, the system calls **onStart()** to initialize the ServiceAbility, and then calls **onCommand()** on the ServiceAbility. + +- If the ServiceAbility is running, the system directly calls **onCommand()** on the ServiceAbility. diff --git a/en/application-dev/application-models/start-uiability-from-fa.md b/en/application-dev/application-models/start-uiability-from-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..42d8e034cd6519643423bb289217d1aa140a18d4 --- /dev/null +++ b/en/application-dev/application-models/start-uiability-from-fa.md @@ -0,0 +1,71 @@ +# Starting a UIAbility from the FA Model + + +This topic describes how the three application components of the FA model start the UIAbility component of the stage model. + + +## PageAbility Starting a UIAbility + +A PageAbility starts a UIAbility in the same way as it starts another PageAbility. + +```ts +import featureAbility from '@ohos.ability.featureAbility'; + +let parameter = { + "want": { + bundleName: "com.ohos.stage", + abilityName: "com.ohos.stage.EntryAbility" + } +}; +featureAbility.startAbility(parameter).then((code) => { + console.info('Ability verify code: ' + JSON.stringify(code)); +}).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); +}); +``` + + +## PageAbility Accessing a UIAbility (startAbilityForResult) + +Different from **startAbility()**, **startAbilityForResult()** obtains the execution result when the UIAbility is destroyed. + +A PageAbility starts a UIAbility through **startAbilityForResult()** in the same way as it starts another PageAbility through **startAbilityForResult()**. + + +```ts +import featureAbility from '@ohos.ability.featureAbility'; + +let parameter = { + "want": { + bundleName: "com.ohos.stage", + abilityName: "com.ohos.stage.EntryAbility" + } +}; +featureAbility.startAbilityForResult(parameter).then((result) => { + console.info('Ability verify result: ' + JSON.stringify(result)); +}).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); +}); +``` + + +## ServiceAbility or DataAbility Starting a UIAbility + +A ServiceAbility or DataAbility starts a UIAbility in the same way as it starts a PageAbility. + + +```ts +import particleAbility from '@ohos.ability.particleAbility'; + +let parameter = { + "want": { + bundleName: "com.ohos.stage", + abilityName: "com.ohos.stage.EntryAbility" + } +}; +particleAbility.startAbility(parameter).then(() => { + console.info('Start Ability successfully.'); +}).catch((error) => { + console.error("Ability failed: " + JSON.stringify(error)); +}); +``` diff --git a/en/application-dev/application-models/stop-pageability.md b/en/application-dev/application-models/stop-pageability.md new file mode 100644 index 0000000000000000000000000000000000000000..7258a6b9e1311bcac602209c31710136a90dfb17 --- /dev/null +++ b/en/application-dev/application-models/stop-pageability.md @@ -0,0 +1,29 @@ +# Stopping a PageAbility + + +The **terminateSelf()** method in the **featureAbility** class is used to stop a PageAbility. + +**Table 1** featureAbility APIs + +| API| Description| +| -------- | -------- | +| terminateSelf() | Terminates this ability.| +| terminateSelfWithResult(parameter: AbilityResult) | Terminates this ability and returns the execution result.| + + +The following code snippet shows how to stop an ability. + +```ts +import featureAbility from '@ohos.ability.featureAbility' + +(async () => { + try { + console.info('Begin to terminateSelf') + await featureAbility.terminateSelf() + console.info('terminateSelf succeed') + } + catch (error) { + console.error('terminateSelf failed with ' + error) + } +})() +``` diff --git a/en/application-dev/application-models/storage-switch.md b/en/application-dev/application-models/storage-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..63486fe56fdf3605121711bee423066d9ac6e116 --- /dev/null +++ b/en/application-dev/application-models/storage-switch.md @@ -0,0 +1,13 @@ +# Storage Switching + + + | API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| GetStorageOptions | There is no corresponding API in the stage model.| The stage model uses **Prefereces** to replace **Storage** and has redesigned the input parameters.| +| SetStorageOptions | There is no corresponding API in the stage model.| The stage model uses **Prefereces** to replace **Storage** and has redesigned the input parameters.| +| ClearStorageOptions | There is no corresponding API in the stage model.| The stage model uses **Prefereces** to replace **Storage** and has redesigned the input parameters.| +| DeleteStorageOptions | There is no corresponding API in the stage model.| The stage model uses **Prefereces** to replace **Storage** and has redesigned the input parameters.| +| [static get(options: GetStorageOptions): void;](../reference/apis/js-apis-system-storage.md#storageget) | \@ohos.data.preferences.d.ts | [get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void;](../reference/apis/js-apis-data-preferences.md#get)
[get(key: string, defValue: ValueType): Promise<ValueType>;](../reference/apis/js-apis-data-preferences.md#get-1) | +| [static set(options: SetStorageOptions): void;](../reference/apis/js-apis-system-storage.md#storageset) | \@ohos.data.preferences.d.ts | [put(key: string, value: ValueType, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-data-preferences.md#put)
[put(key: string, value: ValueType): Promise<void>;](../reference/apis/js-apis-data-preferences.md#put-1) | +| [static clear(options?: ClearStorageOptions): void;](../reference/apis/js-apis-system-storage.md#storageclear) | \@ohos.data.preferences.d.ts | [clear(callback: AsyncCallback<void>): void;](../reference/apis/js-apis-data-preferences.md#clear)
[clear(): Promise<void>;](../reference/apis/js-apis-data-preferences.md#clear-1) | +| [static delete(options: DeleteStorageOptions): void;](../reference/apis/js-apis-system-storage.md#storagedelete) | \@ohos.data.preferences.d.ts | [delete(key: string, callback: AsyncCallback<void>): void;](../reference/apis/js-apis-data-preferences.md#delete)
[delete(key: string): Promise<void>;](../reference/apis/js-apis-data-preferences.md#delete-1) | diff --git a/en/application-dev/application-models/thread-model-fa.md b/en/application-dev/application-models/thread-model-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..75401be69cba994ac631b6da997fb6ce2ea35a2f --- /dev/null +++ b/en/application-dev/application-models/thread-model-fa.md @@ -0,0 +1,28 @@ +# Thread Model (FA Model) + + +There are three types of threads in the FA model: + + +- Main thread + +Manages other threads. + +- Ability thread + - One ability thread for each ability. + - Distributes input events. + - Draws the UI. + - Invokes application code callbacks (event processing and lifecycle callbacks). + - Receives messages sent by the worker thread. + +- Worker thread + + Performs time-consuming operations + + +Based on the OpenHarmony thread model, different services run on different threads. Service interaction requires inter-thread communication. Threads can communicate with each other in Emitter or Worker mode. Emitter is mainly used for event synchronization between threads, and Worker is mainly used to execute time-consuming tasks. + + +> **NOTE** +> +> The FA model provides an independent thread for each ability. Emitter is mainly used for event synchronization within the ability thread, between a pair of ability threads, or between the ability thread and worker thread. diff --git a/en/application-dev/application-models/thread-model-stage.md b/en/application-dev/application-models/thread-model-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..deaab60b7bd7549dcb96bc00d7896d5c67e5c5d2 --- /dev/null +++ b/en/application-dev/application-models/thread-model-stage.md @@ -0,0 +1,25 @@ +# Thread Model (Stage Model) + +For an OpenHarmony application, each process has a main thread to provide the following functionalities: + +- Manage other threads. + +- Enable multiple UIAbility components of the same application to share the same main thread. + +- Distribute input events. + +- Draw the UI. + +- Invoke application code callbacks (event processing and lifecycle callbacks). + +- 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. + +![thread-model-stage](figures/thread-model-stage.png) + +Based on the OpenHarmony thread model, different services run on different threads. Service interaction requires inter-thread communication. In the same process, threads can communicate with each other in Emitter or Worker mode. Emitter is mainly used for event synchronization between threads, and Worker is mainly used to execute time-consuming tasks. + +> **NOTE** +> +> The 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. diff --git a/en/application-dev/application-models/uiability-data-sync-with-ui.md b/en/application-dev/application-models/uiability-data-sync-with-ui.md new file mode 100644 index 0000000000000000000000000000000000000000..981a9212892a8bc1a920ac929608685c3eafeb00 --- /dev/null +++ b/en/application-dev/application-models/uiability-data-sync-with-ui.md @@ -0,0 +1,320 @@ +# Data Synchronization Between UIAbility and UI + + +Based on the OpenHarmony application model, you can use any of the following ways to implement data synchronization between the UIAbility component and UI: + +- EventHub: The [base class Context](application-context-stage.md) provides the EventHub capability. It is implemented based on the publish/subscribe (pub/sub) pattern. Your application subscribes to an event and when the event occurs, receives a notification. + +- globalThis: It is a global object accessible in the ArkTS engine instance. +- LocalStorage/AppStorage: See [State Management of Application-Level Variables](../quick-start/arkts-state-mgmt-application-level.md). + + +## Using EventHub for Data Synchronization + +[EventHub](../reference/apis/js-apis-inner-application-eventHub.md) provides an event mechanism at the UIAbility or ExtensionAbility component level. Centered on the UIAbility or ExtensionAbility component, EventHub provides data communication capabilities for subscribing to, unsubscribing from, and triggering events. + +Before using EventHub, you must obtain an EventHub object, which is provided by the [base class Context](application-context-stage.md). This section uses EventHub as an example to describe how to implement data synchronization between the UIAbility component and the UI. + +1. Call [eventHub.on()](../reference/apis/js-apis-inner-application-eventHub.md#eventhubon) in the UIAbility in either of the following ways to register a custom event **event1**. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + + const TAG: string = '[Example].[Entry].[EntryAbility]'; + + export default class EntryAbility extends UIAbility { + func1(...data) { + // Trigger the event to complete the service operation. + console.info(TAG, '1. ' + JSON.stringify(data)); + } + + onCreate(want, launch) { + // Obtain an eventHub object. + let eventhub = this.context.eventHub; + // Subscribe to the event. + eventhub.on('event1', this.func1); + eventhub.on('event1', (...data) => { + // Trigger the event to complete the service operation. + console.info(TAG, '2. ' + JSON.stringify(data)); + }); + } + } + ``` + +2. Call [eventHub.emit()](../reference/apis/js-apis-inner-application-eventHub.md#eventhubemit) on the UI to trigger the event, and pass the parameters as required. + + ```ts + import common from '@ohos.app.ability.common'; + + @Entry + @Component + struct Index { + private context = getContext(this) as common.UIAbilityContext; + + eventHubFunc() { + // Trigger the event without parameters. + this.context.eventHub.emit('event1'); + // Trigger the event with one parameter. + this.context.eventHub.emit('event1', 1); + // Trigger the event with two parameters. + this.context.eventHub.emit('event1', 2, 'test'); + // You can design the parameters based on your service requirements. + } + + // Page display. + build() { + // ... + } + } + ``` + +3. Obtain the event trigger result from the subscription callback of UIAbility. The run log result is as follows: + + ```ts + [] + + [1] + + [2,'test'] + ``` + +4. After **event1** is used, you can call [eventHub.off()](../reference/apis/js-apis-inner-application-eventHub.md#eventhuboff) to unsubscribe from the event. + + ```ts + // context is the ability context of the UIAbility instance. + this.context.eventHub.off('event1'); + ``` + + +## Using globalThis for Data Synchronization + + +**globalThis** is a global object inside the [ArkTS engine instance](thread-model-stage.md) and can be used by UIAbility, ExtensionAbility, and Page inside the engine. Therefore, you can use **globalThis** for data synchronization. + + **Figure 1** Using globalThis for data synchronization +globalThis1 + + +The following describes how to use **globalThis** in three scenarios. Precautions are provided as well. + +- [Using globalThis Between UIAbility and Page](#using-globalthis-between-uiability-and-page) +- [Using globalThis Between UIAbility and UIAbility](##using-globalthis-between-uiability-and-uiability) +- [Use globalThis Between UIAbility and ExtensionAbility](#using-globalthis-between-uiability-and-extensionability) +- [Precautions for Using globalThis](#precautions-for-using-globalthis) + +### Using globalThis Between UIAbility and Page + +You can use **globalThis** to bind attributes or methods to implement data synchronization between the UIAbility component and UI. For example, if you bind the **want** parameter in the UIAbility component, you can use the **want** parameter information on the UI corresponding to the UIAbility component. + +1. When **startAbility()** is called to start a UIAbility instance, the **onCreate()** callback is invoked, and the **want** parameter can be passed in the callback. Therefore, you can bind the **want** parameter to **globalThis**. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class EntryAbility extends UIAbility { + onCreate(want, launch) { + globalThis.entryAbilityWant = want; + // ... + } + + // ... + } + ``` + +2. Use **globalThis** on the UI to obtain the **want** parameter information. + + ```ts + let entryAbilityWant; + + @Entry + @Component + struct Index { + aboutToAppear() { + entryAbilityWant = globalThis.entryAbilityWant; + } + + // Page display. + build() { + // ... + } + } + ``` + + +### Using globalThis Between UIAbility and UIAbility + +To implement data synchronization between two UIAbility components in the same application, you can bind data to **globalThis**. For example, you can save data in **globalThis** in AbilityA and obtain the data from AbilityB. + +1. AbilityA stores a string and binds it to globalThis. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityA extends UIAbility { + onCreate(want, launch) { + globalThis.entryAbilityStr = 'AbilityA'; // AbilityA stores the string "AbilityA" to globalThis. + // ... + } + } + ``` + +2. Obtain the data from AbilityB. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityB extends UIAbility { + onCreate(want, launch) { + // AbilityB reads the name from globalThis and outputs it. + console.info('name from entryAbilityStr: ' + globalThis.entryAbilityStr); + // ... + } + } + ``` + + +### Using globalThis Between UIAbility and ExtensionAbility + +To implement data synchronization between the UIAbility and ExtensionAbility components in the same application, you can bind data to **globalThis**. For example, you can save data in **globalThis** in AbilityA and obtain the data from ServiceExtensionAbility. + +1. AbilityA stores a string and binds it to globalThis. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityA extends UIAbility { + onCreate(want, launch) { + // AbilityA stores the string "AbilityA" to globalThis. + globalThis.entryAbilityStr = 'AbilityA'; + // ... + } + } + ``` + +2. Obtain the data from ExtensionAbility. + + ```ts + import Extension from '@ohos.app.ability.ServiceExtensionAbility' + + export default class ServiceExtAbility extends Extension { + onCreate(want) { + / / ServiceExtAbility reads name from globalThis and outputs it. + console.info('name from entryAbilityStr: ' + globalThis.entryAbilityStr); + // ... + } + } + ``` + + +### Precautions for Using globalThis + + **Figure 2** Precautions for globalThis +![globalThis2](figures/globalThis2.png) + +- In the stage model, all the UIAbility components in a process share one ArkTS engine instance. When using **globalThis**, do not store objects with the same name. For example, if AbilityA and AbilityB use **globalThis** to store two objects with the same name, the object stored earlier will be overwritten. + +- This problem does not occur in the FA model because each UIAbility component uses an independent engine. + +- The lifecycle of an object bound to **globalThis** is the same as that of the ArkTS engine instance. You are advised to assign the value **null** after using the object to minimize memory usage. + +The following provides an example to describe the object overwritten problem in the stage model. + +1. In the AbilityA file, [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) is stored in **globalThis**. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityA extends UIAbility { + onCreate(want, launch) { + globalThis.context = this.context; // AbilityA stores the context in globalThis. + // ... + } + } + ``` + +2. Obtain and use [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) on the page of Ability A. After the AbilityA instance is used, switch it to the background. + + ```ts + @Entry + @Component + struct Index { + onPageShow() { + let ctx = globalThis.context; // Obtain the context from globalThis and use it. + let permissions = ['com.example.permission'] + ctx.requestPermissionsFromUser(permissions,(result) => { + // ... + }); + } + // Page display. + build() { + // ... + } + } + ``` + +3. In the AbilityB file, [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) is stored in **globalThis** and has the same name as that in the AbilityA file. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityB extends UIAbility { + onCreate(want, launch) { + // AbilityB overwrites the context stored by AbilityA in globalThis. + globalThis.context = this.context; + // ... + } + } + ``` + +4. Obtain and use [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) on the page of Ability B. The obtained **globalThis.context** is the value of [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) in AbilityB. + + ```ts + @Entry + @Component + struct Index { + onPageShow() { + let ctx = globalThis.context; // Obtain the context from globalThis and use it. + let permissions = ['com.example.permission'] + ctx.requestPermissionsFromUser(permissions,(result) => { + console.info('requestPermissionsFromUser result:' + JSON.stringify(result)); + }); + } + // Page display. + build() { + // ... + } + } + ``` + +5. Switch the AbilityB instance to the background and switch the AbilityA instance to the foreground. In this case, AbilityA will not enter the **onCreate()** lifecycle again. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class AbilityA extends UIAbility { + onCreate(want, launch) { // AbilityA will not enter this lifecycle. + globalThis.context = this.context; + // ... + } + } + ``` + +6. When the page of AbilityA is displayed, the obtained **globalThis.context** is [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) of AbilityB instead of AbilityA. An error occurs. + + ```ts + @Entry + @Component + struct Index { + onPageShow() { + let ctx = globalThis.context; // The context in globalThis is the context of AbilityB. + let permissions=['com.example.permission']; + ctx.requestPermissionsFromUser(permissions,(result) => { // Using this object causes a process breakdown. + console.info('requestPermissionsFromUser result:' + JSON.stringify(result)); + }); + } + // Page display. + build() { + // ... + } + } + ``` diff --git a/en/application-dev/application-models/uiability-intra-device-interaction.md b/en/application-dev/application-models/uiability-intra-device-interaction.md new file mode 100644 index 0000000000000000000000000000000000000000..ea6b8bbecfa4a9a4f5434fb0aa5aad6184f38c9f --- /dev/null +++ b/en/application-dev/application-models/uiability-intra-device-interaction.md @@ -0,0 +1,631 @@ +# Intra-Device Interaction Between UIAbility Components + + +UIAbility is the minimum unit that can be scheduled by the system. Jumping between functional modules in a device involves starting of specific UIAbility components, which belong to the same or a different application (for example, starting UIAbility of a third-party payment application). + + +This topic describes the UIAbility interaction modes in the following scenarios. For details about cross-device application component interaction, see [Inter-Device Application Component Interaction (Continuation)](inter-device-interaction-hop-overview.md). + + +- [Starting UIAbility in the Same Application](#starting-uiability-in-the-same-application) + +- [Starting UIAbility in the Same Application and Obtaining the Return Result](#starting-uiability-in-the-same-application-and-obtaining-the-return-result) + +- [Starting UIAbility of Another Application](#starting-uiability-of-another-application) + +- [Starting UIAbility of Another Application and Obtaining the Return Result](#starting-uiability-of-another-application-and-obtaining-the-return-result) + +- [Starting a Specified Page of UIAbility](#starting-a-specified-page-of-uiability) + +- [Using Ability Call to Implement UIAbility Interaction](#using-ability-call-to-implement-uiability-interaction) + + +## Starting UIAbility in the Same Application + +This scenario is possible when an application contains multiple UIAbility components. For example, in a payment application, you may need to start the payment UIAbility from the entry UIAbility. + +Assume that your application has two UIAbility components: EntryAbility and FuncAbility, either in the same module or different modules. You are required to start FuncAbility from EntryAbility. + +1. In EntryAbility, call **startAbility()** to start UIAbility. The [want](../reference/apis/js-apis-app-ability-want.md) parameter is the entry parameter for starting the UIAbility instance. In the **want** parameter, **bundleName** indicates the bundle name of the application to start; **abilityName** indicates the name of the UIAbility to start; **moduleName** is required only when the target UIAbility belongs to a different module; **parameters** is used to carry custom information. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). + + ```ts + let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', // moduleName is optional. + parameters: {// Custom information. + info: 'From the Index page of EntryAbility', + }, + } + // context is the ability-level context of the initiator UIAbility. + this.context.startAbility(wantInfo).then(() => { + // ... + }).catch((err) => { + // ... + }) + ``` + +2. Use the FuncAbility lifecycle callback to receive the parameters passed from EntryAbility. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + import window from '@ohos.window'; + + export default class FuncAbility extends UIAbility { + onCreate(want, launchParam) { + // Receive the parameters passed by the caller UIAbility. + let funcAbilityWant = want; + let info = funcAbilityWant?.parameters?.info; + // ... + } + } + ``` + +3. To stop the **UIAbility** instance after the FuncAbility service is complete, call **terminateSelf()** in FuncAbility. + + ```ts + // context is the ability context of the UIAbility instance to stop. + this.context.terminateSelf((err) => { + // ... + }); + ``` + + +## Starting UIAbility in the Same Application and Obtaining the Return Result + +When starting FuncAbility from EntryAbility, you want the result to be returned after the FuncAbility service is finished. For example, your application uses two independent UIAbility components to carry the entry and sign-in functionalities. After the sign-in operation is finished in the sign-in UIAbility, the sign-in result needs to be returned to the entry UIAbility. + +1. In EntryAbility, call **startAbilityForResult()** to start FuncAbility. Use **data** in the asynchronous callback to receive information returned after FuncAbility stops itself. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). + + ```ts + let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', // moduleName is optional. + parameters: {// Custom information. + info: 'From the Index page of EntryAbility', + }, + } + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(wantInfo).then((data) => { + // ... + }).catch((err) => { + // ... + }) + ``` + +2. Call **terminateSelfWithResult()** to stop FuncAbility. Use the input parameter **abilityResult** to carry the information that FuncAbility needs to return to EntryAbility. + + ```ts + const RESULT_CODE: number = 1001; + let abilityResult = { + resultCode: RESULT_CODE, + want: { + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', + parameters: { + info: 'From the Index page of FuncAbility', + }, + }, + } + // context is the ability context of the callee UIAbility. + this.context.terminateSelfWithResult(abilityResult, (err) => { + // ... + }); + ``` + +3. After FuncAbility stops itself, EntryAbility uses the **startAbilityForResult()** method to receive the information returned by FuncAbility. The value of **RESULT_CODE** must be the same as the preceding value. + + ```ts + const RESULT_CODE: number = 1001; + + // ... + + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(want).then((data) => { + if (data?.resultCode === RESULT_CODE) { + // Parse the information returned by the callee UIAbility. + let info = data.want?.parameters?.info; + // ... + } + }).catch((err) => { + // ... + }) + ``` + + +## Starting UIAbility of Another Application + +Generally, the user only needs to do a common operation (for example, selecting a document application to view the document content) to start the UIAbility of another application. The [implicit Want launch mode](want-overview.md#types-of-want) is recommended. The system identifies a matched UIAbility and starts it based on the **want** parameter of the caller. + +There are two ways to start **UIAbility**: [explicit and implicit](want-overview.md). + +- Explicit Want launch: This mode is used to start a determined UIAbility component of an application. You need to set **bundleName** and **abilityName** of the target application in the **want** parameter. + +- Implicit Want launch: The user selects a UIAbility to start based on the matching conditions. That is, the UIAbility to start is not determined (the **abilityName** parameter is not specified). When the **startAbility()** method is called, the **want** parameter specifies a series of parameters such as [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) and [actions](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction). **entities** provides additional type information of the target UIAbility, such as the browser or video player. **actions** specifies the common operations to perform, such as viewing, sharing, and application details. Then the system analyzes the **want** parameter to find the right UIAbility to start. You usually do not know whether the target application is installed and what **bundleName** and **abilityName** of the target application are. Therefore, implicit Want launch is usually used to start the UIAbility of another application. + +This section describes how to start the UIAbility of another application through implicit Want. + +1. Install multiple document applications on your device. In the **module.json5** file of each UIAbility component, configure [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) and [actions](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction) under **skills**. + + ```json + { + "module": { + "abilities": [ + { + // ... + "skills": [ + { + "entities": [ + // ... + "entity.system.default" + ], + "actions": [ + // ... + "ohos.want.action.viewData" + ] + } + ] + } + ] + } + } + ``` + +2. Include **entities** and **actions** of the caller's **want** parameter into **entities** and **actions** under **skills** of the target UIAbility. After the system matches the UIAbility that meets the **entities** and **actions** information, a dialog box is displayed, showing the list of matched UIAbility instances for users to select. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). + + ```ts + let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + // Uncomment the line below if you want to implicitly query data only in the specific bundle. + // bundleName: 'com.example.myapplication', + action: 'ohos.want.action.viewData', + // entities can be omitted. + entities: ['entity.system.default'], + } + + // context is the ability-level context of the initiator UIAbility. + this.context.startAbility(wantInfo).then(() => { + // ... + }).catch((err) => { + // ... + }) + ``` + + The following figure shows the effect. When you click **Open PDF**, a dialog box is displayed for you to select. + + uiability-intra-device-interaction + +3. To stop the **UIAbility** instance after the document application is used, call **terminateSelf()**. + + ```ts + // context is the ability context of the UIAbility instance to stop. + this.context.terminateSelf((err) => { + // ... + }); + ``` + + +## Starting UIAbility of Another Application and Obtaining the Return Result + +If you want to obtain the return result when using implicit Want to start the UIAbility of another application, use the **startAbilityForResult()** method. An example scenario is that the main application needs to start a third-party payment application and obtain the payment result. + +1. In the **module.json5** file of the UIAbility corresponding to the payment application, set [entities](../reference/apis/js-apis-ability-wantConstant.md#wantconstantentity) and [actions](../reference/apis/js-apis-ability-wantConstant.md#wantconstantaction) under **skills**. + + ```json + { + "module": { + "abilities": [ + { + // ... + "skills": [ + { + "entities": [ + // ... + "entity.system.default" + ], + "actions": [ + // ... + "ohos.want.action.editData" + ] + } + ] + } + ] + } + } + ``` + +2. Call the **startAbilityForResult()** method to start the UIAbility of the payment application. Include **entities** and **actions** of the caller's **want** parameter into **entities** and **actions** under **skills** of the target UIAbility. Use **data** in the asynchronous callback to receive the information returned to the caller after the payment UIAbility stops itself. After the system matches the UIAbility that meets the **entities** and **actions** information, a dialog box is displayed, showing the list of matched UIAbility instances for users to select. + + ```ts + let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + // Uncomment the line below if you want to implicitly query data only in the specific bundle. + // bundleName: 'com.example.myapplication', + action: 'ohos.want.action.editData', + // entities can be omitted. + entities: ['entity.system.default'], + } + + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(wantInfo).then((data) => { + // ... + }).catch((err) => { + // ... + }) + ``` + +3. After the payment is finished, call the **terminateSelfWithResult()** method to stop the payment UIAbility and return the **abilityResult** parameter. + + ```ts + const RESULT_CODE: number = 1001; + let abilityResult = { + resultCode: RESULT_CODE, + want: { + bundleName: 'com.example.myapplication', + abilityName: 'EntryAbility', + moduleName: 'entry', + parameters: { + payResult: 'OKay', + }, + }, + } + // context is the ability context of the callee UIAbility. + this.context.terminateSelfWithResult(abilityResult, (err) => { + // ... + }); + ``` + +4. Receive the information returned by the payment application in the callback of the **startAbilityForResult()** method. The value of **RESULT_CODE** must be the same as that returned by **terminateSelfWithResult()**. + + ```ts + const RESULT_CODE: number = 1001; + + let want = { + // Want parameter information. + }; + + // context is the ability-level context of the initiator UIAbility. + this.context.startAbilityForResult(want).then((data) => { + if (data?.resultCode === RESULT_CODE) { + // Parse the information returned by the callee UIAbility. + let payResult = data.want?.parameters?.payResult; + // ... + } + }).catch((err) => { + // ... + }) + ``` + + +## Starting a Specified Page of UIAbility + +A UIAbility component can have multiple pages. When it is started in different scenarios, different pages can be displayed. For example, when a user jumps from a page of a UIAbility component to another UIAbility, you want to start a specified page of the target UIAbility. This section describes how to specify a startup page and start the specified page when the target UIAbility is started for the first time or when the target UIAbility is not started for the first time. + + +### Specifying a Startup Page + +When the caller UIAbility starts another UIAbility, it usually needs to redirect to a specified page. For example, FuncAbility contains two pages: Index (corresponding to the home page) and Second (corresponding to function A page). You can configure the specified page URL in the **want** parameter by adding a custom parameter to **parameters** in **want**. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). + + +```ts +let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + moduleName: 'module1', // moduleName is optional. + parameters: {// Custom parameter used to pass the page information. + router: 'funcA', + }, +} +// context is the ability-level context of the initiator UIAbility. +this.context.startAbility(wantInfo).then(() => { + // ... +}).catch((err) => { + // ... +}) +``` + + +### Starting a Page When the Target UIAbility Is Started for the First Time + +When the target UIAbility is started for the first time, in the **onWindowStageCreate()** callback of the target UIAbility, parse the **want** parameter passed by EntryAbility to obtain the URL of the page to be loaded, and pass the URL to the **windowStage.loadContent()** method. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility' +import Window from '@ohos.window' + +export default class FuncAbility extends UIAbility { + funcAbilityWant; + + onCreate(want, launchParam) { + // Receive the parameters passed by the caller UIAbility. + this.funcAbilityWant = want; + } + + onWindowStageCreate(windowStage: Window.WindowStage) { + // Main window is created. Set a main page for this ability. + let url = 'pages/Index'; + if (this.funcAbilityWant?.parameters?.router) { + if (this.funcAbilityWant.parameters.router === 'funA') { + url = 'pages/Second'; + } + } + windowStage.loadContent(url, (err, data) => { + // ... + }); + } +} +``` + + +### Starting a Page When the Target UIAbility Is Not Started for the First Time + +You start application A, and its home page is displayed. Then you return to the home screen and start application B. Now you need to start application A again from application B and have a specified page of application A displayed. An example scenario is as follows: When you open the home page of the SMS application and return to the home screen, the SMS application is in the opened state and its home page is displayed. Then you open the home page of the Contacts application, access user A's details page, and touch the SMS icon to send an SMS message to user A. The SMS application is started again and the sending page is displayed. + +![uiability_not_first_started](figures/uiability_not_first_started.png) + +In summary, when a UIAbility instance of application A has been created and the main page of the UIAbility instance is displayed, you need to start the UIAbility of application A from application B and have a different page displayed. + +1. In the target UIAbility, the **Index** page is loaded by default. The UIAbility instance has been created, and the **onNewWant()** callback rather than **onCreate()** and **onWindowStageCreate()** will be invoked. In the **onNewWant()** callback, parse the **want** parameter and bind it to the global variable **globalThis**. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility' + + export default class FuncAbility extends UIAbility { + onNewWant(want, launchParam) { + // Receive the parameters passed by the caller UIAbility. + globalThis.funcAbilityWant = want; + // ... + } + } + ``` + +2. In FuncAbility, use the router module to implement redirection to the specified page on the **Index** page. Because the **Index** page of FuncAbility is active, the variable will not be declared again and the **aboutToAppear()** callback will not be triggered. Therefore, the page routing functionality can be implemented in the **onPageShow()** callback of the **Index** page. + + ```ts + import router from '@ohos.router'; + + @Entry + @Component + struct Index { + onPageShow() { + let funcAbilityWant = globalThis.funcAbilityWant; + let url2 = funcAbilityWant?.parameters?.router; + if (url2 && url2 === 'funcA') { + router.replaceUrl({ + url: 'pages/Second', + }) + } + } + + // Page display. + build() { + // ... + } + } + ``` + +> **NOTE** +> +> When the [launch type of the callee UIAbility](uiability-launch-type.md) is set to **standard**, a new instance is created each time the callee UIAbility is started. In this case, the [onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant) callback will not be invoked. + + +## Using Ability Call to Implement UIAbility Interaction + +This feature applies only to system applications. Ability call is an extension of the UIAbility capability. It enables the UIAbility to be invoked by and communicate with external systems. The UIAbility invoked can be either started in the foreground or created and run in the background. You can use the ability call to implement data sharing between two UIAbility instances (caller ability and callee ability) through IPC. + +The core API used for the ability call is **startAbilityByCall**, which differs from **startAbility** in the following ways: + +- **startAbilityByCall** supports ability launch in the foreground and background, whereas **startAbility** supports ability launch in the foreground only. + +- The caller ability can use the caller object returned by **startAbilityByCall** to communicate with the callee ability, but **startAbility** does not provide the communication capability. + +Ability call is usually used in the following scenarios: + +- Communicating with the callee ability + +- Starting the callee ability in the background + +**Table 1** Terms used in the ability call + +| **Term**| Description| +| -------- | -------- | +| CallerAbility | UIAbility that triggers the ability call.| +| CalleeAbility | UIAbility invoked by the ability call.| +| Caller | Object returned by **startAbilityByCall** and used by the caller ability to communicate with the callee ability.| +| Callee | Object held by the callee ability to communicate with the caller ability.| + +The following figure shows the ability call process. + +**Figure 1** Ability call process + +call + +- The caller ability uses **startAbilityByCall** to obtain a caller object and uses **call()** of the caller object to send data to the callee ability. + +- The callee ability, which holds a **Callee** object, uses **on()** of the **Callee** object to register a callback. This callback is invoked when the callee ability receives data from the caller ability. + +> **NOTE** +> 1. Currently, only system applications can use the ability call. +> +> 2. The launch type of the callee ability must be **singleton**. +> +> 3. Both local (intra-device) and cross-device ability calls are supported. The following describes how to initiate a local call. For details about how to initiate a cross-device ability call, see [Using Cross-Device Ability Call](hop-multi-device-collaboration.md#using-cross-device-ability-call). + + +### Available APIs + +The following table describes the main APIs used for the ability call. For details, see [AbilityContext](../reference/apis/js-apis-app-ability-uiAbility.md#caller). + +**Table 2** Ability call APIs + +| API| Description| +| -------- | -------- | +| startAbilityByCall(want: Want): Promise<Caller> | Starts a UIAbility in the foreground (through the **want** configuration) or background (default) and obtains the caller object for communication with the UIAbility. For details, see [AbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilitybycall) or [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartabilitybycall).| +| on(method: string, callback: CalleeCallBack): void | Callback invoked when the callee ability registers a method.| +| off(method: string): void | Callback invoked when the callee ability deregisters a method.| +| call(method: string, data: rpc.Sequenceable): Promise<void> | Sends agreed sequenceable data to the callee ability.| +| callWithResult(method: string, data: rpc.Sequenceable): Promise<rpc.MessageParcel> | Sends agreed sequenceable data to the callee ability and obtains the agreed sequenceable data returned by the callee ability.| +| release(): void | Releases the caller object.| +| on(type: "release", callback: OnReleaseCallback): void | Callback invoked when the caller object is released.| + +The implementation of using the ability call for UIAbility interaction involves two parts. + +- [Creating a Callee Ability](#creating-a-callee-ability) + +- [Accessing the Callee Ability](#accessing-the-callee-ability) + + +### Creating a Callee Ability + +For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use **on()** to register a listener. When data does not need to be received, use **off()** to deregister the listener. + +1. Configure the ability launch type. + + Set **launchType** of the callee ability to **singleton** in the **module.json5** file. + +| JSON Field| Description| +| -------- | -------- | +| "launchType" | Ability launch type. Set this parameter to **singleton**.| + +An example of the ability configuration is as follows: + + + ```json + "abilities":[{ + "name": ".CalleeAbility", + "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", + "launchType": "singleton", + "description": "$string:CalleeAbility_desc", + "icon": "$media:icon", + "label": "$string:CalleeAbility_label", + "visible": true + }] + ``` + +2. Import the **UIAbility** module. + + ```ts + import Ability from '@ohos.app.ability.UIAbility'; + ``` + +3. Define the agreed sequenceable data. + + The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string. + + + ```ts + export default class MySequenceable { + num: number = 0 + str: string = "" + + constructor(num, string) { + this.num = num + this.str = string + } + + marshalling(messageParcel) { + messageParcel.writeInt(this.num) + messageParcel.writeString(this.str) + return true + } + + unmarshalling(messageParcel) { + this.num = messageParcel.readInt() + this.str = messageParcel.readString() + return true + } + } + ``` + +4. Implement **Callee.on** and **Callee.off**. + + The time to register a listener for the callee ability depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the **MSG_SEND_METHOD** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The sample code is as follows: + + + ```ts + const TAG: string = '[CalleeAbility]'; + const MSG_SEND_METHOD: string = 'CallSendMsg'; + + function sendMsgCallback(data) { + console.info('CalleeSortFunc called'); + + // Obtain the sequenceable data sent by the caller ability. + let receivedData = new MySequenceable(0, ''); + data.readSequenceable(receivedData); + console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`); + + // Process the data. + // Return the sequenceable data result to the caller ability. + return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`); + } + + export default class CalleeAbility extends Ability { + onCreate(want, launchParam) { + try { + this.callee.on(MSG_SEND_METHOD, sendMsgCallback); + } catch (error) { + console.info(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`); + } + } + + onDestroy() { + try { + this.callee.off(MSG_SEND_METHOD); + } catch (error) { + console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`); + } + } + } + ``` + + +### Accessing the Callee Ability + +1. Import the **UIAbility** module. + + ```ts + import Ability from '@ohos.app.ability.UIAbility'; + ``` + +2. Obtain the caller interface. + + The **context** attribute of the ability implements **startAbilityByCall** to obtain the caller object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the caller object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements. + + + ```ts + // Register the onRelease() listener of the caller ability. + private regOnRelease(caller) { + try { + caller.on("release", (msg) => { + console.info(`caller onRelease is called ${msg}`); + }) + console.info('caller register OnRelease succeed'); + } catch (error) { + console.info(`caller register OnRelease failed with ${error}`); + } + } + + async onButtonGetCaller() { + try { + this.caller = await context.startAbilityByCall({ + bundleName: 'com.samples.CallApplication', + abilityName: 'CalleeAbility' + }) + if (this.caller === undefined) { + console.info('get caller failed') + return + } + console.info('get caller success') + this.regOnRelease(this.caller) + } catch (error) { + console.info(`get caller failed with ${error}`) + } + } + ``` diff --git a/en/application-dev/application-models/uiability-launch-type.md b/en/application-dev/application-models/uiability-launch-type.md new file mode 100644 index 0000000000000000000000000000000000000000..cda8307ddd3dae6f7cceac3fad134ef510d7383c --- /dev/null +++ b/en/application-dev/application-models/uiability-launch-type.md @@ -0,0 +1,162 @@ +# UIAbility Component Launch Type + + +The launch type of the UIAbility component refers to the state of the UIAbility instance at startup. The system provides three launch types: + + +- [Singleton](#singleton) + +- [Standard](#standard) + +- [Specified](#specified) + + +## Singleton + +**singleton** is the default launch type. + +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 + +> **NOTE** +> +> Assume that the application already has a UIAbility instance created, and the launch type of the UIAbility instance is set to **singleton**. If [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called again to start the 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. + +To use the singleton mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **singleton**. + + +```json +{ + "module": { + // ... + "abilities": [ + { + "launchType": "singleton", + // ... + } + ] + } +} +``` + + +## Standard + +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**. + +**Figure 2** Demonstration effect in standard mode + +standard-mode + +To use the standard mode, set **launchType** in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **standard**. + + +```json +{ + "module": { + // ... + "abilities": [ + { + "launchType": "standard", + // ... + } + ] + } +} +``` + + +## Specified + +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 + +For example, there are EntryAbility and SpecifiedAbility, and the launch type of SpecifiedAbility is set to **specified**. You are required to start SpecifiedAbility from EntryAbility. + +1. In SpecifiedAbility, set the **launchType** field in the [module.json5 configuration file](../quick-start/module-configuration-file.md) to **specified**. + + ```json + { + "module": { + // ... + "abilities": [ + { + "launchType": "specified", + // ... + } + ] + } + } + ``` + +2. Before a UIAbility instance is created, you can create a unique string key for the instance. The key is bound to the UIAbility instance when it is created. Each time [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) is called, the application is asked which UIAbility instance is used to respond to the [startAbility()](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability) 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 instances. + + ```ts + // Configure an independent key for each UIAbility instance. + // For example, in the document usage scenario, use the document path as the key. + function getInstance() { + // ... + } + + let want = { + deviceId: '', // An empty deviceId indicates the local device. + bundleName: 'com.example.myapplication', + abilityName: 'SpecifiedAbility', + moduleName: 'module1', // moduleName is optional. + parameters: {// Custom information. + instanceKey: getInstance(), + }, + } + // context is the ability-level context of the initiator UIAbility. + this.context.startAbility(want).then(() => { + // ... + }).catch((err) => { + // ... + }) + ``` + +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. + + ```ts + import AbilityStage from '@ohos.app.ability.AbilityStage'; + + export default class MyAbilityStage extends AbilityStage { + onAcceptWant(want): string { + // In the AbilityStage instance of the callee, a key value corresponding to a UIAbility instance is returned for UIAbility whose launch type is specified. + // In this example, SpecifiedAbility of module1 is returned. + if (want.abilityName === 'SpecifiedAbility') { + // The returned string key is a custom string. + return `SpecifiedAbilityInstance_${want.parameters.instanceKey}`; + } + + return ''; + } + } + ``` + + > **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 key values are bound to different document instances. Each time a document is created, a new key value (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. + 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 diff --git a/en/application-dev/application-models/uiability-lifecycle.md b/en/application-dev/application-models/uiability-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..9ec701cbffd4da51098d5dc448addd88f26ee47e --- /dev/null +++ b/en/application-dev/application-models/uiability-lifecycle.md @@ -0,0 +1,147 @@ +# UIAbility Component Lifecycle + + +## Overview + +When a user opens, switches, and returns to an application, the UIAbility instances in the application transit in their different states. The UIAbility class provides a series of callbacks. Through these callbacks, you can know the state changes of the UIAbility instance, for example, being created or destroyed, or running in the foreground or background. + +The lifecycle of UIAbility has four states: **Create**, **Foreground**, **Background**, and **Destroy**, as shown in the figure below. + +**Figure 1** UIAbility lifecycle states +Ability-Life-Cycle + + +## Description of Lifecycle States + + +### Create + +The **Create** state is triggered when the UIAbility instance is created during application loading. The system invokes the **onCreate()** callback. In this callback, you can perform application initialization operations, for example, defining variables or loading resources. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + // Initialize the application. + } + // ... +} +``` + + +### WindowStageCreate and WindowStageDestory + +After the UIAbility instance is created but before it enters the **Foreground** state, the system creates a WindowStage instance and triggers the **onWindowStageCreate()** callback. You can set UI loading and WindowStage event subscription in the callback. + +**Figure 2** WindowStageCreate and WindowStageDestory +Ability-Life-Cycle-WindowStage + +In the **onWindowStageCreate()** callback, use [loadContent()](../reference/apis/js-apis-window.md#loadcontent9-2) to set the page to be loaded, and call [on('windowStageEvent')](../reference/apis/js-apis-window.md#onwindowstageevent9) to subscribe to [WindowStage events](../reference/apis/js-apis-window.md#windowstageeventtype9), for example, having or losing focus, or becoming visible or invisible. + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +export default class EntryAbility extends UIAbility { + // ... + + onWindowStageCreate(windowStage: Window.WindowStage) { + // Subscribe to the WindowStage events (having or losing focus, or becoming visible or invisible). + try { + windowStage.on('windowStageEvent', (data) => { + console.info('Succeeded in enabling the listener for window stage event changes. Data: ' + + JSON.stringify(data)); + }); + } catch (exception) { + console.error('Failed to enable the listener for window stage event changes. Cause:' + + JSON.stringify(exception)); + }; + + // Set the UI loading. + windowStage.loadContent('pages/Index', (err, data) => { + // ... + }); + } +} +``` + +> **NOTE** +> +> For details about how to use WindowStage, see [Window Development](../windowmanager/application-window-stage.md). + +Before the UIAbility instance is destroyed, the **onWindowStageDestroy()** callback is invoked to release UI resources. In this callback, you can unsubscribe from the WindowStage events. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +export default class EntryAbility extends UIAbility { + // ... + + onWindowStageDestroy() { + // Release UI resources. + // Unsubscribe from the WindowStage events such as having or losing focus in the onWindowStageDestroy() callback. + try { + windowStage.off('windowStageEvent'); + } catch (exception) { + console.error('Failed to disable the listener for window stage event changes. Cause:' + + JSON.stringify(exception)); + }; + } +} +``` + + +### Foreground and Background + +The **Foreground** and **Background** states are triggered when the UIAbility instance is switched to the foreground and background respectively. They correspond to the **onForeground()** and **onBackground()** callbacks. + +The **onForeground()** callback is triggered before the UI of the UIAbility instance becomes visible, for example, when the UIAbility instance is switched to the foreground. In this callback, you can apply for resources required by the system or re-apply for resources that have been released in the **onBackground()** callback. + +The **onBackground()** callback is triggered after the UI of the UIAbility component is completely invisible, for example, when the UIAbility instance is switched to the background. In this callback, you can release useless resources or perform time-consuming operations such as saving the status. + +For example, an application needs to use positioning, and the application has requested the positioning permission from the user. Before the UI is displayed, you can enable positioning in the **onForeground()** callback to obtain the location information. + +When the application is switched to the background, you can disable positioning in the **onBackground()** callback to reduce system resource consumption. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; + +export default class EntryAbility extends UIAbility { + // ... + + onForeground() { + // Apply for the resources required by the system or re-apply for the resources released in onBackground(). + } + + onBackground() { + // Release useless resources when the UI is invisible, or perform time-consuming operations in this callback, + // for example, saving the status. + } +} +``` + + +### Destroy + +The **Destroy** state is triggered when the UIAbility instance is destroyed. You can perform operations such as releasing system resources and saving data in the **onDestroy()** callback. + +The UIAbility instance is destroyed when **terminateSelf()** is called or the user closes the instance in **Recents**. + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +export default class EntryAbility extends UIAbility { + // ... + + onDestroy() { + // Release system resources and save data. + } +} +``` diff --git a/en/application-dev/application-models/uiability-overview.md b/en/application-dev/application-models/uiability-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..14cb5c4652749c97dd6e50c4232b6f65fb6feaab --- /dev/null +++ b/en/application-dev/application-models/uiability-overview.md @@ -0,0 +1,39 @@ +# UIAbility Component Overview + + +## Overview + +UIAbility has the UI and is mainly used for user interaction. + +UIAbility is the basic unit scheduled by the system and provides a window for applications to draw UIs. A UIAbility component can implement a functional module through multiple pages. Each UIAbility component instance corresponds to a mission in **Recents**. + + +## Privacy Statement Configuration + +To enable an application to properly use a UIAbility component, declare the UIAbility name, entry, and tags under [abilities](../quick-start/module-configuration-file.md#abilities) in the [module.json5 configuration file](../quick-start/module-configuration-file.md). + + +```json +{ + "module": { + // ... + "abilities": [ + { + "name": "EntryAbility", // Name of the UIAbility component. + "srcEntrance": "./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. + "startWindowIcon": "$media:icon", // Index of the icon resource file. + "startWindowBackground": "$color:start_window_background", // Index of the background color resource file. + // ... + } + ] + } +} +``` + +> **NOTE** +> +> For the ability composition, see [Adding an Ability to a Module](https://developer.harmonyos.com/en/docs/documentation/doc-guides-V3/ohos-adding-ability-0000001218280664-V3). + diff --git a/en/application-dev/application-models/uiability-usage.md b/en/application-dev/application-models/uiability-usage.md new file mode 100644 index 0000000000000000000000000000000000000000..fa8badc6d48c7e550922cb60a15d02eab9cc80b6 --- /dev/null +++ b/en/application-dev/application-models/uiability-usage.md @@ -0,0 +1,99 @@ +# UIAbility Component Usage + + +When using the UIAbility component, you must specify a startup page and obtain the context, [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md). + + +## Specifying the Startup Page of UIAbility + +If no startup page is specified, a white screen occurs after the application is started. You can use **loadContent()** of [WindowStage](../reference/apis/js-apis-window.md#windowstage9) to set the startup page in the **onWindowStageCreate()** callback of the UIAbility instance. + + +```ts +import UIAbility from '@ohos.app.ability.UIAbility'; +import window from '@ohos.window'; + +export default class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage: window.WindowStage) { + // Main window is created. Set a main page for this ability. + windowStage.loadContent('pages/Index', (err, data) => { + // ... + }); + } + + // ... +} +``` + +> **NOTE** +> +> When you create UIAbility in DevEco Studio, the UIAbility instance loads the **Index** page by default. Therefore, you only need to replace the **Index** page path with the required startup page path. + + +## Obtaining the Context of UIAbility + +The UIAbility class has its own context, which is an instance of the [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md) class. The UIAbilityContext class has attributes such as **abilityInfo** and **currentHapModuleInfo**. UIAbilityContext can be used to obtain the UIAbility configuration information, such as the bundle code path, bundle name, ability name, and environment status required by the application. It can also be used to obtain methods to operate the UIAbility instance, such as **startAbility()**, **connectServiceExtensionAbility()**, and **terminateSelf()**. + +- You can use **this.context** to obtain the context of a UIAbility instance. + + ```ts + import UIAbility from '@ohos.app.ability.UIAbility'; + + export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + // Obtain the context of the UIAbility instance. + let context = this.context; + + // ... + } + } + ``` + +- Import the context module and define the **context** variable in the component. + + ```ts + import common from '@ohos.app.ability.common'; + + @Entry + @Component + struct Index { + private context = getContext(this) as common.UIAbilityContext; + + startAbilityTest() { + let want = { + // Want parameter information. + }; + this.context.startAbility(want); + } + + // Page display. + build() { + // ... + } + } + ``` + + You can also define variables after importing the context module but before using [UIAbilityContext](../reference/apis/js-apis-inner-application-uiAbilityContext.md). + + + ```ts + import common from '@ohos.app.ability.common'; + + @Entry + @Component + struct Index { + + startAbilityTest() { + let context = getContext(this) as common.UIAbilityContext; + let want = { + // Want parameter information. + }; + context.startAbility(want); + } + + // Page display. + build() { + // ... + } + } + ``` diff --git a/en/application-dev/application-models/want-fa.md b/en/application-dev/application-models/want-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..5ef82daf1f6ac353200131fd8195cbea35725e3c --- /dev/null +++ b/en/application-dev/application-models/want-fa.md @@ -0,0 +1,4 @@ +# Want (FA Model) + + +For details, see "[Want](want-overview.md)" in the stage model. diff --git a/en/application-dev/application-models/want-overview.md b/en/application-dev/application-models/want-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..f8239c64cf43a0df0acca0bc1ec0e3be914eecfe --- /dev/null +++ b/en/application-dev/application-models/want-overview.md @@ -0,0 +1,49 @@ +# Want Overview + + +## Definition and Usage of Want + +[Want](../reference/apis/js-apis-app-ability-want.md) is used as the carrier to transfer information between application components. It is used as a parameter of **startAbility()** to specify the startup target and information that needs to be carried during startup, for example, **bundleName** and **abilityName**, which respectively indicate the bundle name of the target ability and the ability name in the bundle. For example, when UIAbilityA starts UIAbilityB and needs to transfer some data to UIAbilityB, it can use Want to transfer the data. + +**Figure 1** Want usage +usage-of-want + + +## Types of Want + +- **Explicit Want**: A type of Want with **abilityName** and **bundleName** specified when starting an ability. + When there is an explicit object to process the request, the target ability can be started by specifying the bundle name and ability name in Want. Explicit Want is usually used to start a known ability. + + ```ts + let wantInfo = { + deviceId: '', // An empty deviceId indicates the local device. + bundleName: 'com.example.myapplication', + abilityName: 'FuncAbility', + } + ``` + +- **Implicit Want**: A type of Want with **abilityName** unspecified when starting the ability. + Implicit Want can be used when the object used to process the request is unclear and the current application wants to use a capability (defined by the [skills tag](../quick-start/module-configuration-file.md#skills)) provided by another application. For example, you can use implicit Want to describe a request for opening a link, since you do not care which application is used to open the link. The system matches all applications that support the request. + + + ```ts + let wantInfo = { + // Uncomment the line below if you want to implicitly query data only in the specific bundle. + // bundleName: 'com.example.myapplication', + action: 'ohos.want.action.search', + // entities can be omitted. + entities: [ 'entity.system.browsable' ], + uri: 'https://www.test.com:8080/query/student', + type: 'text/plain', + }; + ``` + + > **NOTE** + > - Depending on the ability matching result, the following cases may be possible when you attempt to use implicit Want to start the ability. + > - No ability is matched. The startup fails. + > - An ability that meets the conditions is matched. That ability is started. + > - Multiple abilities that meet the conditions are matched. A dialog box is displayed for users to select one of them. + > + > - If the **want** parameter passed does not contain **abilityName** or **bundleName**, the ServiceExtensionAbility components of all applications cannot be started through implicit Want. + > + > - If the **want** parameter passed contains **bundleName**, the **startServiceExtensionAbility()** method can be used to implicitly start ServiceExtensionAbility. By default, ServiceExtensionAbility with the highest priority is returned. If all the matching ServiceExtensionAbility components have the same priority, the first ServiceExtensionAbility is returned. diff --git a/en/application-dev/application-models/widget-development-fa.md b/en/application-dev/application-models/widget-development-fa.md new file mode 100644 index 0000000000000000000000000000000000000000..df162455f63272a817d0a7773d150419011a7467 --- /dev/null +++ b/en/application-dev/application-models/widget-development-fa.md @@ -0,0 +1,546 @@ +# Widget Development + + +## 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) and provides basic interactive features such as opening a UI page or sending a message. + +Before you get started, it would be helpful if you have a basic understanding of the following concepts: + +- Widget host: an application that displays the widget content and controls the widget location. + +- Widget Manager: a resident agent that provides widget management features such as periodic widget updates. + +- Widget provider: an atomic service that provides the widget content to display and controls how widget components are laid out and how they interact with users. + + +## Working Principles + +Figure 1 shows the working principles of the widget framework. + +**Figure 1** Widget framework working principles in the FA model +![form-extension](figures/form-extension.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 **FormAbility** has the following APIs. + +| API| Description| +| -------- | -------- | +| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a widget has been created.| +| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| +| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated.| +| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility.| +| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event.| +| onDestroy(formId: string): void | Called to notify the widget provider that a widget has been destroyed.| +| onAcquireFormState?(want: Want): formInfo.FormState | Called to instruct the widget provider to receive the status query result of a widget.| +| onShare?(formId: string): {[key: string]: any} | Called by the widget provider to receive shared widget data.| + +The **FormProvider** class has the following APIs. For details, see [FormProvider](../reference/apis/js-apis-app-form-formProvider.md). + + +| API| Description| +| -------- | -------- | +| 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). + + +| API| Description| +| -------- | -------- | +| createFormBindingData(obj?: Object \ string): FormBindingData| | Creates a **FormBindingData** object.| + + +## How to Develop + +The widget provider development based on the [FA model](fa-model-development-overview.md) involves the following key steps: + +- [Implementing Widget Lifecycle Callbacks](#implementing-widget-lifecycle-callbacks): Develop the **FormAbility** lifecycle callback functions. + +- [Configuring the Widget Configuration File](#configuring-the-widget-configuration-file): Configure the application configuration file **config.json**. + +- [Persistently Storing Widget Data](#persistently-storing-widget-data): Perform persistent management on widget information. + +- [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. + + +### Implementing Widget Lifecycle Callbacks + +To create a widget in the FA model, implement the widget lifecycle callbacks. 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 **form.ts**. + + ```ts + 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 widget lifecycle callbacks in **form.ts**. + + ```ts + export default { + onCreate(want) { + console.info('FormAbility onCreate'); + // 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; + }, + onCastToNormal(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('FormAbility onCastToNormal'); + }, + onUpdate(formId) { + // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. + console.info('FormAbility onUpdate'); + let obj = { + "title": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + formProvider.updateForm(formId, formData).catch((error) => { + console.info('FormAbility updateForm, error:' + JSON.stringify(error)); + }); + }, + onVisibilityChange(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('FormAbility onVisibilityChange'); + }, + onEvent(formId, message) { + // If the widget supports event triggering, override this method and implement the trigger. + console.info('FormAbility onEvent'); + }, + onDestroy(formId) { + // Delete widget data. + console.info('FormAbility onDestroy'); + }, + onAcquireFormState(want) { + console.info('FormAbility onAcquireFormState'); + return formInfo.FormState.READY; + }, + } + ``` + +> **NOTE** +> +> FormAbility cannot reside in the background. Therefore, continuous tasks cannot be processed in the widget lifecycle callbacks. + +### Configuring the Widget Configuration File + +The widget configuration file is named **config.json**. Find the **config.json** file for the widget and edit the file depending on your need. + +- The **js** module in the **config.json** file provides JavaScript resources of the widget. The internal structure is described as follows: + | Name| Description| Data Type| Initial Value Allowed| + | -------- | -------- | -------- | -------- | + | name | Name of a JavaScript component. The default value is **default**.| String| No| + | pages | Route information about all pages in the JavaScript component, including the page path and page name. The value is an array, in which each element represents a page. The first element in the array represents the home page of the JavaScript FA.| Array| No| + | window | Window-related configurations.| Object| Yes| + | type | Type of the JavaScript component. The value can be:
**normal**: indicates an application instance.
**form**: indicates a widget instance.| String| Yes (initial value: **normal**)| + | mode | Development mode of the JavaScript component.| Object| Yes (initial value: left empty)| + + A configuration example is as follows: + + + ```json + "js": [{ + "name": "widget", + "pages": ["pages/index/index"], + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + "type": "form" + }] + ``` + +- The **abilities** module in the **config.json** file corresponds to **FormAbility** of the widget. The internal structure is described as follows: + | Name| Description| Data Type| Initial Value Allowed| + | -------- | -------- | -------- | -------- | + | name | Class name of a 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)| + | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean| No| + | type | Type of the widget. The value can be:
**JS**: indicates a JavaScript-programmed widget.| String| No| + | colorMode | Color mode of the widget.
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String| Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget.
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No| + | 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 attribute 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)| + | jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes.| String| No| + | metaData | Metadata of the widget. This attribute contains the array of the **customizeData** attribute.| Object| Yes (initial value: left empty)| + | customizeData | Custom information about the widget.| Object array| Yes (initial value: left empty)| + + A configuration example is as follows: + + + ```json + "abilities": [{ + "name": "FormAbility", + "description": "This is a FormAbility", + "formsEnabled": true, + "icon": "$media:icon", + "label": "$string:form_FormAbility_label", + "srcPath": "FormAbility", + "type": "service", + "srcLanguage": "ets", + "formsEnabled": true, + "formConfigAbility": "ability://com.example.entry.EntryAbility", + "forms": [{ + "colorMode": "auto", + "defaultDimension": "2*2", + "description": "This is a service widget.", + "formVisibleNotify": true, + "isDefault": true, + "jsComponentName": "widget", + "name": "widget", + "scheduledUpdateTime": "10:30", + "supportDimensions": ["2*2"], + "type": "JS", + "updateEnabled": true + }] + }] + ``` + + +### 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 the widget information. + await storage.put(formId, JSON.stringify(formInfo)); + console.info(`storeFormInfo, put form info successfully, formId: ${formId}`); + await storage.flush(); + } catch (err) { + console.error(`failed to storeFormInfo, err: ${JSON.stringify(err)}`); + } +} + +// ... + onCreate(want) { + console.info('FormAbility onCreate'); + + 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 information 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 **onDestroy** 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); + // Delete the widget information. + await storage.delete(formId); + console.info(`deleteFormInfo, del form info successfully, formId: ${formId}`); + await storage.flush(); + } catch (err) { + console.error(`failed to deleteFormInfo, err: ${JSON.stringify(err)}`); + } +} + +// ... + onDestroy(formId) { + console.info('FormAbility onDestroy'); + // Delete the persistent widget instance data. + // Implement this API based on project requirements. + deleteFormInfo(formId); + } +// ... +``` + +For details about how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). + +The **Want** object passed 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 +onUpdate(formId) { + // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. + console.info('FormAbility onUpdate'); + 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('FormAbility 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. + +![widget-development-fa](figures/widget-development-fa.png) + +> **NOTE** +> +> 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. + + ```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": "com.example.entry.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 ability redirection, and the message event applies to custom click events. The key steps are as follows: + +1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. + +2. Set the router event. + - **action**: **router**, which indicates a router event. + - **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name 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. + +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 **onEvent**. + +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": "com.example.entry.EntryAbility", + "params": { + "message": "add detail" + } + }, + "messageEvent": { + "action": "message", + "params": { + "message": "add detail" + } + } + } + } + ``` + diff --git a/en/application-dev/application-models/widget-development-stage.md b/en/application-dev/application-models/widget-development-stage.md new file mode 100644 index 0000000000000000000000000000000000000000..32aa03e7aaea833a41b948764ca225c605adf24b --- /dev/null +++ b/en/application-dev/application-models/widget-development-stage.md @@ -0,0 +1,599 @@ +# FormExtensionAbility (Widget) + + +## Widget Overview + +FormExtensionAbility provides a service widget (also called widget), which is a set of UI components that display important information or operations specific to an application. It provides users with direct access to a desired application service, without the need to open the application first. + +A widget usually appears as a part of the UI of another application (which currently can only be a system application) and provides basic interactive features such as opening a UI page or sending a message. + +Before you get started, it would be helpful if you have a basic understanding of the following concepts: + +- Widget host: an application that displays the widget content and controls the widget location. + +- Widget Manager: a resident agent that provides widget management features such as periodic widget updates. + +- Widget provider: an atomic service that provides the widget content to display and controls how widget components are laid out and how they interact with users. + + +## Working Principles + +Figure 1 shows the working principles of the widget framework. + +**Figure 1** Widget framework working principles in the stage model +![form-extension](figures/form-extension.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). + +| API| 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 **FormExtensionAbility** class also has a member context, that is, the FormExtensionContext class. For details, see [FormExtensionContext](../reference/apis/js-apis-inner-application-formExtensionContext.md). + +| API| Description| +| -------- | -------- | +| startAbility(want: Want, callback: AsyncCallback<void>): void | Starts UIAbility of the application to which a widget belongs. This API uses an asynchronous callback to return the result. (This is a system API and cannot be called by third-party applications. You must apply for the permission to use the API.)| +| startAbility(want: Want): Promise<void> | Starts UIAbility of the application to which a widget belongs. This API uses a promise to return the result. (This is a system API and cannot be called by third-party applications. You must apply for the permission to use the API.)| + +The **FormProvider** class has the following APIs. For details, see [FormProvider](../reference/apis/js-apis-app-form-formProvider.md). + +| API| 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). + +| API| 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 File](#configuring-the-widget-configuration-file): Configure the application configuration file **module.json5** and profile configuration file. + +- [Persistently Storing Widget Data](#persistently-storing-widget-data): Perform persistent management on widget information. + +- [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 FormExtension 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 FormExtension { + 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 File + +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. + A configuration example is as follows: + + + ```json + { + "module": { + // ... + "extensionAbilities": [ + { + "name": "EntryFormAbility", + "srcEntrance": "./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| Initial Value Allowed| + | -------- | -------- | -------- | -------- | + | name | Class name of a widget. The value is a string with a maximum of 127 bytes.| String| No| + | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String| Yes (initial value: left empty)| + | src | Full path of the UI code corresponding to the widget.| String| No| + | window | Window-related configurations.| Object| Yes| + | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean| No| + | colorMode | Color mode of the widget.
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String| Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget.
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No| + | 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 attribute 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 attribute contains the array of the **customizeData** attribute.| Object| Yes (initial value: left empty)| + + A configuration example is as follows: + + ```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 the widget information. + 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 information 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); + // Delete the widget information. + 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 how to implement persistent data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). + +The **Want** object passed 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. + +![widget-development-stage](figures/widget-development-stage.png) + +> **NOTE** +> +> 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. + + ```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 ability redirection, and the message event applies to custom click events. + +The key steps are as follows: + +1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. + +2. Set the router event. + - **action**: **router**, which indicates a router event. + - **abilityName**: name of the ability to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name of the stage model created by DevEco Studio is EntryAbility. + - **params**: custom parameters passed to the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field. + +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) { + // Obtain the info parameter passed in the router event. + if (want.parameters.info === "router info") { + // Do something. + // console.log("router info:" + want.parameters.info) + } + // Obtain the message parameter passed in the router event. + if (want.parameters.message === "router message") { + // Do something. + // console.log("router message:" + want.parameters.message) + } + } + // ... + }; + ``` + +- Receive the message event in FormExtensionAbility and obtain parameters. + + ```ts + import FormExtension from '@ohos.app.form.FormExtensionAbility'; + + export default class FormAbility extends FormExtension { + // ... + onFormEvent(formId, message) { + // Obtain the detail parameter passed in the message event. + let msg = JSON.parse(message) + if (msg.params.detail === "message detail") { + // Do something. + // console.log("message info:" + msg.params.detail) + } + } + // ... + }; + ``` + diff --git a/en/application-dev/application-models/widget-switch.md b/en/application-dev/application-models/widget-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..8d9823385a8a05f71c742327dc966054427a6718 --- /dev/null +++ b/en/application-dev/application-models/widget-switch.md @@ -0,0 +1,48 @@ +# Widget Switching + + +Widget switching involves the following parts: + + +- Widget UI layout: Both the FA model and stage model use the web-like paradigm to develop the widget UI layout. Therefore, the UI layout of a widget in the FA model can be directly reused in the stage mode. +- Widget configuration file: Widgets are configured in the **config.json** file in the FA model and in **module.json5** and **form_config.json** files in the stage model (as shown in Figure 1 and Figure 2). +- Widget service logic: The widget entry file and lifecycle of the FA model are slightly different from those of the stage model, as shown in Figure 3 and Figure 4. + +| 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. | +| 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 | +| Level-2 directory configuration tag| This configuration item is unavailable. | **metadata**, which consists of **name**, **value**, and **resource**, where **resource** points to the location of the **form_config.json** file in the level-2 directory.| + + +Figure 1 Entry configuration differences + + +![widget-switch1](figures/widget-switch1.png) + + +Figure 2 Widget configuration differences + + +![widget-switch2](figures/widget-switch2.png) + + +| Item| FA Model| Stage Model| +| -------- | -------- | -------- | +| Entry file| **form.ts** in the directory pointed to by **srcPath**| File pointed to by **srcEntrance**| +| Lifecycle| export default| import FormExtension from '\@ohos.app.form.FormExtensionAbility';
export default class FormAbility extends FormExtension| + + +Figure 3 Entry file differences + + +![widget-switch3](figures/widget-switch3.png) + + +Figure 4 Lifecycle differences (The lifecycle callbacks are the same and require no adjustment.) + + +![widget-switch4](figures/widget-switch4.png) diff --git a/en/application-dev/application-models/window-properties.md b/en/application-dev/application-models/window-properties.md new file mode 100644 index 0000000000000000000000000000000000000000..250476f05f7fc66b5deaa52ee2e4905f8de0edf6 --- /dev/null +++ b/en/application-dev/application-models/window-properties.md @@ -0,0 +1,4 @@ +# Window Properties + + +For details about the APIs for obtaining a window instance and setting window properties, see [Application Window Development (FA Model)](../windowmanager/application-window-fa.md). diff --git a/en/application-dev/application-models/window-switch.md b/en/application-dev/application-models/window-switch.md new file mode 100644 index 0000000000000000000000000000000000000000..379f0282b1e50e856d0010a9087622e2e1363d89 --- /dev/null +++ b/en/application-dev/application-models/window-switch.md @@ -0,0 +1,8 @@ +# window Switching + + +| API in the FA Model| Corresponding d.ts File in the Stage Model| Corresponding API in the Stage Model| +| -------- | -------- | -------- | +| [create(id: string, type: WindowType, callback: AsyncCallback<Window>): void;](../reference/apis/js-apis-window.md#windowcreatedeprecated)
[create(id: string, type: WindowType): Promise<Window>;](../reference/apis/js-apis-window.md#windowcreatedeprecated-1) | \@ohos.window.d.ts | [createSubWindow(name: string, callback: AsyncCallback<Window>): void;](../reference/apis/js-apis-window.md#createsubwindow9)
[createSubWindow(name: string): Promise;](../reference/apis/js-apis-window.md#createsubwindow9-1)
An application developed on the FA model uses **window.create(id, WindowType.TYPE_APP)** to create a subwindow, whereas an application developed on the stage model uses **WindowStage.CreateSubWindow()** to create a subwindow.| +| [getTopWindow(callback: AsyncCallback<Window>): void;](../reference/apis/js-apis-window.md#windowgettopwindowdeprecated)
[getTopWindow(): Promise<Window>;](../reference/apis/js-apis-window.md#windowgettopwindowdeprecated-1) | \@ohos.window.d.ts | [getLastWindow(ctx: BaseContext, callback: AsyncCallback<Window>): void;](../reference/apis/js-apis-window.md#windowgetlastwindow9)
[getLastWindow(ctx: BaseContext): Promise<Window>;](../reference/apis/js-apis-window.md#windowgetlastwindow9-1) | +