1# UIServiceExtensionAbility (for System Applications Only) 2 3## Overview 4 5[UIServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md) is an [ExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-extensionAbility.md) component of the UIService type. It provides UI pages (such as preview pages) and background service capabilities. This component internally holds a [UIServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md), which provides a variety of APIs for external systems. 6 7In this document, the component that starts or connects to a UIServiceExtensionAbility is called the client, and the UIServiceExtensionAbility is called the server. 8 9An application can use a UIServiceExtensionAbility in two modes: 10- Call [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) in the [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md), [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md), or [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md) class to start a UIServiceExtensionAbility. 11- Call [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) in the [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md) or [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md) class to connect to a UIServiceExtensionAbility. 12 13Note the following: 14 15- Only one window is created during the start or connection of the UIServiceExtensionAbility. 16- If the window fails to be created or is destroyed, the UIServiceExtensionAbility is automatically destroyed. 17- The start, connection, and disconnection operations can be performed only in the main thread, but not in the Worker and TaskPool threads. 18- Applications can start and connect to a UIServiceExtensionAbility provided by the system only when they gain focus in the foreground. 19 20## Lifecycle 21 22The UIServiceExtensionAbility provides the following lifecycle callbacks: [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#oncreate), [onWindowWillCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onwindowwillcreate), [onWindowDidCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onwindowdidcreate), [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onrequest), [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onconnect), [onDisconnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondisconnect), [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata), and [onDestroy()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondestroy). Override them as required. The figure below shows the lifecycle transitions. 23 24**Figure 1** UIServiceExtensionAbility lifecycle 25 26 27 28 29 30- **onCreate** 31 32 This callback is invoked when a UIServiceExtensionAbility is created for the first time. You can perform initialization operations, for example, registering a common event listener, in this callback. 33 34 > **NOTE** 35 > 36 > If the UIServiceExtensionAbility has been created, starting it again does not trigger the **onCreate()** callback. 37 38- **onRequest** 39 40 This callback is invoked when another component calls [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) to start a UIServiceExtensionAbility. After This callback is invoked, the UIServiceExtensionAbility is started and runs in the foreground. This callback is invoked each time [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) is called. 41 42- **onWindowWillCreate** 43 44 This callback is invoked before a window is created. Through this callback, you can pass window parameters to the system. If **config.windowAttribute** is set to **window.ExtensionWindowAttribute.SUB_WINDOW**, a subwindow is created. If it is set to **window.ExtensionWindowAttribute.SYSTEM_WINDOW**, a system window is created. 45 46 Currently, both the subwindow and system window can be created for the UIServiceExtensionAbility started by [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md) and [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md), but only the system window can be created for the UIServiceExtensionAbility started by [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md). In addition, only one window is created for a UIServiceExtensionAbility. 47 48- **onWindowDidCreate** 49 50 This callback is invoked when a window is created. You can operate the window through a [Window](../reference/apis-arkui/arkts-apis-window-Window.md) object. You can use [window.on('windowVisibilityChange')](../reference/apis-arkui/arkts-apis-window-Window.md#onwindowvisibilitychange11) to bind and process window events, such as window showing, hiding, and destruction. 51 52- **onConnect** 53 54 This callback is invoked when another component calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a UIServiceExtensionAbility. In this callback, a remote proxy object, namely, [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md), is returned, through which the server communicates with the client. For the same client, if the values of **DeviceId**, **BundleName**, **ModuleName**, and **AbilityName** in the want object and the callback object are the same, [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) is invoked only for the first connection. If any of them is different, [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) is invoked again. 55 56- **onData** 57 58 This callback is invoked to receive data sent by the caller through [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md). 59 60- **onDisconnect** 61 62 This callback is invoked when the connection is interrupted, which occurs when the client exits or [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14) is called. 63 64- **onDestroy** 65 66 This callback is invoked when a UIServiceExtensionAbility is no longer required and the instance is ready for destruction. You can clear resources, for example, deregistering the listener, in this callback. 67 68## Implementing an Extension Base Class of the UIService Type 69 70### Preparations 71 72Only system applications can implement a UIServiceExtensionAbility. You must make the following preparations before development: 73 74- **Switching to the full SDK**: All the APIs provided by the UIServiceExtensionAbility class are marked as system APIs and hidden by default. Therefore, you must manually obtain the full SDK from the mirror and switch to it in DevEco Studio. For details, see [Switching to Full SDK](../faqs/full-sdk-switch-guide.md). 75 76- **Requesting the AllowAppUsePrivilegeExtension privilege**: Only applications with the **AllowAppUsePrivilegeExtension** privilege can implement a UIServiceExtensionAbility. For details about how to request the privilege, see [Application Privilege Configuration](../../device-dev/subsystems/subsys-app-privilege-config-guide.md). 77 78### Creating a UIServiceExtensionAbility 79 80To manually create a UIServiceExtensionAbility in a project in DevEco Studio, perform the following steps: 81 821. In the **ets** directory of the target module, right-click and choose **New > Directory** to create a directory named [UIServiceExtension](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md). 83 842. In the **UIServiceExt** directory, right-click and choose **New > ArkTS File** to create a file named **UIServiceExt.ets**. 85 86 ``` 87 ├── ets 88 │ ├── UIServiceExt 89 │ │ ├── UIServiceExt.ets 90 ``` 91 923. In the **UIServiceExt.ets** file, import the UIServiceExtensionAbility module. Customize a class that inherits from the UIServiceExtensionAbility and implement the lifecycle callbacks. 93 94 ```ts 95 import { common, UIServiceExtensionAbility, Want } from '@kit.AbilityKit'; 96 import { hilog } from '@kit.PerformanceAnalysisKit'; 97 import { window } from '@kit.ArkUI'; 98 99 export default class UIServiceExtAbility extends UIServiceExtensionAbility { 100 // Create a UIServiceExtensionAbility. 101 onCreate(want: Want) { 102 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 103 } 104 105 // Callback for request processing. 106 onRequest(want: Want, startId: number) { 107 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onRequest'); 108 } 109 110 // Callback invoked when a connection is set up. 111 onConnect(want: Want, proxy: common.UIServiceHostProxy) { 112 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onConnect'); 113 } 114 115 // Callback invoked when a connection is interrupted. 116 onDisconnect(want: Want, proxy: common.UIServiceHostProxy) { 117 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDisconnect'); 118 } 119 120 // Callback invoked when a window is about to create. 121 onWindowWillCreate(config: window.ExtensionWindowConfig): void { 122 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowWillCreate'); 123 let rect: window.Rect = { 124 left: 100, 125 top: 100, 126 width: 500, 127 height: 500 128 }; 129 // Create a subwindow. 130 config.windowName = 'sub_window' 131 config.windowAttribute = window.ExtensionWindowAttribute.SUB_WINDOW; 132 config.windowRect = rect; 133 config.subWindowOptions = { 134 title: 'sub_window_title', 135 decorEnabled: true, 136 // Whether the window is a modal window. 137 isModal: false 138 }; 139 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowWillCreate end'); 140 } 141 142 // Callback invoked when a window is created. 143 onWindowDidCreate(window: window.Window) { 144 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowDidCreate'); 145 window.setUIContent('uiservice/page/WindowPage'); 146 window.showWindow(); 147 } 148 149 // Callback invoked to receive data. 150 onData(proxy: common.UIServiceHostProxy, data: Record<string, Object>) { 151 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onData'); 152 } 153 154 // Callback invoked to destroy the instance. 155 onDestroy() { 156 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 157 } 158 } 159 ``` 160 1614. Register the UIServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) of the module in the project. Set **type** to **"uiService"** and **srcEntry** to the code path of the UIServiceExtensionAbility component. 162 163 ```json 164 { 165 "module": { 166 // ... 167 "extensionAbilities": [ 168 { 169 "name": "UIServiceExtAbility", 170 "icon": "$media:icon", 171 "description": "uiService", 172 "type": "uiService", 173 "exported": true, 174 "srcEntry": "./ets/UIServiceExtAbility/UIServiceExtAbility.ets" 175 } 176 ] 177 } 178 } 179 ``` 180 181### Starting a UIServiceExtensionAbility 182 183An application calls [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) to start a UIServiceExtensionAbility. The [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onrequest) callback is invoked, through which the background service receives the Want object passed by the caller. Once the UIServiceExtensionAbility is started, its lifecycle is independent of the client. In other words, even if the client is destroyed, the background service remains alive. However, the service is destroyed if the window fails to be created or is destroyed. Therefore, the background service must be stopped by calling [terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md#uiserviceextensioncontextterminateself) of [UIServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md) when its work is complete. 184 185Start a new UIServiceExtensionAbility 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). 186 187 188```ts 189import { common, Want } from '@kit.AbilityKit'; 190import { BusinessError } from '@kit.BasicServicesKit'; 191 192@Entry 193@Component 194struct Index { 195 build() { 196 Column() { 197 Row() { 198 // Create a Start button. 199 Button('start ability') 200 .enabled(true) 201 .onClick(() => { 202 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 203 let startWant: Want = { 204 bundleName: 'com.acts.uiserviceextensionability', 205 abilityName: 'UiServiceExtAbility', 206 }; 207 try { 208 // Start the UIServiceExtensionAbility. 209 context.startUIServiceExtensionAbility(startWant).then(() => { 210 console.info(`startUIServiceExtensionAbility success.`); 211 }).catch((error: BusinessError) => { 212 console.error(`startUIServiceExtensionAbility failed, err code: ${error.code}, err msg: ${error.message}.`); 213 }) 214 } catch (err) { 215 let code = (err as BusinessError).code; 216 let msg = (err as BusinessError).message; 217 console.error(`startUIServiceExtensionAbility failed, err code: ${code}, err msg: ${msg}.`); 218 } 219 }) 220 } 221 } 222 } 223} 224``` 225 226### Connecting to a UIServiceExtensionAbility 227 228An application can use [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a service (specified in the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object). The [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) callback is invoked, through which the service receives the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object passed by the caller. In this way, a connection is established. 229 230When the client calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to the server, the client receives a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object returned by the server and saves it. Through this proxy object, the client sends data to the server, and disconnects from the server by calling [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14). 231 232- Call [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a UIServiceExtensionAbility. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). 233 ```ts 234 import { common, Want } from '@kit.AbilityKit'; 235 import { BusinessError } from '@kit.BasicServicesKit'; 236 237 @Entry 238 @Component 239 struct Page_UIServiceExtensionAbility { 240 @State uiServiceProxy: common.UIServiceProxy | null = null; 241 242 build() { 243 Column() { 244 //... 245 Row() { 246 //... 247 }.onClick(() => { 248 const context = this.getUIContext().getHostContext() as common.UIAbilityContext; 249 const want: Want = { 250 deviceId: '', 251 bundleName: 'com.example.myapplication', 252 abilityName: '' 253 }; 254 // Define a callback. 255 const callback: common.UIServiceExtensionConnectCallback = { 256 onData: (data: Record<string, Object>): void => { 257 console.info(`onData, data: ${JSON.stringify(data)}.`); 258 }, 259 onDisconnect: (): void => { 260 console.info(`onDisconnect.`); 261 } 262 }; 263 // Connect to the UIServiceExtensionAbility. 264 context.connectUIServiceExtensionAbility(want, callback).then((uiServiceProxy: common.UIServiceProxy) => { 265 this.uiServiceProxy = uiServiceProxy; 266 console.info(`connectUIServiceExtensionAbility success.`); 267 }).catch((error: BusinessError) => { 268 console.error(`connectUIServiceExtensionAbility failed, err code:${error.code}, err msg: ${error.message}.`); 269 }); 270 }) 271 } 272 } 273 } 274 ``` 275 276- Call [disconnectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14) to disconnect from a UIServiceExtensionAbility. 277 ```ts 278 import { common } from '@kit.AbilityKit'; 279 import { BusinessError } from '@kit.BasicServicesKit'; 280 281 @Entry 282 @Component 283 struct Page_UIServiceExtensionAbility { 284 @State uiServiceProxy: common.UIServiceProxy | null = null; 285 286 build() { 287 Column() { 288 //... 289 Row() { 290 //... 291 }.onClick(() => { 292 const context = this.getUIContext().getHostContext() as common.UIAbilityContext; 293 // this.uiServiceProxy is the proxy object saved during connection. 294 context.disconnectUIServiceExtensionAbility(this.uiServiceProxy).then(() => { 295 console.info(`disconnectUIServiceExtensionAbility success.`); 296 }).catch((error: BusinessError) => { 297 console.error(`disconnectUIServiceExtensionAbility failed, err code: ${error.code}, err msg: ${error.message}.`); 298 }); 299 }) 300 } 301 } 302 } 303 ``` 304 305 306 307## Bidirectional Communication Between the Client and Server 308 309After a UIServiceExtensionAbility is started, the following operations are possible: 310 3111. The client calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md#connectuiserviceextensionability14) to obtain a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object, through which it can send data to the server. 3122. The server obtains a [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md) object through the [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onconnect) callback and sends data to the client through this proxy. 313 314 315 316 317### Communication Between the Client and Server 318- Data transmission on the client 319 320 The client connects to the server through [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md#connectuiserviceextensionability14) and obtains a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object. The client calls [sendData()](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md#uiserviceproxysenddata) of the proxy object to send data to the server. The server receives data through the [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata) callback. 321 ```ts 322 import { common, Want } from '@kit.AbilityKit'; 323 import { BusinessError } from '@kit.BasicServicesKit'; 324 325 @Entry 326 @Component 327 struct Index { 328 comProxy: common.UIServiceProxy | null = null; 329 connectCallback: common.UIServiceExtensionConnectCallback = { 330 onData: (data: Record<string, Object>) => { 331 console.info(`onData, data: ${JSON.stringify(data)}.`); 332 }, 333 onDisconnect: () => { 334 console.info(`onDisconnect.`); 335 } 336 } 337 338 build() { 339 Column() { 340 Row() { 341 // Create a Connect button. 342 Button('connect ability') 343 .enabled(true) 344 .onClick(() => { 345 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 346 let startWant: Want = { 347 bundleName: 'com.acts.uiserviceextensionability', 348 abilityName: 'UiServiceExtAbility', 349 }; 350 try { 351 // Connect to the UIServiceExtensionAbility. 352 context.connectUIServiceExtensionAbility(startWant, this.connectCallback) 353 .then((proxy: common.UIServiceProxy) => { 354 this.comProxy = proxy; 355 let formData: Record<string, string> = { 356 'test': 'test' 357 }; 358 try { 359 this.comProxy.sendData(formData); 360 } catch (err) { 361 let code = (err as BusinessError).code; 362 let msg = (err as BusinessError).message; 363 console.error(`sendData failed, err code: ${code}, err msg: ${msg}.`); 364 } 365 }) 366 .catch((err: BusinessError) => { 367 console.error(`connectUIServiceExtensionAbility failed, err code: ${err.code}, err msg: ${err.message}.`); 368 }); 369 } catch (err) { 370 let code = (err as BusinessError).code; 371 let msg = (err as BusinessError).message; 372 console.error(`connectUIServiceExtensionAbility failed, err code: ${code}, err msg: ${msg}.`); 373 } 374 }) 375 } 376 } 377 } 378 } 379 ``` 380 381- Data transmission on the server 382 383 The server receives data transferred by the client through [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata). Through the [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md) object, which is saved during the connection, the server calls [sendData()](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md#senddata) to send data to the client. 384 ```ts 385 import { common, Want, UIServiceExtensionAbility } from '@kit.AbilityKit'; 386 import { window } from '@kit.ArkUI'; 387 import { BusinessError } from '@kit.BasicServicesKit'; 388 389 export default class MyServiceExtAbility extends UIServiceExtensionAbility { 390 comProxy: common.UIServiceHostProxy | null = null; 391 392 // Callback invoked when a UIServiceExtensionAbility is created. 393 onCreate(want: Want) { 394 console.info('UIServiceExtensionAbility onCreate'); 395 } 396 397 // Callback for request processing. 398 onRequest(want: Want, startId: number) { 399 console.info('UIServiceExtensionAbility onRequest'); 400 } 401 402 // Callback invoked when a connection is set up. 403 onConnect(want: Want, proxy: common.UIServiceHostProxy) { 404 console.info('UIServiceExtensionAbility onConnect'); 405 this.comProxy = proxy; 406 } 407 408 // Callback invoked when a connection is interrupted. 409 onDisconnect(want: Want, proxy: common.UIServiceHostProxy) { 410 console.info('UIServiceExtensionAbility onDisconnect'); 411 this.comProxy = null; 412 } 413 414 // Callback invoked to receive data. 415 onData(proxy: common.UIServiceHostProxy, data: Record<string, Object>) { 416 console.info('UIServiceExtensionAbility onData'); 417 try { 418 let formData: Record<string, string> = { 419 'Data': 'reply message' 420 }; 421 proxy.sendData(formData); 422 } catch (err) { 423 let code = (err as BusinessError).code; 424 let msg = (err as BusinessError).message; 425 console.error(`sendData failed, err code: ${code}, err msg: ${msg}.`); 426 } 427 } 428 429 onWindowWillCreate(extensionWindowConfig: window.ExtensionWindowConfig) { 430 console.info('UIServiceExtensionAbility onWindowWillCreate'); 431 } 432 433 onWindowDidCreate(window: window.Window) { 434 console.info('UIServiceExtensionAbility onWindowDidCreate'); 435 } 436 437 onDestroy() { 438 console.info('UIServiceExtensionAbility onDestroy'); 439 } 440 } 441 ``` 442