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![](figures/uiability-hot-start.png)
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![](figures/start-uiability-floating-window.png)
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![call](figures/call.png)
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:&nbsp;Want):&nbsp;Promise&lt;Caller&gt; | 启动指定UIAbility并获取其Caller通信接口,默认为后台启动,通过配置want可实现前台启动,详见[接口文档](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilitybycall)。AbilityContext与ServiceExtensionContext均支持该接口。 |
649| on(method:&nbsp;string,&nbsp;callback:&nbsp;CalleeCallBack):&nbsp;void | 通用组件Callee注册method对应的callback方法。 |
650| off(method:&nbsp;string):&nbsp;void | 通用组件Callee解注册method的callback方法。 |
651| call(method:&nbsp;string,&nbsp;data:&nbsp;rpc.Parcelable):&nbsp;Promise&lt;void&gt; | 向通用组件Callee发送约定序列化数据。 |
652| callWithResult(method:&nbsp;string,&nbsp;data:&nbsp;rpc.Parcelable):&nbsp;Promise&lt;rpc.MessageSequence&gt; | 向通用组件Callee发送约定序列化数据,&nbsp;并将Callee返回的约定序列化数据带回。 |
653| release():&nbsp;void | 释放通用组件的Caller通信接口。 |
654| on(type:&nbsp;"release",&nbsp;callback:&nbsp;OnReleaseCallback):&nbsp;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)