1# UIExtensionAbility 2 3## Overview 4 5[UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) is an ExtensionAbility component of the UI type. It is usually used in modular development scenarios where process isolation is required, for example, system dialog boxes, status bars, and capsules. There are two forms: embedded and system pop-ups. 6- The UIExtensionAbility in embedded mode must be used together with the [UIExtensionComponent](../reference/apis-arkui/arkui-ts/ts-container-ui-extension-component-sys.md). Specifically, with the UIExtensionComponent, you can embed the UI provided by the UIExtensionAbility of another application into a UIAbility of your application. The UIExtensionAbility runs in a process independent of the UIAbility for UI layout and rendering. 7- To start the UIExtensionAbility in system pop-up mode, call [requestModalUIExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md#serviceextensioncontextrequestmodaluiextension11) or the specified interface encapsulated in the application. 8 9## Constraints 10- Currently, the UIExtensionAbility of the **sys/commonUI**, **sysDialog**, and **sysPicker** types can be used only by system applications. For details about the UIExtensionAbility types and corresponding permission control, see the [module.json5 file](../quick-start/module-configuration-file.md). 11- The UIExtensionAbility can be started only by applications that are running in the foreground. 12 13## Lifecycle 14The [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) class provides the lifecycle callbacks [onCreate](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityoncreate), [onSessionCreate](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonsessioncreate), [onSessionDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonsessiondestroy), [onForeground](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonforeground), [onBackground](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonbackground), and [onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityondestroy). You must override them as required. 15 16- **onCreate**: called to initialize the service logic when a UIExtensionAbility is created. 17- **onSessionCreate**: called when a **UIExtensionContentSession** instance is created for the UIExtensionAbility. 18- **onSessionDestroy**: called when a **UIExtensionContentSession** instance is destroyed for the UIExtensionAbility. 19- **onForeground**: called when the UIExtensionAbility is switched from the background to the foreground. 20- **onBackground**: called when the UIExtensionAbility is switched from the foreground to the background. 21- **onDestroy**: called to clear resources when the UIExtensionAbility is destroyed. 22 23## Selecting a Proper Process Model for the UIExtensionAbility 24The [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) supports the multiton pattern. Each embedded UI corresponds to a UIExtensionAbility instance. In the multiton scenario, the multi-process model is used by default. 25 26When multiple UIExtensionAbility instances exist in an application, these instances can run in independent processes or share one process. They can also be grouped, and each group share one process. You can select a process model based on the **extensionProcessMode** field in the [module.json5](../quick-start/module-configuration-file.md) file. The table below describes the comparison between the process models. 27| Process Model| extensionProcessMode Field Value| Description| 28| --------| --------| --------| 29| One process for all UIExtensionAbility instances in the same bundle|bundle| The UIExtensionAbility instances do not need to communicate with each other across IPCs. Their statuses are dependent and affect each other.| 30| One process for all UIExtensionAbility instances with the same name| type |The UIExtensionAbility instances of the same type are configured in the same process so that your application can manage them by type.| 31| One process for each UIExtensionAbility instance| instance | The UIExtensionAbility instances communicate with each other only across IPCs. Their statuses do not affect each other, which is more secure.| 32### One Process for All UIExtensionAbility Instances in the Bundle 33The [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) instances of the same bundle are configured in a process. This makes communication between multiple instances easier. However, the status of these instances affects each other. When an instance in the process exits abnormally, all instances in the process exit. 34 35**Figure 1** Bundle-based process model configuration 36 37 38 39The sample code of **Index.ets** is as follows: 40```ts 41@Entry 42@Component 43struct Index { 44 @State message: string = 'UIExtension UserA'; 45 private myProxy: UIExtensionProxy | undefined = undefined; 46 47 build() { 48 Row() { 49 Column() { 50 Text(this.message) 51 .fontSize(30) 52 .size({ width: '100%', height: '50' }) 53 .fontWeight(FontWeight.Bold) 54 .textAlign(TextAlign.Center) 55 56 UIExtensionComponent( 57 { 58 bundleName: 'com.samples.uiextensionability', 59 abilityName: 'UIExtensionProvider', 60 moduleName: 'entry', 61 parameters: { 62 'ability.want.params.uiExtensionType': 'sys/commonUI', 63 } 64 }) 65 .onRemoteReady((proxy) => { 66 this.myProxy = proxy; 67 }) 68 .onReceive((data) => { 69 this.message = JSON.stringify(data); 70 }) 71 .onResult((data) => { 72 this.message = JSON.stringify(data); 73 }) 74 .onRelease((code) => { 75 this.message = "release code:" + code; 76 }) 77 .offset({ x: 0, y: 10 }) 78 .size({ width: 300, height: 300 }) 79 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 80 81 UIExtensionComponent( 82 { 83 bundleName: 'com.samples.uiextension2', 84 abilityName: 'UIExtensionProviderB', 85 moduleName: 'entry', 86 parameters: { 87 'ability.want.params.uiExtensionType': 'sys/commonUI', 88 } 89 }) 90 .onRemoteReady((proxy) => { 91 this.myProxy = proxy; 92 }) 93 .onReceive((data) => { 94 this.message = JSON.stringify(data); 95 }) 96 .onResult((data) => { 97 this.message = JSON.stringify(data); 98 }) 99 .onRelease((code) => { 100 this.message = "release code:" + code; 101 }) 102 .offset({ x: 0, y: 50 }) 103 .size({ width: 300, height: 300 }) 104 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 105 } 106 .width('100%') 107 } 108 .height('100%') 109 } 110} 111``` 112**Figure 2** Index page generated based on the preceding code 113 114 115 116If this process model is used, the process name format is as follows: 117 118process name [{bundleName}:{UIExtensionAbility type}] 119 120Example: process name [com.ohos.intentexecutedemo:xxx] 121 122**Figure 3** Bundle-based process model 123 124 125 126### One Process for All UIExtensionAbility Instances of the Same Type 127Processes are allocated based on the [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) type. Multiple UIExtensionAbility instances of the same type are configured in the same process so that your application can manage the instances by type. 128 129**Figure 4** Type-based process model configuration 130 131 132 133The sample code of **Index.ets** is as follows: 134```ts 135@Entry 136@Component 137struct Index { 138 @State message: string = 'UIExtension User'; 139 private myProxy: UIExtensionProxy | undefined = undefined; 140 141 build() { 142 Row() { 143 Column() { 144 Text(this.message) 145 .fontSize(30) 146 .size({ width: '100%', height: '50' }) 147 .fontWeight(FontWeight.Bold) 148 .textAlign(TextAlign.Center) 149 150 UIExtensionComponent( 151 { 152 bundleName: 'com.samples.uiextensionability', 153 abilityName: 'UIExtensionProviderA', 154 moduleName: 'entry', 155 parameters: { 156 'ability.want.params.uiExtensionType': 'sys/commonUI', 157 } 158 }) 159 .onRemoteReady((proxy) => { 160 this.myProxy = proxy; 161 }) 162 .onReceive((data) => { 163 this.message = JSON.stringify(data); 164 }) 165 .onResult((data) => { 166 this.message = JSON.stringify(data); 167 }) 168 .onRelease((code) => { 169 this.message = "release code:" + code; 170 }) 171 .offset({ x: 0, y: 10 }) 172 .size({ width: 300, height: 300 }) 173 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 174 175 UIExtensionComponent( 176 { 177 bundleName: 'com.samples.uiextensionability', 178 abilityName: 'UIExtensionProviderB', 179 moduleName: 'entry', 180 parameters: { 181 'ability.want.params.uiExtensionType': 'sys/commonUI', 182 } 183 }) 184 .onRemoteReady((proxy) => { 185 this.myProxy = proxy; 186 }) 187 .onReceive((data) => { 188 this.message = JSON.stringify(data); 189 }) 190 .onResult((data) => { 191 this.message = JSON.stringify(data); 192 }) 193 .onRelease((code) => { 194 this.message = "release code:" + code; 195 }) 196 .offset({ x: 0, y: 50 }) 197 .size({ width: 300, height: 300 }) 198 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 199 } 200 .width('100%') 201 } 202 .height('100%') 203 } 204} 205``` 206**Figure 5** Index page generated based on the preceding code 207 208 209 210If this process model is used, the process name format is as follows: 211 212process name [{bundleName}:{UIExtensionAbility name}] 213 214Example: process name [com.ohos.intentexecutedemo:xxx] 215 216**Figure 6** Type-based process model 217 218 219 220### One Process for Each UIExtensionAbility Instance 221Processes are allocated based on the [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) instance. That is, each UIExtensionAbility instance has an independent process. In this mode, UIExtensionAbility instances can communicate with each other only through IPCs. However, their statuses do not affect each other, improving security. 222 223**Figure 7** Instance-specific process model configuration 224 225 226 227 228The sample code of **Index.ets** is as follows: 229```ts 230@Entry 231@Component 232struct Index { 233 @State message: string = 'UIExtension User' 234 private myProxy: UIExtensionProxy | undefined = undefined; 235 236 build() { 237 Row() { 238 Column() { 239 Text(this.message) 240 .fontSize(30) 241 .size({ width: '100%', height: '50' }) 242 .fontWeight(FontWeight.Bold) 243 .textAlign(TextAlign.Center) 244 245 UIExtensionComponent( 246 { 247 bundleName: 'com.samples.uiextensionability', 248 abilityName: 'UIExtensionProvider', 249 moduleName: 'entry', 250 parameters: { 251 'ability.want.params.uiExtensionType': 'sys/commonUI', 252 } 253 }) 254 .onRemoteReady((proxy) => { 255 this.myProxy = proxy; 256 }) 257 .onReceive((data) => { 258 this.message = JSON.stringify(data); 259 }) 260 .onResult((data) => { 261 this.message = JSON.stringify(data); 262 }) 263 .onRelease((code) => { 264 this.message = "release code:" + code; 265 }) 266 .offset({ x: 0, y: 10 }) 267 .size({ width: 300, height: 300 }) 268 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 269 270 UIExtensionComponent( 271 { 272 bundleName: 'com.samples.uiextensionability', 273 abilityName: 'UIExtensionProvider', 274 moduleName: 'entry', 275 parameters: { 276 'ability.want.params.uiExtensionType': 'sys/commonUI', 277 } 278 }) 279 .onRemoteReady((proxy) => { 280 this.myProxy = proxy; 281 }) 282 .onReceive((data) => { 283 this.message = JSON.stringify(data); 284 }) 285 .onResult((data) => { 286 this.message = JSON.stringify(data); 287 }) 288 .onRelease((code) => { 289 this.message = "release code:" + code; 290 }) 291 .offset({ x: 0, y: 50 }) 292 .size({ width: 300, height: 300 }) 293 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 294 } 295 .width('100%') 296 } 297 .height('100%') 298 } 299} 300``` 301**Figure 8** Index page generated based on the preceding code 302 303 304 305If this process model is used, the process name format is as follows: 306 307process name [{bundleName}: {UIExtensionAbility type}: {instance suffix}] 308 309Example: process name [com.ohos.intentexecutedemo:xxx:n] 310 311**Figure 9** Instance-specific process model 312 313 314 315The UIExtensionAbility provides related capabilities through the [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md) and [UIExtensionContentSession](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionContentSession.md). In this document, the started UIExtensionAbility is called the provider, and the [UIExtensionComponent](../reference/apis-arkui/arkui-ts/ts-container-ui-extension-component-sys.md) that starts the UIExtensionAbility is called the client. 316 317## How to Develop 318 319 For details about how to develop a system dialog box, see [requestModalUIExtension](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md#serviceextensioncontextrequestmodaluiextension11). 320 321### Developing the UIExtensionAbility Provider 322 323To implement a provider, create a [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) in DevEco Studio as follows: 324 3251. In the **ets** directory of the **Module** project, right-click and choose **New > Directory** to create a directory named **uiextensionability**. 326 3272. Right-click the **uiextensionability** directory, and choose **New > File** to create a file named **UIExtensionAbility.ets**. 328 3293. Open the **UIExtensionAbility.ets** file and import its dependencies. Customize a class that inherits from **UIExtensionAbility** and implement the lifecycle callbacks [onCreate](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityoncreate), [onSessionCreate](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonsessioncreate), [onSessionDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonsessiondestroy), [onForeground](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonforeground), [onBackground](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonbackground), and [onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityondestroy). 330 331 ```ts 332 import { Want, UIExtensionAbility, UIExtensionContentSession } from '@kit.AbilityKit'; 333 334 const TAG: string = '[testTag] UIExtAbility'; 335 336 export default class UIExtAbility extends UIExtensionAbility { 337 onCreate() { 338 console.log(TAG, `onCreate`); 339 } 340 341 onForeground() { 342 console.log(TAG, `onForeground`); 343 } 344 345 onBackground() { 346 console.log(TAG, `onBackground`); 347 } 348 349 onDestroy() { 350 console.log(TAG, `onDestroy`); 351 } 352 353 onSessionCreate(want: Want, session: UIExtensionContentSession) { 354 console.log(TAG, `onSessionCreate, want: ${JSON.stringify(want)}}`); 355 let storage: LocalStorage = new LocalStorage(); 356 storage.setOrCreate('session', session); 357 session.loadContent('pages/Extension', storage); 358 } 359 360 onSessionDestroy(session: UIExtensionContentSession) { 361 console.log(TAG, `onSessionDestroy`); 362 } 363 } 364 ``` 365 3664. Write the entry page file **pages/extension.ets**, which will be loaded in [onSessionCreate](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md#uiextensionabilityonsessioncreate) of the [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md), and declare "pages/Extension" in the **entry\src\main\resources\base\profile\main_pages.json** file. The content of **extension.ets** is as follows: 367 368 ```ts 369 import { UIExtensionContentSession } from '@kit.AbilityKit'; 370 371 let storage = LocalStorage.GetShared(); 372 const TAG: string = `[testTag] ExtensionPage`; 373 374 @Entry(storage) 375 @Component 376 struct Extension { 377 @State message: string = `UIExtension provider`; 378 private session: UIExtensionContentSession | undefined = storage.get<UIExtensionContentSession>('session'); 379 380 onPageShow() { 381 console.info(TAG, 'show'); 382 } 383 384 build() { 385 Row() { 386 Column() { 387 Text(this.message) 388 .fontSize(30) 389 .fontWeight(FontWeight.Bold) 390 .textAlign(TextAlign.Center) 391 392 Button("send data") 393 .width('80%') 394 .type(ButtonType.Capsule) 395 .margin({ top: 20 }) 396 .onClick(() => { 397 this.session?.sendData({ "data": 543321 }); 398 }) 399 400 Button("terminate self") 401 .width('80%') 402 .type(ButtonType.Capsule) 403 .margin({ top: 20 }) 404 .onClick(() => { 405 this.session?.terminateSelf(); 406 storage.clear(); 407 }) 408 409 Button("terminate self with result") 410 .width('80%') 411 .type(ButtonType.Capsule) 412 .margin({ top: 20 }) 413 .onClick(() => { 414 this.session?.terminateSelfWithResult({ 415 resultCode: 0, 416 want: { 417 bundleName: "com.example.uiextensiondemo", 418 parameters: { "result": 123456 } 419 } 420 }) 421 }) 422 } 423 } 424 .height('100%') 425 } 426 } 427 ``` 428 4295. Register the [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) in the [module.json5 file](../quick-start/module-configuration-file.md) of the module. Set **type** to that configured for the UIExtensionAbility and **srcEntry** to the code path of the UIExtensionAbility. The **extensionProcessMode** field identifies the multiton process model. Here, **bundle** is used as an example. 430 431 ```json 432 { 433 "module": { 434 "extensionAbilities": [ 435 { 436 "name": "UIExtensionProvider", 437 "srcEntry": "./ets/uiextensionability/UIExtensionAbility.ets", 438 "description": "UIExtensionAbility", 439 "type": "sys/commonUI", 440 "exported": true, 441 "extensionProcessMode": "bundle" 442 }, 443 ] 444 } 445 } 446 ``` 447## Developing the UIExtensionAbility Client 448 449You can load the [UIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md) in the application through the [UIExtensionComponent](../reference/apis-arkui/arkui-ts/ts-container-ui-extension-component-sys.md) on the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) page. For example, add the following content to the home page file **pages/Index.ets**: 450 451```ts 452@Entry 453@Component 454struct Index { 455 @State message: string = 'UIExtension User'; 456 private myProxy: UIExtensionProxy | undefined = undefined; 457 458 build() { 459 Row() { 460 Column() { 461 Text(this.message) 462 .fontSize(30) 463 .size({ width: '100%', height: '50' }) 464 .fontWeight(FontWeight.Bold) 465 .textAlign(TextAlign.Center) 466 467 UIExtensionComponent( 468 { 469 bundleName: 'com.example.uiextensiondemo', 470 abilityName: 'UIExtensionProvider', 471 moduleName: 'entry', 472 parameters: { 473 'ability.want.params.uiExtensionType': 'sys/commonUI', 474 } 475 }) 476 .onRemoteReady((proxy) => { 477 this.myProxy = proxy; 478 }) 479 .onReceive((data) => { 480 this.message = JSON.stringify(data); 481 }) 482 .onResult((data) => { 483 this.message = JSON.stringify(data); 484 }) 485 .onRelease((code) => { 486 this.message = "release code:" + code; 487 }) 488 .offset({ x: 0, y: 30 }) 489 .size({ width: 300, height: 300 }) 490 .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted }) 491 492 Button("sendData") 493 .type(ButtonType.Capsule) 494 .offset({ x: 0, y: 60 }) 495 .width('80%') 496 .type(ButtonType.Capsule) 497 .margin({ 498 top: 20 499 }) 500 .onClick(() => { 501 this.myProxy?.send({ 502 "data": 123456, 503 "message": "data from component" 504 }) 505 }) 506 } 507 .width('100%') 508 } 509 .height('100%') 510 } 511} 512``` 513