• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 启动应用内的UIAbility组件
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)是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,包括应用内的其他UIAbility、或者其他应用的UIAbility(例如启动三方支付UIAbility)。
11
12
13本文主要介绍启动应用内的UIAbility组件的方式。应用间的组件跳转详见[应用间跳转](link-between-apps-overview.md)。<!--Del-->对于跨设备的应用组件交互,请参见[应用组件跨设备交互(流转)](inter-device-interaction-hop-overview.md)。<!--DelEnd-->
14
15
16- [启动应用内的UIAbility](#启动应用内的uiability)
17- [启动应用内的UIAbility并获取返回结果](#启动应用内的uiability并获取返回结果)
18- [启动UIAbility的指定页面](#启动uiability的指定页面)
19<!--Del-->
20- [启动UIAbility指定窗口模式(仅对系统应用开放)](#启动uiability指定窗口模式仅对系统应用开放)
21- [通过Call调用实现UIAbility交互(仅对系统应用开放)](#通过call调用实现uiability交互仅对系统应用开放)
22<!--DelEnd-->
23
24
25## 启动应用内的UIAbility
26
27当一个应用内包含多个[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)时,存在应用内启动UIAbility的场景。例如在支付应用中从入口UIAbility启动收付款UIAbility。
28
29假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在不同的Module中),需要从EntryAbility的页面中启动FuncAbility。
30
311. 在EntryAbility中,通过调用[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability)方法启动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的上下文信息)。
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为Ability对象的成员,在非Ability对象内部调用需要
56                // 将Context对象传递过去
57                let wantInfo: Want = {
58                  deviceId: '', // deviceId为空表示本设备
59                  bundleName: 'com.samples.stagemodelabilitydevelop',
60                  moduleName: 'entry', // moduleName非必选
61                  abilityName: 'FuncAbilityA',
62                  parameters: {
63                    // 自定义信息
64                    info: '来自EntryAbility Page_UIAbilityComponentsInteractive页面'
65                  },
66                };
67                // context为调用方UIAbility的UIAbilityContext
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. 在FuncAbility的[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate)或者[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant)生命周期回调文件中接收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        // 接收调用方UIAbility传过来的参数
92        let funcAbilityWant = want;
93        let info = funcAbilityWant?.parameters?.info;
94      }
95      //...
96    }
97    ```
98
99    > **说明:**
100    >
101    > 在被拉起的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等信息。
102
1033. 在FuncAbility业务完成之后,如需要停止当前[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)实例,在FuncAbility中通过调用[terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#terminateself)方法实现。
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为需要停止的UIAbility实例的AbilityContext
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    > **说明:**
136    >
137    > 调用terminateSelf()方法停止当前UIAbility实例时,默认会保留该实例的快照(Snapshot),即在最近任务列表中仍然能查看到该实例对应的任务。如不需要保留该实例的快照,可以在其对应UIAbility的[module.json5配置文件](../quick-start/module-configuration-file.md)中,将[abilities标签](../quick-start/module-configuration-file.md#abilities标签)的removeMissionAfterTerminate字段配置为true。
138
1394. 如需要关闭应用所有的[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)方法实现关闭应用所有的进程。
140
141
142## 启动应用内的UIAbility并获取返回结果
143
144在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和账号登录功能分别设计为两个独立的[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md),在账号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。
145
1461. 在EntryAbility中,调用[startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilityforresult-2)接口启动FuncAbility,异步回调中的data用于接收FuncAbility停止自身后返回给EntryAbility的信息。示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取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: '', // deviceId为空表示本设备
172                  bundleName: 'com.samples.stagemodelabilitydevelop',
173                  moduleName: 'entry', // moduleName非必选
174                  abilityName: 'FuncAbilityA',
175                  parameters: {
176                    // 自定义信息
177                    info: '来自EntryAbility UIAbilityComponentsInteractive页面'
178                  }
179                };
180                context.startAbilityForResult(want).then((data) => {
181                  if (data?.resultCode === RESULT_CODE) {
182                    // 解析被调用方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. 在FuncAbility停止自身时,需要调用[terminateSelfWithResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#terminateselfwithresult)方法,入参[abilityResult](../reference/apis-ability-kit/js-apis-inner-ability-abilityResult.md)为FuncAbility需要返回给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非必选
234                    abilityName: 'FuncAbilityB',
235                    parameters: {
236                      info: '来自FuncAbility Index页面'
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. FuncAbility停止自身后,EntryAbility通过[startAbilityForResult()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilityforresult-2)方法回调接收被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致。
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: '', // deviceId为空表示本设备
284                  bundleName: 'com.samples.stagemodelabilitydevelop',
285                  moduleName: 'entry', // moduleName非必选
286                  abilityName: 'FuncAbilityA',
287                  parameters: {
288                    // 自定义信息
289                    info: '来自EntryAbility UIAbilityComponentsInteractive页面'
290                  }
291                };
292                context.startAbilityForResult(want).then((data) => {
293                  if (data?.resultCode === RESULT_CODE) {
294                    // 解析被调用方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## 启动UIAbility的指定页面
320
321### 概述
322
323一个[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。
324
325UIAbility的启动分为两种情况:UIAbility冷启动和UIAbility热启动。
326
327- UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。
328- UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。
329
330本文主要讲解[目标UIAbility冷启动](#目标uiability冷启动)和[目标UIAbility热启动](#目标uiability热启动)两种启动指定页面的场景,以及在讲解启动指定页面之前会讲解到在调用方如何指定启动页面。
331
332
333### 调用方UIAbility指定启动页面
334
335调用方[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的上下文信息)。
336
337
338```ts
339import { common, Want } from '@kit.AbilityKit';
340import { hilog } from '@kit.PerformanceAnalysisKit';
341import { BusinessError } from '@kit.BasicServicesKit';
342
343const TAG: string = '[Page_UIAbilityComponentsInteractive]';
344const DOMAIN_NUMBER: number = 0xFF00;
345
346@Entry
347@Component
348struct Page_UIAbilityComponentsInteractive {
349  build() {
350    Column() {
351      //...
352      List({ initialIndex: 0 }) {
353        ListItem() {
354          Row() {
355            //...
356          }
357          .onClick(() => {
358            let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
359            let want: Want = {
360              deviceId: '', // deviceId为空表示本设备
361              bundleName: 'com.samples.stagemodelabilityinteraction',
362              moduleName: 'entry', // moduleName非必选
363              abilityName: 'FuncAbility',
364              parameters: { // 自定义参数传递页面信息
365                router: 'funcA'
366              }
367            };
368            // context为调用方UIAbility的UIAbilityContext
369            context.startAbility(want).then(() => {
370              hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.');
371            }).catch((err: BusinessError) => {
372              hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
373            });
374          })
375        }
376        //...
377      }
378      //...
379    }
380    //...
381  }
382}
383```
384
385
386### 目标UIAbility冷启动
387
388目标[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)冷启动时,在目标UIAbility的[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate)生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate)生命周期回调中,解析调用方传递过来的[want](../reference/apis-ability-kit/js-apis-app-ability-want.md)参数,获取到需要加载的页面信息url,传入[windowStage.loadContent()](../reference/apis-arkui/arkts-apis-window-Window.md#loadcontent9)方法。
389
390
391```ts
392import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit';
393import { hilog } from '@kit.PerformanceAnalysisKit';
394import { window, UIContext } from '@kit.ArkUI';
395
396const DOMAIN_NUMBER: number = 0xFF00;
397const TAG: string = '[EntryAbility]';
398
399export default class EntryAbility extends UIAbility {
400  funcAbilityWant: Want | undefined = undefined;
401  uiContext: UIContext | undefined = undefined;
402
403  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
404    // 接收调用方UIAbility传过来的参数
405    this.funcAbilityWant = want;
406  }
407
408  onWindowStageCreate(windowStage: window.WindowStage): void {
409    // Main window is created, set main page for this ability
410    hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
411    // Main window is created, set main page for this ability
412    let url = 'pages/Index';
413    if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
414      url = 'pages/Page_ColdStartUp';
415    }
416    windowStage.loadContent(url, (err, data) => {
417      // ...
418    });
419  }
420}
421```
422
423### 目标UIAbility热启动
424
425在应用开发中,会遇到目标[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant)生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理。
426
427例如短信应用和联系人应用配合使用的场景。
428
4291. 用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。
4302. 用户将设备回到桌面界面,短信应用进入后台运行状态。
4313. 用户打开联系人应用,找到联系人张三。
4324. 用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。
4335. 由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的onNewWant()回调,而不会再走[onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#oncreate)和[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate)等初始化逻辑。
434
435图1 目标UIAbility热启动
436![](figures/uiability-hot-start.png)
437
438开发步骤如下所示。
439
4401. 冷启动短信应用的UIAbility实例时,在[onWindowStageCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onwindowstagecreate)生命周期回调中,通过调用[getUIContext()](../reference/apis-arkui/arkts-apis-window-Window.md#getuicontext10)接口获取UI上下文实例[UIContext](../reference/apis-arkui/arkts-apis-uicontext-uicontext.md)对象。
441
442    ```ts
443    import { hilog } from '@kit.PerformanceAnalysisKit';
444    import { Want, UIAbility } from '@kit.AbilityKit';
445    import { window, UIContext } from '@kit.ArkUI';
446
447    const DOMAIN_NUMBER: number = 0xFF00;
448    const TAG: string = '[EntryAbility]';
449
450    export default class EntryAbility extends UIAbility {
451      funcAbilityWant: Want | undefined = undefined;
452      uiContext: UIContext | undefined = undefined;
453
454      // ...
455
456      onWindowStageCreate(windowStage: window.WindowStage): void {
457        // Main window is created, set main page for this ability
458        hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
459        let url = 'pages/Index';
460        if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
461          url = 'pages/Page_ColdStartUp';
462        }
463
464        windowStage.loadContent(url, (err, data) => {
465          if (err.code) {
466            return;
467          }
468
469          let windowClass: window.Window;
470          windowStage.getMainWindow((err, data) => {
471            if (err.code) {
472              hilog.error(DOMAIN_NUMBER, TAG, `Failed to obtain the main window. Code is ${err.code}, message is ${err.message}`);
473              return;
474            }
475            windowClass = data;
476            this.uiContext = windowClass.getUIContext();
477          });
478          hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
479        });
480      }
481    }
482    ```
483
4842. 在短信应用UIAbility的[onNewWant()](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#onnewwant)回调中通过AppStorage设置全局变量nameForNavi的值,并进行指定页面的跳转。此时再次启动该短信应用的UIAbility实例时,即可跳转到该短信应用的UIAbility实例的指定页面。
485
486    1. 导入相关模块,并在onNewWant()生命周期回调中设置全局变量nameForNavi的值。
487
488        ```ts
489        import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit';
490        import { hilog } from '@kit.PerformanceAnalysisKit';
491
492        const DOMAIN_NUMBER: number = 0xFF00;
493        const TAG: string = '[EntryAbility]';
494
495        export default class EntryAbility extends UIAbility {
496          // ...
497          onNewWant(want: Want, launchParam: AbilityConstant.   LaunchParam): void {
498            hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'onNewWant');
499            AppStorage.setOrCreate<string>('nameForNavi', 'pageOne');
500          }
501        }
502        ```
503
504    2. 在Index页面显示时触发onPageShow回调,获取全局变量nameForNavi的值,并进行执行页面的跳转。
505
506        ```ts
507        // Index.ets
508        @Entry
509        @Component
510        struct Index {
511          @State message: string = 'Index';
512          pathStack: NavPathStack = new NavPathStack();
513
514          onPageShow(): void {
515            let somePage = AppStorage.get<string>('nameForNavi')
516            if (somePage) {
517              this.pathStack.pushPath({ name: somePage }, false);
518              AppStorage.delete('nameForNavi');
519            }
520          }
521
522          build() {
523            Navigation(this.pathStack) {
524              Text(this.message)
525                .id('Index')
526                .fontSize($r('app.float.page_text_font_size'))
527                .fontWeight(FontWeight.Bold)
528                .alignRules({
529                  center: { anchor: '__container__', align: VerticalAlign.Center },
530                  middle: { anchor: '__container__', align: HorizontalAlign.Center }
531                })
532            }
533            .mode(NavigationMode.Stack)
534            .height('100%')
535            .width('100%')
536          }
537        }
538        ```
539
540    3. 实现Navigation子页面。
541
542        ```ts
543        // PageOne.ets
544        @Builder
545        export function PageOneBuilder() {
546          PageOne();
547        }
548
549        @Component
550        export struct PageOne {
551          @State message: string = 'PageOne';
552          pathStack: NavPathStack = new NavPathStack();
553
554          build() {
555            NavDestination() {
556              Text(this.message)
557                .id('PageOne')
558                .fontSize($r('app.float.page_text_font_size'))
559                .fontWeight(FontWeight.Bold)
560                .alignRules({
561                  center: { anchor: '__container__', align: VerticalAlign.Center },
562                  middle: { anchor: '__container__', align: HorizontalAlign.Center }
563                })
564            }
565            .onReady((context: NavDestinationContext) => {
566              this.pathStack = context.pathStack;
567            })
568            .height('100%')
569            .width('100%')
570          }
571        }
572        ```
573
574    4. 在系统配置文件`route_map.json`中配置子页信息(参考[系统路由表](../ui/arkts-navigation-navigation.md#系统路由表))。
575
576        ```ts
577        // route_map.json
578        {
579          "routerMap": [
580            {
581              "name": "pageOne",
582              "pageSourceFile": "src/main/ets/pages/PageOne.ets",
583              "buildFunction": "PageOneBuilder",
584              "data": {
585                "description": "this is pageOne"
586              }
587            }
588          ]
589        }
590        ```
591
592    5. 在[module.json5配置文件](../quick-start/module-configuration-file.md#routermap标签)中配置routerMap路由映射。
593
594        ```ts
595        // module.json5
596        {
597          "module":{
598            // ...
599            "routerMap": "$profile:route_map",
600          }
601        }
602        ```
603
604> **说明:**
605>
606> 当被调用方[UIAbility组件启动模式](uiability-launch-type.md)设置为multiton启动模式时,每次启动都会创建一个新的实例,那么onNewWant()回调就不会被用到。
607
608<!--Del-->
609## 启动UIAbility指定窗口模式(仅对系统应用开放)
610
611当用户打开应用时,应用程序会以不同的窗口模式进行展示,即启动[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的窗口模式。应用程序可以启动为全屏模式,悬浮窗模式或分屏模式。
612
613全屏模式是指应用程序启动后,占据整个屏幕,用户无法同时查看其他窗口或应用程序。全屏模式通常适用于那些要求用户专注于特定任务或界面的应用程序。
614
615悬浮窗模式是指应用程序启动后,以浮动窗口的形式显示在屏幕上,用户可以轻松切换到其他窗口或应用程序。悬浮窗通常适用于需要用户同时处理多个任务的应用程序。
616
617分屏模式允许用户在同一屏幕上同时运行两个应用程序,其中一个应用程序占据屏幕左侧/上侧的一部分,另一个应用程序占据右侧/下侧的一部分。分屏模式主要用于提高用户的多任务处理效率。
618
619使用[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability)方法启动UIAbility时,可以通过在入参中增加[StartOptions](../reference/apis-ability-kit/js-apis-app-ability-startOptions.md)参数的windowMode属性来配置启动UIAbility的窗口模式。
620
621> **说明:**
622>
623> 1. 如果在使用startAbility()方法启动UIAbility时,入参中未指定StartOptions参数的windowMode属性,那么UIAbility将以系统默认的窗口展示形态启动。
624> 2. 为了确保启动的UIAbility展示形态能够被支持,需要在该UIAbility对应的[module.json5配置文件](../quick-start/module-configuration-file.md)中[abilities标签](../quick-start/module-configuration-file.md#abilities标签)的supportWindowMode字段确认启动的展示形态被支持。
625
626以下是具体的操作步骤,以悬浮窗模式为例,假设需要从EntryAbility的页面中启动FuncAbility:
627
6281. 在调用startAbility()方法时,增加StartOptions参数。
6292. 在StartOptions参数中设置windowMode字段为WINDOW_MODE_FLOATING,表示启动的UIAbility将以悬浮窗的形式展示。
6303. windowMode属性仅适用于系统应用,三方应用可以使用displayId属性。
631
632示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。
633
634```ts
635import { AbilityConstant, common, Want, StartOptions } from '@kit.AbilityKit';
636import { hilog } from '@kit.PerformanceAnalysisKit';
637import { BusinessError } from '@kit.BasicServicesKit';
638
639const TAG: string = '[Page_UIAbilityComponentsInteractive]';
640const DOMAIN_NUMBER: number = 0xFF00;
641
642@Entry
643@Component
644struct Page_UIAbilityComponentsInteractive {
645  build() {
646    Column() {
647      //...
648      List({ initialIndex: 0 }) {
649        ListItem() {
650          Row() {
651            //...
652          }
653          .onClick(() => {
654            let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
655            let want: Want = {
656              deviceId: '', // deviceId为空表示本设备
657              bundleName: 'com.samples.stagemodelabilitydevelop',
658              moduleName: 'entry', // moduleName非必选
659              abilityName: 'FuncAbilityB',
660              parameters: {
661                // 自定义信息
662                info: '来自EntryAbility Index页面'
663              }
664            };
665            let options: StartOptions = {
666              windowMode: AbilityConstant.WindowMode.WINDOW_MODE_FLOATING
667            };
668            // context为调用方UIAbility的UIAbilityContext
669            context.startAbility(want, options).then(() => {
670              hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.');
671            }).catch((err: BusinessError) => {
672              hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
673            });
674          })
675        }
676        //...
677      }
678      //...
679    }
680    //...
681  }
682}
683```
684
685效果示意如下图所示。
686
687![](figures/start-uiability-floating-window.png)
688
689
690## 通过Call调用实现UIAbility交互(仅对系统应用开放)
691
692Call调用是[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)能力的扩展,它为UIAbility提供一种能够被外部调用并与外部进行通信的能力。Call调用支持前台与后台两种启动方式,使UIAbility既能被拉起到前台展示UI,也可以在后台被创建并运行。Call调用在调用方与被调用方间建立了IPC通信,因此应用开发者可通过Call调用实现不同UIAbility之间的数据共享。
693
694Call调用的核心接口是[startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall)方法,与[startAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startability)接口的不同之处在于:
695
696- startAbilityByCall支持前台与后台两种启动方式,而startAbility()仅支持前台启动。
697
698- 调用方可使用startAbilityByCall()所返回的[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)对象与被调用方进行通信,而startAbility()不具备通信能力。
699
700Call调用的使用场景主要包括:
701
702- 需要与被启动的UIAbility进行通信。
703
704- 希望被启动的UIAbility在后台运行。
705
706
707**表1** Call调用相关名词解释
708
709| 名词 | 描述 |
710| -------- | -------- |
711| CallerAbility | 进行Call调用的UIAbility(调用方)。 |
712| CalleeAbility | 被Call调用的UIAbility(被调用方)。 |
713| Caller | 实际对象,由startAbilityByCall接口返回,CallerAbility可使用Caller与CalleeAbility进行通信。 |
714| Callee | 实际对象,被CalleeAbility持有,可与Caller进行通信。 |
715
716Call调用示意图如下所示。
717
718**图1** Call调用示意图
719![call](figures/call.png)
720
721- CallerAbility调用[startAbilityByCall()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall)接口获取[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller),并使用Caller对象的[call](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#call)方法向CalleeAbility发送数据。
722
723- 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#on)方法注册回调函数,当接收到Caller发送的数据时将会调用对应的回调函数。
724
725> **说明:**
726> 1. 当前仅支持系统应用使用Call调用。
727>
728> 2. CalleeAbility的启动模式需要为单实例。
729>
730> 3. Call调用既支持本地(设备内)Call调用,也支持跨设备Call调用,下面介绍设备内Call调用方法。跨设备Call调用方法请参见[跨设备Call调用](hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)。
731
732
733### 接口说明
734
735Call功能主要接口如下表所示。具体的API详见[接口文档](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)。
736
737**表2** Call功能主要接口
738
739| 接口名 | 描述 |
740| -------- | -------- |
741| startAbilityByCall(want:&nbsp;Want):&nbsp;Promise&lt;Caller&gt; | 启动指定UIAbility并获取其Caller通信接口,默认为后台启动,通过配置want可实现前台启动,详见[接口文档](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall)。AbilityContext与ServiceExtensionContext均支持该接口。 |
742| on(method:&nbsp;string,&nbsp;callback:&nbsp;CalleeCallBack):&nbsp;void | 通用组件Callee注册method对应的callback方法。 |
743| off(method:&nbsp;string):&nbsp;void | 通用组件Callee解注册method的callback方法。 |
744| call(method:&nbsp;string,&nbsp;data:&nbsp;rpc.Parcelable):&nbsp;Promise&lt;void&gt; | 向通用组件Callee发送约定序列化数据。 |
745| callWithResult(method:&nbsp;string,&nbsp;data:&nbsp;rpc.Parcelable):&nbsp;Promise&lt;rpc.MessageSequence&gt; | 向通用组件Callee发送约定序列化数据,并将Callee返回的约定序列化数据带回。 |
746| release():&nbsp;void | 释放通用组件的Caller通信接口。 |
747| on(type:&nbsp;"release",&nbsp;callback:&nbsp;OnReleaseCallback):&nbsp;void | 注册通用组件通信断开监听通知。 |
748
749设备内通过Call调用实现[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)交互,涉及如下两部分开发:
750
751- [创建Callee被调用端](#开发步骤创建callee被调用端)
752
753- [访问Callee被调用端](#开发步骤访问callee被调用端)
754
755
756### 开发步骤(创建Callee被调用端)
757
758在[Callee](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#callee)被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过[on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#on)接口注册监听,无需接收数据时通过[off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#off)接口解除监听。
759
7601. 配置[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)的启动模式。
761
762   例如将CalleeAbility配置为单实例模式`singleton`,配置方式请参见[UIAbility组件启动模式](uiability-launch-type.md)。
763
7642. 导入UIAbility模块。
765
766   ```ts
767   import { UIAbility } from '@kit.AbilityKit';
768   ```
769
7703. 定义约定的序列化数据。
771   调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。
772
773
774    ```ts
775    import { rpc } from '@kit.IPCKit';
776
777    class MyParcelable {
778      num: number = 0;
779      str: string = '';
780
781      constructor(num: number, string: string) {
782        this.num = num;
783        this.str = string;
784      }
785
786      mySequenceable(num: number, string: string): void {
787        this.num = num;
788        this.str = string;
789      }
790
791      marshalling(messageSequence: rpc.MessageSequence): boolean {
792        messageSequence.writeInt(this.num);
793        messageSequence.writeString(this.str);
794        return true;
795      }
796
797      unmarshalling(messageSequence: rpc.MessageSequence): boolean {
798        this.num = messageSequence.readInt();
799        this.str = messageSequence.readString();
800        return true;
801      }
802    }
803    ```
804
8054. 实现[Callee.on](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#on)监听及[Callee.off](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#off)解除监听。
806
807   被调用端[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#oncreate)注册'MSG_SEND_METHOD'监听,在[onDestroy](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#ondestroy)取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下:
808
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      // 获取Caller发送的序列化数据
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      // 作相应处理
856      // 返回序列化数据result给Caller
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### 开发步骤(访问Callee被调用端)
897
8981. 导入[UIAbility](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md)模块。
899
900    ```ts
901    import { UIAbility } from '@kit.AbilityKit';
902    ```
903
9042. 获取[Caller](../reference/apis-ability-kit/js-apis-app-ability-uiAbility.md#caller)通信接口。
905
906   [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md)属性实现了[startAbilityByCall](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startabilitybycall)方法,用于获取指定通用组件的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#onrelease)监听。应用开发者根据实际需要做相应处理。
907
908
909    ```ts
910    import { common, Want, Caller } from '@kit.AbilityKit';
911    import { hilog } from '@kit.PerformanceAnalysisKit';
912    import { BusinessError } from '@kit.BasicServicesKit';
913
914    const TAG: string = '[Page_UIAbilityComponentsInteractive]';
915    const DOMAIN_NUMBER: number = 0xFF00;
916
917    @Entry
918    @Component
919    struct Page_UIAbilityComponentsInteractive {
920      caller: Caller | undefined = undefined;
921
922      // 注册caller的release监听
923      private regOnRelease(caller: Caller): void {
924        hilog.info(DOMAIN_NUMBER, TAG, `caller is ${caller}`);
925        try {
926          caller.on('release', (msg: string) => {
927            hilog.info(DOMAIN_NUMBER, TAG, `caller onRelease is called ${msg}`);
928          })
929          hilog.info(DOMAIN_NUMBER, TAG, 'succeeded in registering on release.');
930        } catch (err) {
931          let code = (err as BusinessError).code;
932          let message = (err as BusinessError).message;
933          hilog.error(DOMAIN_NUMBER, TAG, `Failed to caller register on release. Code is ${code}, message is ${message}`);
934        }
935      };
936
937      build() {
938        Column() {
939          // ...
940          List({ initialIndex: 0 }) {
941            // ...
942            ListItem() {
943              Row() {
944                // ...
945              }
946              .onClick(() => {
947                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
948                let want: Want = {
949                  bundleName: 'com.samples.stagemodelabilityinteraction',
950                  abilityName: 'CalleeAbility',
951                  parameters: {
952                    // 自定义信息
953                    info: 'CallSendMsg'
954                  }
955                };
956                context.startAbilityByCall(want).then((caller: Caller) => {
957                  hilog.info(DOMAIN_NUMBER, TAG, `Succeeded in starting ability.Code is ${caller}`);
958                  if (caller === undefined) {
959                    hilog.info(DOMAIN_NUMBER, TAG, 'get caller failed');
960                    return;
961                  }
962                  else {
963                    hilog.info(DOMAIN_NUMBER, TAG, 'get caller success');
964                    this.regOnRelease(caller);
965                    this.getUIContext().getPromptAction().showToast({
966                      message: 'CallerSuccess'
967                    });
968                    try {
969                      caller.release();
970                    } catch (releaseErr) {
971                      console.log('Caller.release catch error, error.code: ' + JSON.stringify(releaseErr.code) +
972                        ' error.message: ' + JSON.stringify(releaseErr.message));
973                    }
974                  }
975                }).catch((err: BusinessError) => {
976                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
977                });
978              })
979            }
980            // ...
981          }
982          // ...
983        }
984        // ...
985      }
986    }
987    ```
988<!--DelEnd-->
989
990## 相关实例
991
992针对UIAbility组件间交互开发,有以下相关实例可供参考:
993
994- [UIAbility内和UIAbility间页面的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/StageAbility)
995- [UIAbility内页面间的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/PagesRouter)