1# Starting UIAbility in the Same Application 2 3<!--Kit: Ability Kit--> 4<!--Subsystem: Ability--> 5<!--Owner: @altay--> 6<!--Designer: @altay--> 7<!--Tester: @lixueqing513--> 8<!--Adviser: @huipeizi--> 9 10[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) is the minimum unit that can be scheduled by the system. Redirection between functional modules in a device involves starting of specific UIAbility components, which belong to the same or a different application (for example, starting the UIAbility of a third-party payment application). 11 12 13This topic describes how to start the UIAbility component that belongs to the same application. For details about component redirection between applications, see [Application Redirection](link-between-apps-overview.md). <!--Del-->For details about cross-device application component interaction, see [Inter-Device Application Component Interaction (Hopping)](inter-device-interaction-hop-overview.md).<!--DelEnd--> 14 15 16- [Starting UIAbility in the Same Application](#starting-uiability-in-the-same-application) 17- [Starting UIAbility in the Same Application and Obtaining the Return Result](#starting-uiability-in-the-same-application-and-obtaining-the-return-result) 18- [Starting a Specified Page of UIAbility](#starting-a-specified-page-of-uiability) 19<!--Del--> 20- [Starting UIAbility with Window Mode Specified (for System Applications Only)](#starting-uiability-with-window-mode-specified-for-system-applications-only) 21- [Using Call to Implement UIAbility Interaction (for System Applications Only)](#using-call-to-implement-uiability-interaction-for-system-applications-only) 22<!--DelEnd--> 23 24 25## Starting UIAbility in the Same Application 26 27This scenario is possible when an application contains multiple [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) components. For example, in a payment application, you may need to start the payment UIAbility from the entry UIAbility. 28 29Assume that your application has two UIAbility components: EntryAbility and FuncAbility, either in the same module or different modules. To start FuncAbility from EntryAbility, proceed as follows: 30 311. In EntryAbility, call [startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability) and pass the [want](../reference/apis-ability-kit/js-apis-app-ability-want.md) parameter to start 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 from EntryAbility; **parameters** is used to carry custom information. For details about how to obtain the context in the example, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). 32 33 ```ts 34 import { common, Want } from '@kit.AbilityKit'; 35 import { hilog } from '@kit.PerformanceAnalysisKit'; 36 import { BusinessError } from '@kit.BasicServicesKit'; 37 38 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 39 const DOMAIN_NUMBER: number = 0xFF00; 40 41 @Entry 42 @Component 43 struct Page_UIAbilityComponentsInteractive { 44 private context = this.getUIContext().getHostContext() as common.UIAbilityContext; 45 46 build() { 47 Column() { 48 //... 49 List({ initialIndex: 0 }) { 50 ListItem() { 51 Row() { 52 //... 53 } 54 .onClick(() => { 55 // Context is a member of the ability object and is required for invoking inside a non-ability object. 56 // Pass in the Context object. 57 let wantInfo: Want = { 58 deviceId: '', // An empty deviceId indicates the local device. 59 bundleName: 'com.samples.stagemodelabilitydevelop', 60 moduleName: 'entry', // moduleName is optional. 61 abilityName: 'FuncAbilityA', 62 parameters: { 63 // Custom information. 64 info: 'From Page_UIAbilityComponentsInteractive of EntryAbility' 65 }, 66 }; 67 // context is the UIAbilityContext of the initiator UIAbility. 68 this.context.startAbility(wantInfo).then(() => { 69 hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.'); 70 }).catch((error: BusinessError) => { 71 hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.'); 72 }); 73 }) 74 } 75 //... 76 } 77 //... 78 } 79 //... 80 } 81 } 82 ``` 83 842. In FuncAbility, use [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate) or [onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant) to receive the parameters passed in by EntryAbility. 85 86 ```ts 87 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 88 89 export default class FuncAbilityA extends UIAbility { 90 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 91 // Receive the parameters passed by the initiator UIAbility. 92 let funcAbilityWant = want; 93 let info = funcAbilityWant?.parameters?.info; 94 } 95 //... 96 } 97 ``` 98 99 > **NOTE** 100 > 101 > In FuncAbility started, you can obtain the PID and bundle name of the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) through **parameters** in the passed [want](../reference/apis-ability-kit/js-apis-app-ability-want.md) parameter. 102 1033. To stop the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) instance after the FuncAbility service is not needed, call [terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#terminateself) in FuncAbility. 104 105 ```ts 106 import { common } from '@kit.AbilityKit'; 107 import { hilog } from '@kit.PerformanceAnalysisKit'; 108 109 const TAG: string = '[Page_FromStageModel]'; 110 const DOMAIN_NUMBER: number = 0xFF00; 111 112 @Entry 113 @Component 114 struct Page_FromStageModel { 115 build() { 116 Column() { 117 //... 118 Button('FuncAbilityB') 119 .onClick(() => { 120 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 121 // context is the UIAbilityContext of the UIAbility instance to stop. 122 context.terminateSelf((err) => { 123 if (err.code) { 124 hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`); 125 return; 126 } 127 }); 128 }) 129 } 130 //... 131 } 132 } 133 ``` 134 135 > **NOTE** 136 > 137 > When **terminateSelf()** is called to stop the UIAbility instance, the snapshot of the instance is retained by default. That is, the mission corresponding to the instance is still displayed in the recent task list. If you do not want to retain the snapshot, set **removeMissionAfterTerminate** under the [abilities](../quick-start/module-configuration-file.md#abilities) tag to **true** in the [module.json5 file](../quick-start/module-configuration-file.md) of the corresponding UIAbility. 138 1394. To stop all [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) instances of the application, call [killAllProcesses()](../reference/apis-ability-kit/js-apis-inner-application-applicationContext.md#applicationcontextkillallprocesses) of [ApplicationContext](../reference/apis-ability-kit/js-apis-inner-application-applicationContext.md). 140 141 142## Starting UIAbility in the Same Application and Obtaining the Return Result 143 144When starting FuncAbility from EntryAbility, you may want the result to be returned after the FuncAbility service is finished. For example, after the sign-in operation is finished in the sign-in [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) of your application, you want the sign-in result to be returned to the entry UIAbility. 145 1461. In EntryAbility, call [startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilityforresult-2) 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 in the example, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). 147 148 ```ts 149 import { common, Want } from '@kit.AbilityKit'; 150 import { hilog } from '@kit.PerformanceAnalysisKit'; 151 import { BusinessError } from '@kit.BasicServicesKit'; 152 153 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 154 const DOMAIN_NUMBER: number = 0xFF00; 155 156 @Entry 157 @Component 158 struct Page_UIAbilityComponentsInteractive { 159 build() { 160 Column() { 161 //... 162 List({ initialIndex: 0 }) { 163 ListItem() { 164 Row() { 165 //... 166 } 167 .onClick(() => { 168 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 169 const RESULT_CODE: number = 1001; 170 let want: Want = { 171 deviceId: '', // An empty deviceId indicates the local device. 172 bundleName: 'com.samples.stagemodelabilitydevelop', 173 moduleName: 'entry', // moduleName is optional. 174 abilityName: 'FuncAbilityA', 175 parameters: { 176 // Custom information. 177 info: 'From UIAbilityComponentsInteractive of EntryAbility' 178 } 179 }; 180 context.startAbilityForResult(want).then((data) => { 181 if (data?.resultCode === RESULT_CODE) { 182 // Parse the information returned by the target UIAbility. 183 let info = data.want?.parameters?.info; 184 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? ''); 185 if (info !== null) { 186 this.getUIContext().getPromptAction().showToast({ 187 message: JSON.stringify(info) 188 }); 189 } 190 } 191 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? ''); 192 }).catch((err: BusinessError) => { 193 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`); 194 }); 195 }) 196 } 197 //... 198 } 199 //... 200 } 201 //... 202 } 203 } 204 ``` 205 2062. Call [terminateSelfWithResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#terminateselfwithresult) to stop FuncAbility. Use the input parameter [abilityResult](../reference/apis-ability-kit/js-apis-inner-ability-abilityResult.md) to carry the information that FuncAbility needs to return to EntryAbility. 207 208 ```ts 209 import { common } from '@kit.AbilityKit'; 210 import { hilog } from '@kit.PerformanceAnalysisKit'; 211 212 const TAG: string = '[Page_FuncAbilityA]'; 213 const DOMAIN_NUMBER: number = 0xFF00; 214 215 @Entry 216 @Component 217 struct Page_FuncAbilityA { 218 build() { 219 Column() { 220 //... 221 List({ initialIndex: 0 }) { 222 ListItem() { 223 Row() { 224 //... 225 } 226 .onClick(() => { 227 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 228 const RESULT_CODE: number = 1001; 229 let abilityResult: common.AbilityResult = { 230 resultCode: RESULT_CODE, 231 want: { 232 bundleName: 'com.samples.stagemodelabilitydevelop', 233 moduleName: 'entry', // moduleName is optional. 234 abilityName: 'FuncAbilityB', 235 parameters: { 236 info: 'From the Index page of FuncAbility' 237 }, 238 }, 239 }; 240 context.terminateSelfWithResult(abilityResult, (err) => { 241 if (err.code) { 242 hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`); 243 return; 244 } 245 }); 246 }) 247 } 248 //... 249 } 250 //... 251 } 252 //... 253 } 254 } 255 ``` 256 2573. After FuncAbility stops itself, EntryAbility uses [startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilityforresult-2) to receive the information returned by FuncAbility. The value of **RESULT_CODE** must be the same as that specified in the preceding step. 258 259 ```ts 260 import { common, Want } from '@kit.AbilityKit'; 261 import { hilog } from '@kit.PerformanceAnalysisKit'; 262 import { BusinessError } from '@kit.BasicServicesKit'; 263 264 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 265 const DOMAIN_NUMBER: number = 0xFF00; 266 267 @Entry 268 @Component 269 struct Page_UIAbilityComponentsInteractive { 270 build() { 271 Column() { 272 //... 273 List({ initialIndex: 0 }) { 274 ListItem() { 275 Row() { 276 //... 277 } 278 .onClick(() => { 279 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 280 const RESULT_CODE: number = 1001; 281 282 let want: Want = { 283 deviceId: '', // An empty deviceId indicates the local device. 284 bundleName: 'com.samples.stagemodelabilitydevelop', 285 moduleName: 'entry', // moduleName is optional. 286 abilityName: 'FuncAbilityA', 287 parameters: { 288 // Custom information. 289 info: 'From UIAbilityComponentsInteractive of EntryAbility' 290 } 291 }; 292 context.startAbilityForResult(want).then((data) => { 293 if (data?.resultCode === RESULT_CODE) { 294 // Parse the information returned by the target UIAbility. 295 let info = data.want?.parameters?.info; 296 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? ''); 297 if (info !== null) { 298 this.getUIContext().getPromptAction().showToast({ 299 message: JSON.stringify(info) 300 }); 301 } 302 } 303 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? ''); 304 }).catch((err: BusinessError) => { 305 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`); 306 }); 307 }) 308 } 309 //... 310 } 311 //... 312 } 313 //... 314 } 315 } 316 ``` 317 318 319## Starting a Specified Page of UIAbility 320 321### Overview 322 323A [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) component can have multiple pages that each display in specific scenarios. 324 325A UIAbility component can be started in two modes: 326 327- Cold start: The UIAbility instance is totally closed before being started. This requires that the code and resources of the UIAbility instance be completely loaded and initialized. 328- Hot start: The UIAbility instance has been started, running in the foreground, and then switched to the background before being started again. In this case, the status of the UIAbility instance can be quickly restored. 329 330This section describes how to start a specified page in both modes: [cold start](#cold-starting-uiability) and [hot start](#hot-starting-uiability). Before starting a specified page, you will learn how to specify a startup page on the initiator UIAbility. 331 332 333### Specifying a Startup Page 334 335When the initiator [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) starts another UIAbility, it usually needs to redirect to a specified page of the target UIAbility. For example, with FuncAbility, which contains two pages, starting FuncAbility means to redirect to either of the pages: Index (corresponding to the home page) and Second (corresponding to feature A page). You can configure the specified page URL in the want parameter by adding a custom parameter to parameters in [want](../reference/apis-ability-kit/js-apis-app-ability-want.md). For details about how to obtain the context in the example, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). 336 337```ts 338import { common, Want } from '@kit.AbilityKit'; 339import { hilog } from '@kit.PerformanceAnalysisKit'; 340import { BusinessError } from '@kit.BasicServicesKit'; 341 342const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 343const DOMAIN_NUMBER: number = 0xFF00; 344 345@Entry 346@Component 347struct Page_UIAbilityComponentsInteractive { 348 build() { 349 Column() { 350 //... 351 List({ initialIndex: 0 }) { 352 ListItem() { 353 Row() { 354 //... 355 } 356 .onClick(() => { 357 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 358 let want: Want = { 359 deviceId: '', // An empty deviceId indicates the local device. 360 bundleName: 'com.samples.stagemodelabilityinteraction', 361 moduleName: 'entry', // moduleName is optional. 362 abilityName: 'FuncAbility', 363 parameters: { // Custom parameter used to pass the page information. 364 router: 'funcA' 365 } 366 }; 367 // context is the UIAbilityContext of the initiator UIAbility. 368 context.startAbility(want).then(() => { 369 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.'); 370 }).catch((err: BusinessError) => { 371 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 372 }); 373 }) 374 } 375 //... 376 } 377 //... 378 } 379 //... 380 } 381} 382``` 383 384 385### Cold Starting UIAbility 386 387In cold start mode, obtain the parameters from the initiator [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) through the [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate) callback of the target UIAbility. Then, in the [onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate) callback of the target UIAbility, parse the [want](../reference/apis-ability-kit/js-apis-app-ability-want.md) parameter passed by the EntryAbility to obtain the URL of the page to be loaded, and pass the URL to the [windowStage.loadContent()](../reference/apis-arkui/arkts-apis-window-Window.md#loadcontent9) method. 388 389```ts 390import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit'; 391import { hilog } from '@kit.PerformanceAnalysisKit'; 392import { window, UIContext } from '@kit.ArkUI'; 393 394const DOMAIN_NUMBER: number = 0xFF00; 395const TAG: string = '[EntryAbility]'; 396 397export default class EntryAbility extends UIAbility { 398 funcAbilityWant: Want | undefined = undefined; 399 uiContext: UIContext | undefined = undefined; 400 401 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 402 // Receive the parameters passed by the initiator UIAbility. 403 this.funcAbilityWant = want; 404 } 405 406 onWindowStageCreate(windowStage: window.WindowStage): void { 407 // Main window is created. Set a main page for this UIAbility. 408 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate'); 409 // Main window is created. Set a main page for this UIAbility. 410 let url = 'pages/Index'; 411 if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') { 412 url = 'pages/Page_ColdStartUp'; 413 } 414 windowStage.loadContent(url, (err, data) => { 415 // ... 416 }); 417 } 418} 419``` 420 421### Hot Starting UIAbility 422 423If the target [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) has been started, the initialization logic is not executed again. Instead, the [onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant) lifecycle callback is directly triggered. To implement redirection, parse the required parameters in **onNewWant()**. 424 425An example scenario is as follows: 426 4271. A user opens the SMS application. The UIAbility instance of the SMS application is started, and the home page of the application is displayed. 4282. The user returns to the home screen, and the SMS application switches to the background. 4293. The user opens the Contacts application and finds a contact. 4304. The user touches the SMS button next to the contact. The UIAbility instance of the SMS application is restarted. 4315. Since the UIAbility instance of the SMS application has been started, the onNewWant() callback of the UIAbility is triggered, and the initialization logic such as [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate) and [onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate) is skipped. 432 433**Figure 1** Hot starting the target UIAbility 434 435 436 437The development procedure is as follows: 438 4391. When the UIAbility instance of the SMS application is cold started, call [getUIContext()](../reference/apis-arkui/arkts-apis-window-Window.md#getuicontext10) in the [onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate) lifecycle callback to obtain the [UIContext](../reference/apis-arkui/arkts-apis-uicontext-uicontext.md). 440 441 ```ts 442 import { hilog } from '@kit.PerformanceAnalysisKit'; 443 import { Want, UIAbility } from '@kit.AbilityKit'; 444 import { window, UIContext } from '@kit.ArkUI'; 445 446 const DOMAIN_NUMBER: number = 0xFF00; 447 const TAG: string = '[EntryAbility]'; 448 449 export default class EntryAbility extends UIAbility { 450 funcAbilityWant: Want | undefined = undefined; 451 uiContext: UIContext | undefined = undefined; 452 453 // ... 454 455 onWindowStageCreate(windowStage: window.WindowStage): void { 456 // Main window is created. Set a main page for this UIAbility. 457 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate'); 458 let url = 'pages/Index'; 459 if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') { 460 url = 'pages/Page_ColdStartUp'; 461 } 462 463 windowStage.loadContent(url, (err, data) => { 464 if (err.code) { 465 return; 466 } 467 468 let windowClass: window.Window; 469 windowStage.getMainWindow((err, data) => { 470 if (err.code) { 471 hilog.error(DOMAIN_NUMBER, TAG, `Failed to obtain the main window. Code is ${err.code}, message is ${err.message}`); 472 return; 473 } 474 windowClass = data; 475 this.uiContext = windowClass.getUIContext(); 476 }); 477 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 478 }); 479 } 480 } 481 ``` 482 4832. In the [onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant) callback of the UIAbility instance of the SMS application, set the value of the global variable **nameForNavi** through AppStorage, and perform the specified page navigation. When the UIAbility instance of the SMS application is started again, the specified page of the UIAbility instance of the SMS application is displayed. 484 485 1. Import the required modules, and set the global variable **nameForNavi** in the **onNewWant()** lifecycle callback. 486 487 ```ts 488 import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit'; 489 import { hilog } from '@kit.PerformanceAnalysisKit'; 490 491 const DOMAIN_NUMBER: number = 0xFF00; 492 const TAG: string = '[EntryAbility]'; 493 494 export default class EntryAbility extends UIAbility { 495 // ... 496 onNewWant(want: Want, launchParam: AbilityConstant. LaunchParam): void { 497 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'onNewWant'); 498 AppStorage.setOrCreate<string>('nameForNavi', 'pageOne'); 499 } 500 } 501 ``` 502 503 2. When the Index page is displayed, trigger the **onPageShow** callback to obtain the value of **nameForNavi**, and execute the page navigation. 504 505 ```ts 506 // Index.ets 507 @Entry 508 @Component 509 struct Index { 510 @State message: string = 'Index'; 511 pathStack: NavPathStack = new NavPathStack(); 512 513 onPageShow(): void { 514 let somePage = AppStorage.get<string>('nameForNavi') 515 if (somePage) { 516 this.pathStack.pushPath({ name: somePage }, false); 517 AppStorage.delete('nameForNavi'); 518 } 519 } 520 521 build() { 522 Navigation(this.pathStack) { 523 Text(this.message) 524 .id('Index') 525 .fontSize($r('app.float.page_text_font_size')) 526 .fontWeight(FontWeight.Bold) 527 .alignRules({ 528 center: { anchor: '__container__', align: VerticalAlign.Center }, 529 middle: { anchor: '__container__', align: HorizontalAlign.Center } 530 }) 531 } 532 .mode(NavigationMode.Stack) 533 .height('100%') 534 .width('100%') 535 } 536 } 537 ``` 538 539 3. Implement the **Navigation** subpage. 540 541 ```ts 542 // PageOne.ets 543 @Builder 544 export function PageOneBuilder() { 545 PageOne(); 546 } 547 548 @Component 549 export struct PageOne { 550 @State message: string = 'PageOne'; 551 pathStack: NavPathStack = new NavPathStack(); 552 553 build() { 554 NavDestination() { 555 Text(this.message) 556 .id('PageOne') 557 .fontSize($r('app.float.page_text_font_size')) 558 .fontWeight(FontWeight.Bold) 559 .alignRules({ 560 center: { anchor: '__container__', align: VerticalAlign.Center }, 561 middle: { anchor: '__container__', align: HorizontalAlign.Center } 562 }) 563 } 564 .onReady((context: NavDestinationContext) => { 565 this.pathStack = context.pathStack; 566 }) 567 .height('100%') 568 .width('100%') 569 } 570 } 571 ``` 572 573 4. Configure subpages in the system configuration file **route_map.json**. For details, see [System Routing Table](../ui/arkts-navigation-navigation.md#system-routing-table). 574 575 ```ts 576 // route_map.json 577 { 578 "routerMap": [ 579 { 580 "name": "pageOne", 581 "pageSourceFile": "src/main/ets/pages/PageOne.ets", 582 "buildFunction": "PageOneBuilder", 583 "data": { 584 "description": "this is pageOne" 585 } 586 } 587 ] 588 } 589 ``` 590 591 5. Configure **routerMap** in the [module.json5](../quick-start/module-configuration-file.md#routermap) file. 592 593 ```ts 594 // module.json5 595 { 596 "module":{ 597 // ... 598 "routerMap": "$profile:route_map", 599 } 600 } 601 ``` 602 603> **NOTE** 604> 605> When the [launch type of the target UIAbility](uiability-launch-type.md) is set to **multiton**, a new instance is created each time the target UIAbility is started. In this case, the **onNewWant()** callback will not be invoked. 606 607<!--Del--> 608## Starting UIAbility with Window Mode Specified (for System Applications Only) 609 610By specifying the window mode when starting the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) of an application, you can have the application displayed in the specified window mode, which can be full-screen, floating window, or split-screen. 611 612In full-screen mode, an application occupies the entire screen after being started. Users cannot view other windows or applications. This mode is suitable for an application that requires users to focus on a specific task or UI. 613 614In floating window mode, an application is displayed on the screen as a floating window after being started. Users can easily switch to other windows or applications. This mode is suitable for an application that allows users to process multiple tasks at the same time. 615 616In split-screen mode, two applications occupy the entire screen, side by side, horizontally or vertically. This mode helps users improve multi-task processing efficiency. 617 618The window mode is specified by the **windowMode** field in the [StartOptions](../reference/apis-ability-kit/js-apis-app-ability-startOptions.md) parameter of [startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability). 619 620> **NOTE** 621> 622> - If the **windowMode** field is not specified, the UIAbility is started in the default window mode. 623> - To ensure that the application can be displayed in the required window mode, check the **supportWindowMode** field under [abilities](../quick-start/module-configuration-file.md#abilities) in the [module.json5 file](../quick-start/module-configuration-file.md) of the UIAbility and make sure the specified window mode is supported. 624 625The following describes how to start the FuncAbility from the EntryAbility page and display it in floating window mode. 626 6271. Add the **StartOptions** parameter in **startAbility()**. 6282. Set the **windowMode** field in the **StartOptions** parameter to **WINDOW_MODE_FLOATING**. This setting applies only to a system application. 6293. In the case of a third-party application, set the **displayId** field instead. 630 631For details about how to obtain the context in the example, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability). 632 633```ts 634import { AbilityConstant, common, Want, StartOptions } from '@kit.AbilityKit'; 635import { hilog } from '@kit.PerformanceAnalysisKit'; 636import { BusinessError } from '@kit.BasicServicesKit'; 637 638const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 639const DOMAIN_NUMBER: number = 0xFF00; 640 641@Entry 642@Component 643struct Page_UIAbilityComponentsInteractive { 644 build() { 645 Column() { 646 //... 647 List({ initialIndex: 0 }) { 648 ListItem() { 649 Row() { 650 //... 651 } 652 .onClick(() => { 653 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 654 let want: Want = { 655 deviceId: '', // An empty deviceId indicates the local device. 656 bundleName: 'com.samples.stagemodelabilitydevelop', 657 moduleName: 'entry', // moduleName is optional. 658 abilityName: 'FuncAbilityB', 659 parameters: { 660 // Custom information. 661 info: 'From the Index page of EntryAbility' 662 } 663 }; 664 let options: StartOptions = { 665 windowMode: AbilityConstant.WindowMode.WINDOW_MODE_FLOATING 666 }; 667 // context is the UIAbilityContext of the initiator UIAbility. 668 context.startAbility(want, options).then(() => { 669 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.'); 670 }).catch((err: BusinessError) => { 671 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 672 }); 673 }) 674 } 675 //... 676 } 677 //... 678 } 679 //... 680 } 681} 682``` 683 684The display effect is shown below. 685 686 687 688 689## Using Call to Implement UIAbility Interaction (for System Applications Only) 690 691Call is an extension of the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) 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 call to implement data sharing between two UIAbility instances (CallerAbility and CalleeAbility) through IPC. 692 693The core API used for the call is [startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall), which differs from [startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability) in the following ways: 694 695- **startAbilityByCall()** supports UIAbility launch in the foreground and background, whereas **startAbility()** supports UIAbility launch in the foreground only. 696 697- The CallerAbility can use the [Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller) object returned by **startAbilityByCall()** to communicate with the CalleeAbility, but **startAbility()** does not provide the communication capability. 698 699Call is usually used in the following scenarios: 700 701- Communicating with the CalleeAbility 702 703- Starting the CalleeAbility in the background 704 705 706**Table 1** Terms used in the call 707 708| **Term**| Description| 709| -------- | -------- | 710| CallerAbility| UIAbility that triggers the call.| 711| CalleeAbility | UIAbility invoked by the call.| 712| Caller | Object returned by **startAbilityByCall** and used by the CallerAbility to communicate with the CalleeAbility.| 713| Callee | Object held by the CalleeAbility to communicate with the CallerAbility.| 714 715The following figure shows the call process. 716 717**Figure 1** Call process 718 719 720 721- The CallerAbility uses [startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall) to obtain a [Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller) object and uses [call](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#call) of the Caller object to send data to the CalleeAbility. 722 723- The CalleeAbility, which holds a [Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee) object, uses [on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#on) of the Callee object to register a callback. This callback is invoked when the CalleeAbility receives data from the CallerAbility. 724 725> **NOTE** 726> 727> Currently, only system applications can use the call. 728> 729> The launch type of the CalleeAbility must be **singleton**. 730> 731> Both local (intra-device) and cross-device calls are supported. The following describes how to initiate a local call. For details about how to initiate a cross-device call, see [Using Cross-Device Call](hop-multi-device-collaboration.md#using-cross-device-call). 732 733 734### Available APIs 735 736The following table describes the main APIs used for the call. For details, see [AbilityContext](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller). 737 738**Table 2** Call APIs 739 740| API| Description| 741| -------- | -------- | 742| 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-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall) or **ServiceExtensionContext**.| 743| on(method: string, callback: CalleeCallBack): void | Callback invoked when the CalleeAbility registers a method.| 744| off(method: string): void | Callback invoked when the CalleeAbility deregisters a method.| 745| call(method: string, data: rpc.Parcelable): Promise<void> | Sends agreed parcelable data to the CalleeAbility.| 746| callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence> | Sends agreed parcelable data to the CalleeAbility and obtains the agreed parcelable data returned by the CalleeAbility.| 747| release(): void | Releases the caller object.| 748| on(type: "release", callback: OnReleaseCallback): void| Callback invoked when the caller object is released.| 749 750The implementation of using the call for [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) interaction involves two parts: 751 752- [Creating a CalleeAbility](#creating-a-calleeability) 753 754- [Accessing the CalleeAbility](#accessing-the-calleeability) 755 756 757### Creating a CalleeAbility 758 759For the CalleeAbility, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use [on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#on) to register a listener. When data does not need to be received, use [off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#off) to deregister the listener. 760 7611. Configure the launch type of the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md). 762 763 For example, set the launch type of the CalleeAbility to **singleton**. For details, see [UIAbility Component Launch Type](uiability-launch-type.md). 764 7652. Import the **UIAbility** module. 766 767 ```ts 768 import { UIAbility } from '@kit.AbilityKit'; 769 ``` 770 7713. Define the agreed parcelable data. 772 773 The data formats sent and received by the CallerAbility and CalleeAbility must be consistent. In the following example, the data formats are number and string. 774 775 ```ts 776 import { rpc } from '@kit.IPCKit'; 777 778 class MyParcelable { 779 num: number = 0; 780 str: string = ''; 781 782 constructor(num: number, string: string) { 783 this.num = num; 784 this.str = string; 785 } 786 787 mySequenceable(num: number, string: string): void { 788 this.num = num; 789 this.str = string; 790 } 791 792 marshalling(messageSequence: rpc.MessageSequence): boolean { 793 messageSequence.writeInt(this.num); 794 messageSequence.writeString(this.str); 795 return true; 796 } 797 798 unmarshalling(messageSequence: rpc.MessageSequence): boolean { 799 this.num = messageSequence.readInt(); 800 this.str = messageSequence.readString(); 801 return true; 802 } 803 } 804 ``` 805 8064. Implement [Callee.on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#on) and [Callee.off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#off). 807 808 The time to register a listener for the CalleeAbility 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](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate) of the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) and deregistered in [onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#ondestroy). After receiving parcelable 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: 809 810 ```ts 811 import { AbilityConstant, UIAbility, Want, Caller } from '@kit.AbilityKit'; 812 import { hilog } from '@kit.PerformanceAnalysisKit'; 813 import { rpc } from '@kit.IPCKit'; 814 815 const MSG_SEND_METHOD: string = 'CallSendMsg'; 816 const DOMAIN_NUMBER: number = 0xFF00; 817 const TAG: string = '[CalleeAbility]'; 818 819 class MyParcelable { 820 num: number = 0; 821 str: string = ''; 822 823 constructor(num: number, string: string) { 824 this.num = num; 825 this.str = string; 826 } 827 828 mySequenceable(num: number, string: string): void { 829 this.num = num; 830 this.str = string; 831 } 832 833 marshalling(messageSequence: rpc.MessageSequence): boolean { 834 messageSequence.writeInt(this.num); 835 messageSequence.writeString(this.str); 836 return true; 837 } 838 839 unmarshalling(messageSequence: rpc.MessageSequence): boolean { 840 this.num = messageSequence.readInt(); 841 this.str = messageSequence.readString(); 842 return true; 843 } 844 } 845 846 function sendMsgCallback(data: rpc.MessageSequence): rpc.Parcelable { 847 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'CalleeSortFunc called'); 848 849 // Obtain the parcelable data sent by the CallerAbility. 850 let receivedData: MyParcelable = new MyParcelable(0, ''); 851 data.readParcelable(receivedData); 852 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `receiveData[${receivedData.num}, ${receivedData.str}]`); 853 let num: number = receivedData.num; 854 855 // Process the data. 856 // Return the parcelable data result to the CallerAbility. 857 return new MyParcelable(num + 1, `send ${receivedData.str} succeed`) as rpc.Parcelable; 858 } 859 860 export default class CalleeAbility extends UIAbility { 861 caller: Caller | undefined; 862 863 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 864 try { 865 this.callee.on(MSG_SEND_METHOD, sendMsgCallback); 866 } catch (error) { 867 hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`); 868 } 869 } 870 871 releaseCall(): void { 872 try { 873 if (this.caller) { 874 this.caller.release(); 875 this.caller = undefined; 876 } 877 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'caller release succeed'); 878 } catch (error) { 879 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `caller release failed with ${error}`); 880 } 881 } 882 883 onDestroy(): void { 884 try { 885 this.callee.off(MSG_SEND_METHOD); 886 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Callee OnDestroy'); 887 this.releaseCall(); 888 } catch (error) { 889 hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`); 890 } 891 } 892 } 893 ``` 894 895 896### Accessing the CalleeAbility 897 8981. Import the [UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md) module. 899 900 ```ts 901 import { UIAbility } from '@kit.AbilityKit'; 902 ``` 903 9042. Obtain the [Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller) object. 905 906 The [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md) attribute implements [startAbilityByCall](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall) to obtain the Caller object for communication. The following example uses **this.context** to obtain the UIAbilityContext, uses **startAbilityByCall** to start the CalleeAbility, obtain the Caller object, and register the [onRelease](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onrelease) listener of the CallerAbility. You need to implement processing based on service requirements. 907 908 ```ts 909 import { common, Want, Caller } from '@kit.AbilityKit'; 910 import { hilog } from '@kit.PerformanceAnalysisKit'; 911 import { BusinessError } from '@kit.BasicServicesKit'; 912 913 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 914 const DOMAIN_NUMBER: number = 0xFF00; 915 916 @Entry 917 @Component 918 struct Page_UIAbilityComponentsInteractive { 919 caller: Caller | undefined = undefined; 920 921 // Register the onRelease() listener of the CallerAbility. 922 private regOnRelease(caller: Caller): void { 923 hilog.info(DOMAIN_NUMBER, TAG, `caller is ${caller}`); 924 try { 925 caller.on('release', (msg: string) => { 926 hilog.info(DOMAIN_NUMBER, TAG, `caller onRelease is called ${msg}`); 927 }) 928 hilog.info(DOMAIN_NUMBER, TAG, 'succeeded in registering on release.'); 929 } catch (err) { 930 let code = (err as BusinessError).code; 931 let message = (err as BusinessError).message; 932 hilog.error(DOMAIN_NUMBER, TAG, `Failed to caller register on release. Code is ${code}, message is ${message}`); 933 } 934 }; 935 936 build() { 937 Column() { 938 // ... 939 List({ initialIndex: 0 }) { 940 // ... 941 ListItem() { 942 Row() { 943 // ... 944 } 945 .onClick(() => { 946 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext 947 let want: Want = { 948 bundleName: 'com.samples.stagemodelabilityinteraction', 949 abilityName: 'CalleeAbility', 950 parameters: { 951 // Custom information. 952 info: 'CallSendMsg' 953 } 954 }; 955 context.startAbilityByCall(want).then((caller: Caller) => { 956 hilog.info(DOMAIN_NUMBER, TAG, `Succeeded in starting ability.Code is ${caller}`); 957 if (caller === undefined) { 958 hilog.info(DOMAIN_NUMBER, TAG, 'get caller failed'); 959 return; 960 } 961 else { 962 hilog.info(DOMAIN_NUMBER, TAG, 'get caller success'); 963 this.regOnRelease(caller); 964 this.getUIContext().getPromptAction().showToast({ 965 message: 'CallerSuccess' 966 }); 967 try { 968 caller.release(); 969 } catch (releaseErr) { 970 console.log('Caller.release catch error, error.code: ' + JSON.stringify(releaseErr.code) + 971 ' error.message: ' + JSON.stringify(releaseErr.message)); 972 } 973 } 974 }).catch((err: BusinessError) => { 975 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 976 }); 977 }) 978 } 979 // ... 980 } 981 // ... 982 } 983 // ... 984 } 985 } 986 ``` 987<!--DelEnd--> 988 989