1# 启动应用内的UIAbility组件 2 3 4[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,包括应用内的其他UIAbility、或者其他应用的UIAbility(例如启动三方支付UIAbility)。 5 6 7本文主要介绍启动应用内的UIAbility组件的方式。应用间的组件跳转详见[应用间跳转](link-between-apps-overview.md)。<!--Del-->对于跨设备的应用组件交互,请参见[应用组件跨设备交互(流转)](inter-device-interaction-hop-overview.md)。<!--DelEnd--> 8 9 10- [启动应用内的UIAbility](#启动应用内的uiability) 11- [启动应用内的UIAbility并获取返回结果](#启动应用内的uiability并获取返回结果) 12- [启动UIAbility的指定页面](#启动uiability的指定页面) 13<!--Del--> 14- [启动UIAbility指定窗口模式(仅对系统应用开放)](#启动uiability指定窗口模式仅对系统应用开放) 15- [通过Call调用实现UIAbility交互(仅对系统应用开放)](#通过call调用实现uiability交互仅对系统应用开放) 16<!--DelEnd--> 17 18 19## 启动应用内的UIAbility 20 21当一个应用内包含多个[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)时,存在应用内启动UIAbility的场景。例如在支付应用中从入口UIAbility启动收付款UIAbility。 22 23假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在不同的Module中),需要从EntryAbility的页面中启动FuncAbility。 24 251. 在EntryAbility中,通过调用[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)方法启动UIAbility,[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)为UIAbility实例启动的入口参数,其中bundleName为待启动应用的Bundle名称,abilityName为待启动的Ability名称,moduleName在待启动的UIAbility属于不同的Module时添加,parameters为自定义信息参数。示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。 26 27 ```ts 28 import { common, Want } from '@kit.AbilityKit'; 29 import { hilog } from '@kit.PerformanceAnalysisKit'; 30 import { BusinessError } from '@kit.BasicServicesKit'; 31 32 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 33 const DOMAIN_NUMBER: number = 0xFF00; 34 35 @Entry 36 @Component 37 struct Page_UIAbilityComponentsInteractive { 38 private context = getContext(this) as common.UIAbilityContext; 39 40 build() { 41 Column() { 42 //... 43 List({ initialIndex: 0 }) { 44 ListItem() { 45 Row() { 46 //... 47 } 48 .onClick(() => { 49 // context为Ability对象的成员,在非Ability对象内部调用需要 50 // 将Context对象传递过去 51 let wantInfo: Want = { 52 deviceId: '', // deviceId为空表示本设备 53 bundleName: 'com.samples.stagemodelabilitydevelop', 54 moduleName: 'entry', // moduleName非必选 55 abilityName: 'FuncAbilityA', 56 parameters: { 57 // 自定义信息 58 info: '来自EntryAbility Page_UIAbilityComponentsInteractive页面' 59 }, 60 }; 61 // context为调用方UIAbility的UIAbilityContext 62 this.context.startAbility(wantInfo).then(() => { 63 hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.'); 64 }).catch((error: BusinessError) => { 65 hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.'); 66 }); 67 }) 68 } 69 //... 70 } 71 //... 72 } 73 //... 74 } 75 } 76 ``` 77 782. 在FuncAbility的[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityoncreate)或者[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonnewwant)生命周期回调文件中接收EntryAbility传递过来的参数。 79 80 ```ts 81 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 82 83 export default class FuncAbilityA extends UIAbility { 84 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 85 // 接收调用方UIAbility传过来的参数 86 let funcAbilityWant = want; 87 let info = funcAbilityWant?.parameters?.info; 88 } 89 //... 90 } 91 ``` 92 93 > **说明:** 94 > 95 > 在被拉起的FuncAbility中,可以通过获取传递过来的[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)参数的`parameters`来获取拉起方[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的PID、Bundle Name等信息。 96 973. 在FuncAbility业务完成之后,如需要停止当前[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)实例,在FuncAbility中通过调用[terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextterminateself)方法实现。 98 99 ```ts 100 import { common } from '@kit.AbilityKit'; 101 import { hilog } from '@kit.PerformanceAnalysisKit'; 102 103 const TAG: string = '[Page_FromStageModel]'; 104 const DOMAIN_NUMBER: number = 0xFF00; 105 106 @Entry 107 @Component 108 struct Page_FromStageModel { 109 build() { 110 Column() { 111 //... 112 Button('FuncAbilityB') 113 .onClick(() => { 114 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 115 // context为需要停止的UIAbility实例的AbilityContext 116 context.terminateSelf((err) => { 117 if (err.code) { 118 hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`); 119 return; 120 } 121 }); 122 }) 123 } 124 //... 125 } 126 } 127 ``` 128 129 > **说明:** 130 > 131 > 调用terminateSelf()方法停止当前UIAbility实例时,默认会保留该实例的快照(Snapshot),即在最近任务列表中仍然能查看到该实例对应的任务。如不需要保留该实例的快照,可以在其对应UIAbility的[module.json5配置文件](../quick-start/module-configuration-file.md)中,将[abilities标签](../quick-start/module-configuration-file.md#abilities标签)的removeMissionAfterTerminate字段配置为true。 132 1334. 如需要关闭应用所有的[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)实例,可以调用[ApplicationContext](../reference/apis-ability-kit/js-apis-inner-application-applicationContext.md)的[killAllProcesses()](../reference/apis-ability-kit/js-apis-inner-application-applicationContext.md#applicationcontextkillallprocesses)方法实现关闭应用所有的进程。 134 135 136## 启动应用内的UIAbility并获取返回结果 137 138在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和账号登录功能分别设计为两个独立的[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md),在账号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。 139 1401. 在EntryAbility中,调用[startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilityforresult-2)接口启动FuncAbility,异步回调中的data用于接收FuncAbility停止自身后返回给EntryAbility的信息。示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。 141 142 ```ts 143 import { common, Want } from '@kit.AbilityKit'; 144 import { hilog } from '@kit.PerformanceAnalysisKit'; 145 import { promptAction } from '@kit.ArkUI'; 146 import { BusinessError } from '@kit.BasicServicesKit'; 147 148 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 149 const DOMAIN_NUMBER: number = 0xFF00; 150 151 @Entry 152 @Component 153 struct Page_UIAbilityComponentsInteractive { 154 build() { 155 Column() { 156 //... 157 List({ initialIndex: 0 }) { 158 ListItem() { 159 Row() { 160 //... 161 } 162 .onClick(() => { 163 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 164 const RESULT_CODE: number = 1001; 165 let want: Want = { 166 deviceId: '', // deviceId为空表示本设备 167 bundleName: 'com.samples.stagemodelabilitydevelop', 168 moduleName: 'entry', // moduleName非必选 169 abilityName: 'FuncAbilityA', 170 parameters: { 171 // 自定义信息 172 info: '来自EntryAbility UIAbilityComponentsInteractive页面' 173 } 174 }; 175 context.startAbilityForResult(want).then((data) => { 176 if (data?.resultCode === RESULT_CODE) { 177 // 解析被调用方UIAbility返回的信息 178 let info = data.want?.parameters?.info; 179 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? ''); 180 if (info !== null) { 181 promptAction.showToast({ 182 message: JSON.stringify(info) 183 }); 184 } 185 } 186 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? ''); 187 }).catch((err: BusinessError) => { 188 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`); 189 }); 190 }) 191 } 192 //... 193 } 194 //... 195 } 196 //... 197 } 198 } 199 ``` 200 2012. 在FuncAbility停止自身时,需要调用[terminateSelfWithResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextterminateselfwithresult)方法,入参[abilityResult](../reference/apis-ability-kit/js-apis-inner-ability-abilityResult.md)为FuncAbility需要返回给EntryAbility的信息。 202 203 ```ts 204 import { common } from '@kit.AbilityKit'; 205 import { hilog } from '@kit.PerformanceAnalysisKit'; 206 207 const TAG: string = '[Page_FuncAbilityA]'; 208 const DOMAIN_NUMBER: number = 0xFF00; 209 210 @Entry 211 @Component 212 struct Page_FuncAbilityA { 213 build() { 214 Column() { 215 //... 216 List({ initialIndex: 0 }) { 217 ListItem() { 218 Row() { 219 //... 220 } 221 .onClick(() => { 222 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 223 const RESULT_CODE: number = 1001; 224 let abilityResult: common.AbilityResult = { 225 resultCode: RESULT_CODE, 226 want: { 227 bundleName: 'com.samples.stagemodelabilitydevelop', 228 moduleName: 'entry', // moduleName非必选 229 abilityName: 'FuncAbilityB', 230 parameters: { 231 info: '来自FuncAbility Index页面' 232 }, 233 }, 234 }; 235 context.terminateSelfWithResult(abilityResult, (err) => { 236 if (err.code) { 237 hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`); 238 return; 239 } 240 }); 241 }) 242 } 243 //... 244 } 245 //... 246 } 247 //... 248 } 249 } 250 ``` 251 2523. FuncAbility停止自身后,EntryAbility通过[startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilityforresult-2)方法回调接收被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致。 253 254 ```ts 255 import { common, Want } from '@kit.AbilityKit'; 256 import { hilog } from '@kit.PerformanceAnalysisKit'; 257 import { promptAction } from '@kit.ArkUI'; 258 import { BusinessError } from '@kit.BasicServicesKit'; 259 260 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 261 const DOMAIN_NUMBER: number = 0xFF00; 262 263 @Entry 264 @Component 265 struct Page_UIAbilityComponentsInteractive { 266 build() { 267 Column() { 268 //... 269 List({ initialIndex: 0 }) { 270 ListItem() { 271 Row() { 272 //... 273 } 274 .onClick(() => { 275 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 276 const RESULT_CODE: number = 1001; 277 278 let want: Want = { 279 deviceId: '', // deviceId为空表示本设备 280 bundleName: 'com.samples.stagemodelabilitydevelop', 281 moduleName: 'entry', // moduleName非必选 282 abilityName: 'FuncAbilityA', 283 parameters: { 284 // 自定义信息 285 info: '来自EntryAbility UIAbilityComponentsInteractive页面' 286 } 287 }; 288 context.startAbilityForResult(want).then((data) => { 289 if (data?.resultCode === RESULT_CODE) { 290 // 解析被调用方UIAbility返回的信息 291 let info = data.want?.parameters?.info; 292 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? ''); 293 if (info !== null) { 294 promptAction.showToast({ 295 message: JSON.stringify(info) 296 }); 297 } 298 } 299 hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? ''); 300 }).catch((err: BusinessError) => { 301 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`); 302 }); 303 }) 304 } 305 //... 306 } 307 //... 308 } 309 //... 310 } 311 } 312 ``` 313 314 315## 启动UIAbility的指定页面 316 317### 概述 318 319一个[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。 320 321UIAbility的启动分为两种情况:UIAbility冷启动和UIAbility热启动。 322 323- UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。 324- UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。 325 326本文主要讲解[目标UIAbility冷启动](#目标uiability冷启动)和[目标UIAbility热启动](#目标uiability热启动)两种启动指定页面的场景,以及在讲解启动指定页面之前会讲解到在调用方如何指定启动页面。 327 328 329### 调用方UIAbility指定启动页面 330 331调用方[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)启动另外一个UIAbility时,通常需要跳转到指定的页面。例如FuncAbility包含两个页面(Index对应首页,Second对应功能A页面),此时需要在传入的[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)参数中配置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。 332 333 334```ts 335import { common, Want } from '@kit.AbilityKit'; 336import { hilog } from '@kit.PerformanceAnalysisKit'; 337import { BusinessError } from '@kit.BasicServicesKit'; 338 339const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 340const DOMAIN_NUMBER: number = 0xFF00; 341 342@Entry 343@Component 344struct Page_UIAbilityComponentsInteractive { 345 build() { 346 Column() { 347 //... 348 List({ initialIndex: 0 }) { 349 ListItem() { 350 Row() { 351 //... 352 } 353 .onClick(() => { 354 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 355 let want: Want = { 356 deviceId: '', // deviceId为空表示本设备 357 bundleName: 'com.samples.stagemodelabilityinteraction', 358 moduleName: 'entry', // moduleName非必选 359 abilityName: 'FuncAbility', 360 parameters: { // 自定义参数传递页面信息 361 router: 'funcA' 362 } 363 }; 364 // context为调用方UIAbility的UIAbilityContext 365 context.startAbility(want).then(() => { 366 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.'); 367 }).catch((err: BusinessError) => { 368 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 369 }); 370 }) 371 } 372 //... 373 } 374 //... 375 } 376 //... 377 } 378} 379``` 380 381 382### 目标UIAbility冷启动 383 384目标[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)冷启动时,在目标UIAbility的[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityoncreate)生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate)生命周期回调中,解析调用方传递过来的[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)参数,获取到需要加载的页面信息url,传入[windowStage.loadContent()](../reference/apis-arkui/js-apis-window.md#loadcontent9)方法。 385 386 387```ts 388import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit'; 389import { hilog } from '@kit.PerformanceAnalysisKit'; 390import { window, UIContext } from '@kit.ArkUI'; 391 392const DOMAIN_NUMBER: number = 0xFF00; 393const TAG: string = '[EntryAbility]'; 394 395export default class EntryAbility extends UIAbility { 396 funcAbilityWant: Want | undefined = undefined; 397 uiContext: UIContext | undefined = undefined; 398 399 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 400 // 接收调用方UIAbility传过来的参数 401 this.funcAbilityWant = want; 402 } 403 404 onWindowStageCreate(windowStage: window.WindowStage): void { 405 // Main window is created, set main page for this ability 406 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate'); 407 // Main window is created, set main page for this ability 408 let url = 'pages/Index'; 409 if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') { 410 url = 'pages/Page_ColdStartUp'; 411 } 412 windowStage.loadContent(url, (err, data) => { 413 // ... 414 }); 415 } 416} 417``` 418 419### 目标UIAbility热启动 420 421在应用开发中,会遇到目标[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonnewwant)生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理。 422 423例如短信应用和联系人应用配合使用的场景。 424 4251. 用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。 4262. 用户将设备回到桌面界面,短信应用进入后台运行状态。 4273. 用户打开联系人应用,找到联系人张三。 4284. 用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。 4295. 由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的onNewWant()回调,而不会再走[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityoncreate)和[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate)等初始化逻辑。 430 431图1 目标UIAbility热启动 432 433 434开发步骤如下所示。 435 4361. 冷启动短信应用的UIAbility实例时,在[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate)生命周期回调中,通过调用[getUIContext()](../reference/apis-arkui/js-apis-window.md#getuicontext10)接口获取UI上下文实例[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md)对象。 437 438 ```ts 439 import { hilog } from '@kit.PerformanceAnalysisKit'; 440 import { Want, UIAbility } from '@kit.AbilityKit'; 441 import { window, UIContext } from '@kit.ArkUI'; 442 443 const DOMAIN_NUMBER: number = 0xFF00; 444 const TAG: string = '[EntryAbility]'; 445 446 export default class EntryAbility extends UIAbility { 447 funcAbilityWant: Want | undefined = undefined; 448 uiContext: UIContext | undefined = undefined; 449 450 // ... 451 452 onWindowStageCreate(windowStage: window.WindowStage): void { 453 // Main window is created, set main page for this ability 454 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate'); 455 let url = 'pages/Index'; 456 if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') { 457 url = 'pages/Page_ColdStartUp'; 458 } 459 460 windowStage.loadContent(url, (err, data) => { 461 if (err.code) { 462 return; 463 } 464 465 let windowClass: window.Window; 466 windowStage.getMainWindow((err, data) => { 467 if (err.code) { 468 hilog.error(DOMAIN_NUMBER, TAG, `Failed to obtain the main window. Code is ${err.code}, message is ${err.message}`); 469 return; 470 } 471 windowClass = data; 472 this.uiContext = windowClass.getUIContext(); 473 }); 474 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 475 }); 476 } 477 } 478 ``` 479 4802. 在短信应用UIAbility的[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityonnewwant)回调中解析调用方传递过来的[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)参数,通过调用[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md)中的[getRouter()](../reference/apis-arkui/js-apis-arkui-UIContext.md#getrouter)方法获取[Router](../reference/apis-arkui/js-apis-arkui-UIContext.md#router)对象,并进行指定页面的跳转。此时再次启动该短信应用的UIAbility实例时,即可跳转到该短信应用的UIAbility实例的指定页面。 481 482 ```ts 483 import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit'; 484 import { hilog } from '@kit.PerformanceAnalysisKit'; 485 import type { Router, UIContext } from '@kit.ArkUI'; 486 import type { BusinessError } from '@kit.BasicServicesKit'; 487 488 const DOMAIN_NUMBER: number = 0xFF00; 489 const TAG: string = '[EntryAbility]'; 490 491 export default class EntryAbility extends UIAbility { 492 funcAbilityWant: Want | undefined = undefined; 493 uiContext: UIContext | undefined = undefined; 494 // ... 495 onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { 496 if (want?.parameters?.router && want.parameters.router === 'funcA') { 497 let funcAUrl = 'pages/Page_HotStartUp'; 498 if (this.uiContext) { 499 let router: Router = this.uiContext.getRouter(); 500 router.pushUrl({ 501 url: funcAUrl 502 }).catch((err: BusinessError) => { 503 hilog.error(DOMAIN_NUMBER, TAG, `Failed to push url. Code is ${err.code}, message is ${err.message}`); 504 }); 505 } 506 } 507 } 508 } 509 ``` 510 511> **说明:** 512> 513> 当被调用方[UIAbility组件启动模式](uiability-launch-type.md)设置为multiton启动模式时,每次启动都会创建一个新的实例,那么onNewWant()回调就不会被用到。 514 515<!--Del--> 516## 启动UIAbility指定窗口模式(仅对系统应用开放) 517 518当用户打开应用时,应用程序会以不同的窗口模式进行展示,即启动[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的窗口模式。应用程序可以启动为全屏模式,悬浮窗模式或分屏模式。 519 520全屏模式是指应用程序启动后,占据整个屏幕,用户无法同时查看其他窗口或应用程序。全屏模式通常适用于那些要求用户专注于特定任务或界面的应用程序。 521 522悬浮窗模式是指应用程序启动后,以浮动窗口的形式显示在屏幕上,用户可以轻松切换到其他窗口或应用程序。悬浮窗通常适用于需要用户同时处理多个任务的应用程序。 523 524分屏模式允许用户在同一屏幕上同时运行两个应用程序,其中一个应用程序占据屏幕左侧/上侧的一部分,另一个应用程序占据右侧/下侧的一部分。分屏模式主要用于提高用户的多任务处理效率。 525 526使用[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)方法启动UIAbility时,可以通过在入参中增加[StartOptions](../reference/apis-ability-kit/js-apis-app-ability-startOptions.md)参数的windowMode属性来配置启动UIAbility的窗口模式。 527 528> **说明:** 529> 530> 1. 如果在使用startAbility()方法启动UIAbility时,入参中未指定StartOptions参数的windowMode属性,那么UIAbility将以系统默认的窗口展示形态启动。 531> 2. 为了确保启动的UIAbility展示形态能够被支持,需要在该UIAbility对应的[module.json5配置文件](../quick-start/module-configuration-file.md)中[abilities标签](../quick-start/module-configuration-file.md#abilities标签)的supportWindowMode字段确认启动的展示形态被支持。 532 533以下是具体的操作步骤,以悬浮窗模式为例,假设需要从EntryAbility的页面中启动FuncAbility: 534 5351. 在调用startAbility()方法时,增加StartOptions参数。 5362. 在StartOptions参数中设置windowMode字段为WINDOW_MODE_FLOATING,表示启动的UIAbility将以悬浮窗的形式展示。 5373. windowMode属性仅适用于系统应用,三方应用可以使用displayId属性。 538 539示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。 540 541```ts 542import { AbilityConstant, common, Want, StartOptions } from '@kit.AbilityKit'; 543import { hilog } from '@kit.PerformanceAnalysisKit'; 544import { BusinessError } from '@kit.BasicServicesKit'; 545 546const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 547const DOMAIN_NUMBER: number = 0xFF00; 548 549@Entry 550@Component 551struct Page_UIAbilityComponentsInteractive { 552 build() { 553 Column() { 554 //... 555 List({ initialIndex: 0 }) { 556 ListItem() { 557 Row() { 558 //... 559 } 560 .onClick(() => { 561 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 562 let want: Want = { 563 deviceId: '', // deviceId为空表示本设备 564 bundleName: 'com.samples.stagemodelabilitydevelop', 565 moduleName: 'entry', // moduleName非必选 566 abilityName: 'FuncAbilityB', 567 parameters: { 568 // 自定义信息 569 info: '来自EntryAbility Index页面' 570 } 571 }; 572 let options: StartOptions = { 573 windowMode: AbilityConstant.WindowMode.WINDOW_MODE_FLOATING 574 }; 575 // context为调用方UIAbility的UIAbilityContext 576 context.startAbility(want, options).then(() => { 577 hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.'); 578 }).catch((err: BusinessError) => { 579 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 580 }); 581 }) 582 } 583 //... 584 } 585 //... 586 } 587 //... 588 } 589} 590``` 591 592效果示意如下图所示。 593 594 595 596 597## 通过Call调用实现UIAbility交互(仅对系统应用开放) 598 599Call调用是[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)能力的扩展,它为UIAbility提供一种能够被外部调用并与外部进行通信的能力。Call调用支持前台与后台两种启动方式,使UIAbility既能被拉起到前台展示UI,也可以在后台被创建并运行。Call调用在调用方与被调用方间建立了IPC通信,因此应用开发者可通过Call调用实现不同UIAbility之间的数据共享。 600 601Call调用的核心接口是[startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilitybycall)方法,与[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)接口的不同之处在于: 602 603- startAbilityByCall支持前台与后台两种启动方式,而startAbility()仅支持前台启动。 604 605- 调用方可使用startAbilityByCall()所返回的[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)对象与被调用方进行通信,而startAbility()不具备通信能力。 606 607Call调用的使用场景主要包括: 608 609- 需要与被启动的UIAbility进行通信。 610 611- 希望被启动的UIAbility在后台运行。 612 613 614**表1** Call调用相关名词解释 615 616| 名词 | 描述 | 617| -------- | -------- | 618| CallerAbility | 进行Call调用的UIAbility(调用方)。 | 619| CalleeAbility | 被Call调用的UIAbility(被调用方)。 | 620| Caller | 实际对象,由startAbilityByCall接口返回,CallerAbility可使用Caller与CalleeAbility进行通信。 | 621| Callee | 实际对象,被CalleeAbility持有,可与Caller进行通信。 | 622 623Call调用示意图如下所示。 624 625**图1** Call调用示意图 626 627 628- CallerAbility调用[startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilitybycall)接口获取[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller),并使用Caller对象的[call](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callercall)方法向CalleeAbility发送数据。 629 630- CalleeAbility持有一个[Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee)对象,通过Callee的[on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeon)方法注册回调函数,当接收到Caller发送的数据时将会调用对应的回调函数。 631 632> **说明:** 633> 1. 当前仅支持系统应用使用Call调用。 634> 635> 2. CalleeAbility的启动模式需要为单实例。 636> 637> 3. Call调用既支持本地(设备内)Call调用,也支持跨设备Call调用,下面介绍设备内Call调用方法。跨设备Call调用方法请参见[跨设备Call调用](hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)。 638 639 640### 接口说明 641 642Call功能主要接口如下表所示。具体的API详见[接口文档](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)。 643 644**表2** Call功能主要接口 645 646| 接口名 | 描述 | 647| -------- | -------- | 648| startAbilityByCall(want: Want): Promise<Caller> | 启动指定UIAbility并获取其Caller通信接口,默认为后台启动,通过配置want可实现前台启动,详见[接口文档](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilitybycall)。AbilityContext与ServiceExtensionContext均支持该接口。 | 649| on(method: string, callback: CalleeCallBack): void | 通用组件Callee注册method对应的callback方法。 | 650| off(method: string): void | 通用组件Callee解注册method的callback方法。 | 651| call(method: string, data: rpc.Parcelable): Promise<void> | 向通用组件Callee发送约定序列化数据。 | 652| callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence> | 向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。 | 653| release(): void | 释放通用组件的Caller通信接口。 | 654| on(type: "release", callback: OnReleaseCallback): void | 注册通用组件通信断开监听通知。 | 655 656设备内通过Call调用实现[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)交互,涉及如下两部分开发: 657 658- [创建Callee被调用端](#开发步骤创建callee被调用端) 659 660- [访问Callee被调用端](#开发步骤访问callee被调用端) 661 662 663### 开发步骤(创建Callee被调用端) 664 665在[Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee)被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过[on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeon)接口注册监听,无需接收数据时通过[off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeoff)接口解除监听。 666 6671. 配置[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的启动模式。 668 669 例如将CalleeAbility配置为单实例模式`singleton`,配置方式请参见[UIAbility组件启动模式](uiability-launch-type.md)。 670 6712. 导入UIAbility模块。 672 673 ```ts 674 import { UIAbility } from '@kit.AbilityKit'; 675 ``` 676 6773. 定义约定的序列化数据。 678 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。 679 680 681 ```ts 682 import { rpc } from '@kit.IPCKit'; 683 684 class MyParcelable { 685 num: number = 0; 686 str: string = ''; 687 688 constructor(num: number, string: string) { 689 this.num = num; 690 this.str = string; 691 } 692 693 mySequenceable(num: number, string: string): void { 694 this.num = num; 695 this.str = string; 696 } 697 698 marshalling(messageSequence: rpc.MessageSequence): boolean { 699 messageSequence.writeInt(this.num); 700 messageSequence.writeString(this.str); 701 return true; 702 } 703 704 unmarshalling(messageSequence: rpc.MessageSequence): boolean { 705 this.num = messageSequence.readInt(); 706 this.str = messageSequence.readString(); 707 return true; 708 } 709 } 710 ``` 711 7124. 实现[Callee.on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeon)监听及[Callee.off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleeoff)解除监听。 713 714 被调用端[Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee)的监听函数注册时机,取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的[onCreate](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityoncreate)注册'MSG_SEND_METHOD'监听,在[onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#uiabilityondestroy)取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下: 715 716 717 ```ts 718 import { AbilityConstant, UIAbility, Want, Caller } from '@kit.AbilityKit'; 719 import { hilog } from '@kit.PerformanceAnalysisKit'; 720 import { rpc } from '@kit.IPCKit'; 721 722 const MSG_SEND_METHOD: string = 'CallSendMsg'; 723 const DOMAIN_NUMBER: number = 0xFF00; 724 const TAG: string = '[CalleeAbility]'; 725 726 class MyParcelable { 727 num: number = 0; 728 str: string = ''; 729 730 constructor(num: number, string: string) { 731 this.num = num; 732 this.str = string; 733 } 734 735 mySequenceable(num: number, string: string): void { 736 this.num = num; 737 this.str = string; 738 } 739 740 marshalling(messageSequence: rpc.MessageSequence): boolean { 741 messageSequence.writeInt(this.num); 742 messageSequence.writeString(this.str); 743 return true; 744 } 745 746 unmarshalling(messageSequence: rpc.MessageSequence): boolean { 747 this.num = messageSequence.readInt(); 748 this.str = messageSequence.readString(); 749 return true; 750 } 751 } 752 753 function sendMsgCallback(data: rpc.MessageSequence): rpc.Parcelable { 754 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'CalleeSortFunc called'); 755 756 // 获取Caller发送的序列化数据 757 let receivedData: MyParcelable = new MyParcelable(0, ''); 758 data.readParcelable(receivedData); 759 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `receiveData[${receivedData.num}, ${receivedData.str}]`); 760 let num: number = receivedData.num; 761 762 // 作相应处理 763 // 返回序列化数据result给Caller 764 return new MyParcelable(num + 1, `send ${receivedData.str} succeed`) as rpc.Parcelable; 765 } 766 767 export default class CalleeAbility extends UIAbility { 768 caller: Caller | undefined; 769 770 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 771 try { 772 this.callee.on(MSG_SEND_METHOD, sendMsgCallback); 773 } catch (error) { 774 hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`); 775 } 776 } 777 778 releaseCall(): void { 779 try { 780 if (this.caller) { 781 this.caller.release(); 782 this.caller = undefined; 783 } 784 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'caller release succeed'); 785 } catch (error) { 786 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `caller release failed with ${error}`); 787 } 788 } 789 790 onDestroy(): void { 791 try { 792 this.callee.off(MSG_SEND_METHOD); 793 hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Callee OnDestroy'); 794 this.releaseCall(); 795 } catch (error) { 796 hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`); 797 } 798 } 799 } 800 ``` 801 802 803### 开发步骤(访问Callee被调用端) 804 8051. 导入[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)模块。 806 807 ```ts 808 import { UIAbility } from '@kit.AbilityKit'; 809 ``` 810 8112. 获取[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)通信接口。 812 813 [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md)属性实现了[startAbilityByCall](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartabilitybycall)方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取UIAbility实例的context属性,使用startAbilityByCall拉起[Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee)被调用端并获取Caller通信接口,注册Caller的[onRelease](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#calleronrelease)监听。应用开发者根据实际需要做相应处理。 814 815 816 ```ts 817 import { common, Want, Caller } from '@kit.AbilityKit'; 818 import { hilog } from '@kit.PerformanceAnalysisKit'; 819 import { promptAction } from '@kit.ArkUI'; 820 import { BusinessError } from '@kit.BasicServicesKit'; 821 822 const TAG: string = '[Page_UIAbilityComponentsInteractive]'; 823 const DOMAIN_NUMBER: number = 0xFF00; 824 825 @Entry 826 @Component 827 struct Page_UIAbilityComponentsInteractive { 828 caller: Caller | undefined = undefined; 829 830 // 注册caller的release监听 831 private regOnRelease(caller: Caller): void { 832 hilog.info(DOMAIN_NUMBER, TAG, `caller is ${caller}`); 833 try { 834 caller.on('release', (msg: string) => { 835 hilog.info(DOMAIN_NUMBER, TAG, `caller onRelease is called ${msg}`); 836 }) 837 hilog.info(DOMAIN_NUMBER, TAG, 'succeeded in registering on release.'); 838 } catch (err) { 839 let code = (err as BusinessError).code; 840 let message = (err as BusinessError).message; 841 hilog.error(DOMAIN_NUMBER, TAG, `Failed to caller register on release. Code is ${code}, message is ${message}`); 842 } 843 }; 844 845 build() { 846 Column() { 847 // ... 848 List({ initialIndex: 0 }) { 849 // ... 850 ListItem() { 851 Row() { 852 // ... 853 } 854 .onClick(() => { 855 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext 856 let want: Want = { 857 bundleName: 'com.samples.stagemodelabilityinteraction', 858 abilityName: 'CalleeAbility', 859 parameters: { 860 // 自定义信息 861 info: 'CallSendMsg' 862 } 863 }; 864 context.startAbilityByCall(want).then((caller: Caller) => { 865 hilog.info(DOMAIN_NUMBER, TAG, `Succeeded in starting ability.Code is ${caller}`); 866 if (caller === undefined) { 867 hilog.info(DOMAIN_NUMBER, TAG, 'get caller failed'); 868 return; 869 } 870 else { 871 hilog.info(DOMAIN_NUMBER, TAG, 'get caller success'); 872 this.regOnRelease(caller); 873 promptAction.showToast({ 874 message: 'CallerSuccess' 875 }); 876 try { 877 caller.release(); 878 } catch (releaseErr) { 879 console.log('Caller.release catch error, error.code: ' + JSON.stringify(releaseErr.code) + 880 ' error.message: ' + JSON.stringify(releaseErr.message)); 881 } 882 } 883 }).catch((err: BusinessError) => { 884 hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`); 885 }); 886 }) 887 } 888 // ... 889 } 890 // ... 891 } 892 // ... 893 } 894 } 895 ``` 896<!--DelEnd--> 897 898## 相关实例 899 900针对UIAbility组件间交互开发,有以下相关实例可供参考: 901 902- [UIAbility内和UIAbility间页面的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/StageAbility) 903- [UIAbility内页面间的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/PagesRouter)