1# Page Ability Development 2 3## Overview 4### Concepts 5The Page ability implements the ArkUI and provides the capability of interacting with developers. When you create an ability in DevEco Studio, DevEco Studio automatically creates template code. The capabilities related to the Page ability are implemented through the **featureAbility**, and the lifecycle callbacks are implemented through the callbacks in **app.js** or **app.ets**. 6 7### Page Ability Lifecycle 8 9**Ability lifecycle** 10 11The Page ability lifecycle defines all states of a Page ability, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**. 12 13The following figure shows the lifecycle state transition of the Page ability. 14 15 16 17 18Description of ability lifecycle states: 19 20 - **UNINITIALIZED**: The Page ability is not initialized. This is a temporary state, from which a Page ability changes directly to the **INITIAL** state upon its creation. 21 22 - **INITIAL**: The Page ability is initialized but not running. The Page ability enters the **INACTIVE** state after it is started. 23 24 - **INACTIVE**: The Page ability is visible but does not gain focus. 25 26 - **ACTIVE**: The Page ability runs in the foreground and has focus. 27 28 - **BACKGROUND**: The Page ability runs in the background. After being re-activated, the Page ability enters the **ACTIVE** state. After being destroyed, the Page ability enters the **INITIAL** state. 29 30**The following figure shows the relationship between lifecycle callbacks and lifecycle states of the Page ability.** 31 32 33 34You can override the lifecycle callbacks provided by the Page ability in the **app.js** or **app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. 35 36### Launch Type 37The ability supports two launch types: singleton and multi-instance. 38You can specify the launch type by setting **launchType** in the **config.json** file. 39 40| Launch Type | Description |Description | 41| ----------- | ------- |---------------- | 42| standard | Multi-instance | A new instance is started each time an ability starts.| 43| singleton | Singleton | Only one instance exists in the system. If an instance already exists when an ability is started, that instance is reused.| 44 45By default, **singleton** is used. 46 47 48## Development Guidelines 49### Available APIs 50 51**Table 1** APIs provided by featureAbility 52 53| API | Description | 54| --------------------------------------------------- | --------------- | 55| void startAbility(parameter: StartAbilityParameter) | Starts an ability. | 56| Context getContext(): | Obtains the application context.| 57| void terminateSelf() | Terminates the ability. | 58| bool hasWindowFocus() | Checks whether the ability has focus. | 59 60 61### Starting a Local Page Ability 62 63**Modules to Import** 64 65```js 66 import featureAbility from '@ohos.ability.featureAbility' 67``` 68 69**Example** 70 71```javascript 72 import featureAbility from '@ohos.ability.featureAbility' 73 featureAbility.startAbility({ 74 want: 75 { 76 action: "", 77 entities: [""], 78 type: "", 79 options: { 80 // Grant the permission to perform read operations on the URI. 81 authReadUriPermission: true, 82 // Grant the permission to perform write operations on the URI. 83 authWriteUriPermission: true, 84 // Support forwarding the Want result to the ability. 85 abilityForwardResult: true, 86 // Enable abiligy continuation. 87 abilityContinuation: true, 88 // Specify that a component does not belong to ohos. 89 notOhosComponent: true, 90 // Specify that an ability is started. 91 abilityFormEnabled: true, 92 // Grant the permission for possible persisting on the URI. 93 authPersistableUriPermission: true, 94 // Grant the permission for possible persisting on the prefix URI. 95 authPrefixUriPermission: true, 96 // Support distributed scheduling system startup on multiple devices. 97 abilitySliceMultiDevice: true, 98 // A service ability is started regardless of whether the host application has been started. 99 startForegroundAbility: true, 100 // Install the specified ability if it is not installed. 101 installOnDemand: true, 102 // Return the result to the ability slice. 103 abilitySliceForwardResult: true, 104 // Install the specified ability with background mode if it is not installed. 105 installWithBackgroundMode: true 106 }, 107 deviceId: "", 108 bundleName: "com.example.startability", 109 abilityName: "com.example.startability.MainAbility", 110 uri: "" 111 }, 112 }, 113 ); 114``` 115 116You can also include **parameters** in the **want** parameter and set its value in the key-value format. 117 118**Example** 119 120```javascript 121 import featureAbility from '@ohos.ability.featureAbility' 122 featureAbility.startAbility({ 123 want: 124 { 125 bundleName: "com.example.startability", 126 uri: "", 127 parameters: { 128 abilityName: "com.example.startability.MainAbility" 129 } 130 }, 131 }, 132 ); 133``` 134### Starting a Remote Page Ability 135>Note 136> 137>This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. 138 139**Modules to Import** 140 141``` 142 import featureAbility from '@ohos.ability.featureAbility' 143 import deviceManager from '@ohos.distributedHardware.deviceManager'; 144``` 145 146**Example** 147```ts 148 function onStartRemoteAbility() { 149 console.info('onStartRemoteAbility begin'); 150 let params; 151 let wantValue = { 152 bundleName: 'ohos.samples.etsDemo', 153 abilityName: 'ohos.samples.etsDemo.RemoteAbility', 154 deviceId: getRemoteDeviceId(), 155 parameters: params 156 }; 157 console.info('onStartRemoteAbility want=' + JSON.stringify(wantValue)); 158 featureAbility.startAbility({ 159 want: wantValue 160 }).then((data) => { 161 console.info('onStartRemoteAbility finished, ' + JSON.stringify(data)); 162 }); 163 console.info('onStartRemoteAbility end'); 164 } 165``` 166 167Obtain **deviceId** from **DeviceManager**. The sample code is as follows: 168 169```ts 170 import deviceManager from '@ohos.distributedHardware.deviceManager'; 171 let dmClass; 172 function getRemoteDeviceId() { 173 if (typeof dmClass === 'object' && dmClass != null) { 174 let list = dmClass.getTrustedDeviceListSync(); 175 if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { 176 console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); 177 return; 178 } 179 console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); 180 return list[0].deviceId; 181 } else { 182 console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); 183 } 184 } 185``` 186 187In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows: 188 189```ts 190 import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; 191 import bundle from '@ohos.bundle'; 192 async function RequestPermission() { 193 console.info('RequestPermission begin'); 194 let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"]; 195 let bundleFlag = 0; 196 let tokenID = undefined; 197 let userID = 100; 198 let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); 199 tokenID = appInfo.accessTokenId; 200 let atManager = abilityAccessCtrl.createAtManager(); 201 let requestPermissions: Array<string> = []; 202 for (let i = 0;i < array.length; i++) { 203 let result = await atManager.verifyAccessToken(tokenID, array[i]); 204 console.info("verifyAccessToken result:" + JSON.stringify(result)); 205 if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 206 } else { 207 requestPermissions.push(array[i]); 208 } 209 } 210 console.info("requestPermissions:" + JSON.stringify(requestPermissions)); 211 if (requestPermissions.length == 0 || requestPermissions == []) { 212 return; 213 } 214 let context = featureAbility.getContext(); 215 context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{ 216 console.info("data:" + JSON.stringify(data)); 217 console.info("data requestCode:" + data.requestCode); 218 console.info("data permissions:" + data.permissions); 219 console.info("data authResults:" + data.authResults); 220 }); 221 console.info('RequestPermission end'); 222 } 223``` 224 225### Lifecycle APIs 226 227**Table 2** Lifecycle callbacks 228 229| API | Description | 230| ------------ | ------------------------------------------------------------ | 231| onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.| 232| onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible to users.| 233| 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.| 234| onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.| 235| onInactive() | Called when the ability loses focus. An ability loses focus when it is about to enter the background state.| 236| onActive() | Called when the ability is switched to the foreground and gains focus. | 237 238**Example** 239 240You need to override the lifecycle callbacks except **onCreate()** and **onDestroy()** in **app.js** or **app.ets**. The **onCreate()** and **onDestroy()** callbacks are automatically generated in the template code provided by DevEco Studio. 241 242```javascript 243export default { 244 onCreate() { 245 console.info('Application onCreate') 246 }, 247 onDestroy() { 248 console.info('Application onDestroy') 249 }, 250 onShow(){ 251 console.info('Application onShow') 252 }, 253 onHide(){ 254 console.info('Application onHide') 255 }, 256 onInactive(){ 257 console.info('Application onInactive') 258 }, 259 onActive(){ 260 console.info('Application onActive') 261 }, 262} 263``` 264