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