• 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)的[`killProcessBySelf()`](../reference/apis/js-apis-inner-application-applicationContext.md#applicationcontextkillallprocesses9)方法实现关闭应用所有的进程。
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     // uncomment line below if wish to implicitly query only in the specific bundle.
236     // bundleName: 'com.example.myapplication',
237     action: 'ohos.want.action.viewData',
238     // entities can be omitted.
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 = ...; // 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将以悬浮窗的形式展示。
400
401示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。
402
403```ts
404import AbilityConstant from '@ohos.app.ability.AbilityConstant';
405import common from '@ohos.app.ability.common';
406import Want from '@ohos.app.ability.Want';
407import StartOptions from '@ohos.app.ability.StartOptions';
408import { BusinessError } from '@ohos.base';
409
410let context: common.UIAbilityContext = ...; // UIAbilityContext
411let want: Want = {
412  deviceId: '', // deviceId为空表示本设备
413  bundleName: 'com.example.myapplication',
414  moduleName: 'func', // moduleName非必选
415  abilityName: 'FuncAbility',
416  parameters: { // 自定义信息
417    info: '来自EntryAbility Index页面',
418  },
419}
420let options: StartOptions = {
421  windowMode: AbilityConstant.WindowMode.WINDOW_MODE_FLOATING
422};
423// context为调用方UIAbility的UIAbilityContext
424context.startAbility(want, options).then(() => {
425  console.info('Succeeded in starting ability.');
426}).catch((err: BusinessError) => {
427  console.error(`Failed to start ability. Code is ${err.code}, message is ${err.message}`);
428})
429```
430
431效果示意如下图所示。
432![](figures/start-uiability-floating-window.png)
433
434## 启动UIAbility的指定页面
435
436### 概述
437
438一个UIAbility可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。
439
440UIAbility的启动分为两种情况:UIAbility冷启动和UIAbility热启动。
441
442- UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。
443- UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。
444
445本文主要讲解[目标UIAbility冷启动](#目标uiability冷启动)和[目标UIAbility热启动](#目标uiability热启动)两种启动指定页面的场景,以及在讲解启动指定页面之前会讲解到在调用方如何指定启动页面。
446
447
448### 调用方UIAbility指定启动页面
449
450调用方UIAbility启动另外一个UIAbility时,通常需要跳转到指定的页面。例如FuncAbility包含两个页面(Index对应首页,Second对应功能A页面),此时需要在传入的want参数中配置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。示例中的context的获取方式请参见[获取UIAbility的上下文信息](uiability-usage.md#获取uiability的上下文信息)。
451
452
453```ts
454import common from '@ohos.app.ability.common';
455import Want from '@ohos.app.ability.Want';
456import { BusinessError } from '@ohos.base';
457
458let context: common.UIAbilityContext = ...; // UIAbilityContext
459let want: Want = {
460  deviceId: '', // deviceId为空表示本设备
461  bundleName: 'com.example.funcapplication',
462  moduleName: 'entry', // moduleName非必选
463  abilityName: 'EntryAbility',
464  parameters: { // 自定义参数传递页面信息
465    router: 'funcA',
466  },
467}
468// context为调用方UIAbility的UIAbilityContext
469context.startAbility(want).then(() => {
470  console.info('Succeeded in starting ability.');
471}).catch((err: BusinessError) => {
472  console.error(`Failed to start ability. Code is ${err.code}, message is ${err.message}`);
473})
474```
475
476
477### 目标UIAbility冷启动
478
479目标UIAbility冷启动时,在目标UIAbility的`onCreate()`生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的`onWindowStageCreate()`生命周期回调中,解析EntryAbility传递过来的want参数,获取到需要加载的页面信息url,传入`windowStage.loadContent()`方法。
480
481
482```ts
483import AbilityConstant from '@ohos.app.ability.AbilityConstant';
484import UIAbility from '@ohos.app.ability.UIAbility';
485import Want from '@ohos.app.ability.Want';
486import window from '@ohos.window';
487
488export default class FuncAbility extends UIAbility {
489  funcAbilityWant: Want | undefined = undefined;
490
491  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
492    // 接收调用方UIAbility传过来的参数
493    this.funcAbilityWant = want;
494  }
495
496  onWindowStageCreate(windowStage: window.WindowStage) {
497    // Main window is created, set main page for this ability
498    let url = 'pages/Index';
499    if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
500      url = 'pages/Second';
501    }
502    windowStage.loadContent(url, (err, data) => {
503      // ...
504    });
505  }
506}
507```
508
509### 目标UIAbility热启动
510
511在应用开发中,会遇到目标UIAbility实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发`onNewWant()`生命周期方法。为了实现跳转到指定页面,需要在`onNewWant()`中解析要参数进行处理。
512
513例如短信应用和联系人应用配合使用的场景。
514
5151. 用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。
5162. 用户将设备回到桌面界面,短信应用进入后台运行状态。
5173. 用户打开联系人应用,找到联系人张三。
5184. 用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。
5195. 由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的`onNewWant()`回调,而不会再走`onCreate()`和`onWindowStageCreate()`等初始化逻辑。
520
521图1 目标UIAbility热启动
522![](figures/uiability-hot-start.png)
523
524开发步骤如下所示。
525
5261. 冷启动短信应用的UIAbility实例时,在`onWindowStageCreate()`生命周期回调中,通过调用[`getUIContext()`](../reference/apis/js-apis-window.md#getuicontext10)接口获取UI上下文实例[`UIContext`](../reference/apis/js-apis-arkui-UIContext.md)对象。
527
528   ```ts
529   import AbilityConstant from '@ohos.app.ability.AbilityConstant';
530   import UIAbility from '@ohos.app.ability.UIAbility';
531   import Want from '@ohos.app.ability.Want';
532   import window from '@ohos.window';
533
534   import { Router, UIContext } from '@ohos.arkui.UIContext';
535
536   export default class EntryAbility extends UIAbility {
537     funcAbilityWant: Want | undefined = undefined;
538     uiContext: UIContext | undefined = undefined;
539
540     // ...
541
542     onWindowStageCreate(windowStage: window.WindowStage) {
543       // Main window is created, set main page for this ability
544       let url = 'pages/Index';
545       if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
546         url = 'pages/Second';
547       }
548
549       windowStage.loadContent(url, (err, data) => {
550         if (err.code) {
551           return;
552         }
553
554         let windowClass: window.Window;
555         windowStage.getMainWindow((err, data) => {
556           if (err.code) {
557             console.error(`Failed to obtain the main window. Code is ${err.code}, message is ${err.message}`);
558             return;
559           }
560           windowClass = data;
561           this.uiContext = windowClass.getUIContext();
562         })
563       });
564     }
565   }
566   ```
567
5682. 在短信应用UIAbility的`onNewWant()`回调中解析调用方传递过来的want参数,通过调用UIContext中的[`getRouter()`](../reference/apis/js-apis-arkui-UIContext.md#getrouter)方法获取[`Router`](../reference/apis/js-apis-arkui-UIContext.md#router)对象,并进行指定页面的跳转。此时再次启动该短信应用的UIAbility实例时,即可跳转到该短信应用的UIAbility实例的指定页面。
569
570   ```ts
571   import AbilityConstant from '@ohos.app.ability.AbilityConstant';
572   import UIAbility from '@ohos.app.ability.UIAbility';
573   import Want from '@ohos.app.ability.Want';
574   import { Router, UIContext } from '@ohos.arkui.UIContext';
575   import { BusinessError } from '@ohos.base';
576
577   export default class EntryAbility extends UIAbility {
578     funcAbilityWant: Want | undefined = undefined;
579     uiContext: UIContext | undefined = undefined;
580
581     onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
582       if (want?.parameters?.router && want.parameters.router === 'funcA') {
583         let funcAUrl = 'pages/Second';
584         if (this.uiContext) {
585           let router: Router = this.uiContext.getRouter();
586           router.pushUrl({
587             url: funcAUrl
588           }).catch((err: BusinessError) => {
589             console.error(`Failed to push url. Code is ${err.code}, message is ${err.message}`);
590           })
591         }
592       }
593     }
594
595     // ...
596   }
597   ```
598
599> **说明:**
600>
601> 当被调用方[UIAbility组件启动模式](uiability-launch-type.md)设置为multiton启动模式时,每次启动都会创建一个新的实例,那么[onNewWant()](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)回调就不会被用到。
602
603
604## 通过Call调用实现UIAbility交互(仅对系统应用开放)
605
606Call调用是UIAbility能力的扩展,它为UIAbility提供一种能够被外部调用并与外部进行通信的能力。Call调用支持前台与后台两种启动方式,使UIAbility既能被拉起到前台展示UI,也可以在后台被创建并运行。Call调用在调用方与被调用方间建立了IPC通信,因此应用开发者可通过Call调用实现不同UIAbility之间的数据共享。
607
608Call调用的核心接口是`startAbilityByCall()`方法,与`startAbility()`接口的不同之处在于:
609
610- startAbilityByCall支持前台与后台两种启动方式,而`startAbility()`仅支持前台启动。
611
612- 调用方可使用`startAbilityByCall()`所返回的Caller对象与被调用方进行通信,而`startAbilty()`不具备通信能力。
613
614Call调用的使用场景主要包括:
615
616- 需要与被启动的UIAbility进行通信。
617
618- 希望被启动的UIAbility在后台运行。
619
620
621**表1** Call调用相关名词解释
622
623| 名词 | 描述 |
624| -------- | -------- |
625| CallerAbility | 进行Call调用的UIAbility(调用方)。 |
626| CalleeAbility | 被Call调用的UIAbility(被调用方)。 |
627| Caller | 实际对象,由startAbilityByCall接口返回,CallerAbility可使用Caller与CalleeAbility进行通信。 |
628| Callee | 实际对象,被CalleeAbility持有,可与Caller进行通信。 |
629
630Call调用示意图如下所示。
631
632**图1** Call调用示意图
633![call](figures/call.png)
634
635- CallerAbility调用startAbilityByCall接口获取Caller,并使用Caller对象的call方法向CalleeAbility发送数据。
636
637- CalleeAbility持有一个Callee对象,通过Callee的on方法注册回调函数,当接收到Caller发送的数据时将会调用对应的回调函数。
638
639> **说明:**
640> 1. 当前仅支持系统应用使用Call调用。
641>
642> 2. CalleeAbility的启动模式需要为单实例。
643>
644> 3. Call调用既支持本地(设备内)Call调用,也支持跨设备Call调用,下面介绍设备内Call调用方法。跨设备Call调用方法请参见[跨设备Call调用](hop-multi-device-collaboration.md#通过跨设备call调用实现多端协同)。
645
646
647### 接口说明
648
649Call功能主要接口如下表所示。具体的API详见[接口文档](../reference/apis/js-apis-app-ability-uiAbility.md#caller)。
650
651**表2** Call功能主要接口
652
653| 接口名 | 描述 |
654| -------- | -------- |
655| startAbilityByCall(want: Want): Promise<Caller> | 启动指定UIAbility并获取其Caller通信接口,默认为后台启动,通过配置want可实现前台启动,详见[接口文档](../reference/apis/js-apis-inner-application-uiAbilityContext.md#abilitycontextstartabilitybycall)。AbilityContext与ServiceExtensionContext均支持该接口。 |
656| on(method: string, callback: CalleeCallBack): void | 通用组件Callee注册method对应的callback方法。 |
657| off(method: string): void | 通用组件Callee解注册method的callback方法。 |
658| call(method: string, data: rpc.Parcelable): Promise<void> | 向通用组件Callee发送约定序列化数据。 |
659| callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence> | 向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。 |
660| release(): void | 释放通用组件的Caller通信接口。 |
661| on(type: "release", callback: OnReleaseCallback): void | 注册通用组件通信断开监听通知。 |
662
663设备内通过Call调用实现UIAbility交互,涉及如下两部分开发:
664
665- [创建Callee被调用端](#开发步骤创建callee被调用端)
666
667- [访问Callee被调用端](#开发步骤访问callee被调用端)
668
669
670### 开发步骤(创建Callee被调用端)
671
672在Callee被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。
673
6741. 配置UIAbility的启动模式。
675
676   例如将CalleeAbility配置为单实例模式`singleton`,配置方式请参见[UIAbility组件启动模式](uiability-launch-type.md)。
677
6782. 导入UIAbility模块。
679
680   ```ts
681   import UIAbility from '@ohos.app.ability.UIAbility';
682   ```
683
6843. 定义约定的序列化数据。
685   调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。
686
687
688   ```ts
689   import rpc from '@ohos.rpc';
690
691   export default class MyParcelable {
692     num: number = 0;
693     str: string = '';
694
695     constructor(num: number, string: string) {
696       this.num = num;
697       this.str = string;
698     }
699
700     marshalling(messageSequence: rpc.MessageSequence) {
701       messageSequence.writeInt(this.num);
702       messageSequence.writeString(this.str);
703       return true;
704     }
705
706     unmarshalling(messageSequence: rpc.MessageSequence) {
707       this.num = messageSequence.readInt();
708       this.str = messageSequence.readString();
709       return true;
710     }
711   }
712   ```
713
7144. 实现Callee.on监听及Callee.off解除监听。
715
716   被调用端Callee的监听函数注册时机,取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在UIAbility的onCreate注册'MSG_SEND_METHOD'监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下:
717
718
719   ```ts
720   import AbilityConstant from '@ohos.app.ability.AbilityConstant';
721   import UIAbility from '@ohos.app.ability.UIAbility';
722   import Want from '@ohos.app.ability.Want';
723   import rpc from '@ohos.rpc';
724   import { BusinessError } from '@ohos.base';
725   import MyParcelable from './MyParcelable';
726
727   const TAG: string = '[CalleeAbility]';
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)
829