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![uiextability-bundle-processmodel](figures/uiextability-bundle-processmodel.png)
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![uiextension-bundle-example](figures/uiextability-bundle-example.png)
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![uiextension-bundle-process-example](figures/uiextability-bundle-process-example.png)
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![uiextability-type-processmodel](figures/uiextability-type-processmodel.png)
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![uiextability-type-example](figures/uiextability-type-example.png)
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![uiextability-type-process-example](figures/uiexteability-type-precess-example.png)
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![uiextability-instance-processmodel](figures/uiextability-instance-processmodel.png)
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![uiextability-instance-example](figures/uiextability-instance-example.png)
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![uiextability-instance-process-example](figures/uiextability-instance-process-example.png)
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