「鸿蒙学习笔记」Stage模型--UIAbility
概述
UIAbility组件是一种包含UI界面的应用组件,主要用于和用户交互。
UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口;一个UIAbility组件中可以通过多个页面来实现一个功能模块。每一个UIAbility组件实例,都对应于一个最近任务列表中的任务。
配置
为使应用能够正常使用UIAbility,需要在 module.json5 配置文件的 abilities标签 中声明UIAbility的名称、入口、标签等相关信息。
{
"module": {
// ...
"abilities": [
{
"name": "EntryAbility", // UIAbility组件的名称
"srcEntrance": "./ets/entryability/EntryAbility.ts", // UIAbility组件的代码路径
"description": "$string:EntryAbility_desc", // UIAbility组件的描述信息
"icon": "$media:icon", // UIAbility组件的图标
"label": "$string:EntryAbility_label", // UIAbility组件的标签
"startWindowIcon": "$media:icon", // UIAbility组件启动页面图标资源文件的索引
"startWindowBackground": "$color:start_window_background", // UIAbility组件启动页面背景颜色资源文件的索引
// ...
}
]
}
}
生命周期
启动模式
针对不同的业务场景,系统提供了三种启动模式:
- singleton(单实例模式)
- standard(标准实例模式)
- specified(指定实例模式)
singleton(单实例模式)
singleton启动模式为单实例模式,也是默认情况下的启动模式。
每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例。
应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用startAbility()方法启动该UIAbility实例,此时只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。
在module.json5配置文件中的"launchType"字段配置为"singleton"即可。
{
"module": {
// ...
"abilities": [
{
"launchType": "singleton",
// ...
}
]
}
}
standard(标准实例模式)
standard启动模式为标准实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。这种情况下可以将UIAbility配置为standard(标准实例模式)。
在module.json5配置文件中的"launchType"字段配置为"standard"即可。
{
"module": {
// ...
"abilities": [
{
"launchType": "standard",
// ...
}
]
}
}
specified(指定实例模式)
specified启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
在UIAbility实例创建之前,允许开发者为该实例创建一个唯一的字符串Key,创建的UIAbility实例绑定Key之后,后续每次调用startAbility()方法时,都会询问应用使用哪个Key对应的UIAbility实例来响应startAbility()请求。运行时由UIAbility内部业务决定是否创建多实例,如果匹配有该UIAbility实例的Key,则直接拉起与之绑定的UIAbility实例,否则创建一个新的UIAbility实例。
应用的UIAbility实例已创建,该UIAbility配置为指定实例模式,再次调用startAbility()方法启动该UIAbility实例,且AbilityStage的onAcceptWant()回调匹配到一个已创建的UIAbility实例。此时,再次启动该UIAbility时,只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。
例如有两个UIAbility:EntryAbility和FuncAbility,FuncAbility配置为specified启动模式,需要从EntryAbility的页面中启动FuncAbility。
在module.json5配置文件中的"launchType"字段配置为"specified"即可。
{ "module": { // ... "abilities": [ { "launchType": "specified", // ... } ] } }
在EntryAbility中,调用startAbility()方法时,在want参数中,增加一个自定义参数来区别UIAbility实例,例如增加一个"instanceKey"自定义参数。
// 在启动指定实例模式的UIAbility时,给每一个UIAbility实例配置一个独立的Key标识 // 例如在文档使用场景中,可以用文档路径作为Key标识 function getInstance() { // ... } let want = { deviceId: '', // deviceId为空表示本设备 bundleName: 'com.example.myapplication', abilityName: 'FuncAbility', moduleName: 'module1', // moduleName非必选 parameters: { // 自定义信息 instanceKey: getInstance(), }, } // context为调用方UIAbility的AbilityContext this.context.startAbility(want).then(() => { // ... }).catch((err) => { // ... })
由于FuncAbility的启动模式配置为了指定实例启动模式,在FuncAbility启动之前,会先进入其对应的AbilityStage的onAcceptWant()生命周期回调中,解析传入的want参数,获取"instanceKey"自定义参数。根据业务需要通过AbilityStage的onAcceptWant()生命周期回调返回一个字符串Key标识。如果返回的Key对应一个已启动的UIAbility,则会将之前的UIAbility拉回前台并获焦,而不创建新的实例,否则创建新的实例并启动。
import AbilityStage from '@ohos.app.ability.AbilityStage'; export default class MyAbilityStage extends AbilityStage { onAcceptWant(want): string { // 在被调用方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值 // 当前示例指的是module1 Module的FuncAbility if (want.abilityName === 'FuncAbility') { // 返回的字符串Key标识为自定义拼接的字符串内容 return `ControlModule_EntryAbilityInstance_${want.parameters.instanceKey}`; } return ''; } }
例如在文档应用中,可以对不同的文档实例内容绑定不同的Key值。当每次新建文档的时候,可以传入不同的新Key值(如可以将文件的路径作为一个Key标识),此时AbilityStage中启动UIAbility时都会创建一个新的UIAbility实例;当新建的文档保存之后,回到桌面,或者新打开一个已保存的文档,回到桌面,此时再次打开该已保存的文档,此时AbilityStage中再次启动该UIAbility时,打开的仍然是之前原来已保存的文档界面。
基本用法
指定UIAbility的启动页面
应用中的UIAbility在启动过程中,需要指定启动页面,否则应用启动后会因为没有默认加载页面而导致白屏。可以在UIAbility的onWindowStageCreate()生命周期回调中,通过WindowStage对象的loadContent()方法设置启动页面。
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: Window.WindowStage) {
// Main window is created, set main page for this ability
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
}
// ...
}
获取UIAbility的上下文信息
UIAbility类拥有自身的上下文信息,该信息为UIAbilityContext类的实例,UIAbilityContext类拥有abilityInfo、currentHapModuleInfo等属性。通过UIAbilityContext可以获取UIAbility的相关配置信息,如包代码路径、Bundle名称、Ability名称和应用程序需要的环境状态等属性信息,以及可以获取操作UIAbility实例的方法(如startAbility()、connectServiceExtensionAbility()、terminateSelf()等)。
在UIAbility中可以通过this.context获取UIAbility实例的上下文信息。
import UIAbility from '@ohos.app.ability.UIAbility'; export default class EntryAbility extends UIAbility { onCreate(want, launchParam) { // 获取UIAbility实例的上下文 let context = this.context; // ... } }
在页面中获取UIAbility实例的上下文信息,包括导入依赖资源context模块和在组件中定义一个context变量两个部分。
import common from '@ohos.app.ability.common'; @Entry @Component struct Index { private context = getContext(this) as common.UIAbilityContext; startAbilityTest() { let want = { // Want参数信息 }; this.context.startAbility(want); } // 页面展示 build() { // ... } }
UI数据同步
基于HarmonyOS的应用模型,可以通过以下两种方式来实现UIAbility组件与UI之间的数据同步。
- EventHub:基于发布订阅模式来实现,事件需要先订阅后发布,订阅者收到消息后进行处理。
- globalThis:ArkTS引擎实例内部的一个全局对象,在ArkTS引擎实例内部都能访问。
使用EventHub进行数据通信
EventHub提供了UIAbility组件/ExtensionAbility组件级别的事件机制,以UIAbility组件/ExtensionAbility组件为中心提供了订阅、取消订阅和触发事件的数据通信能力。接口说明请参见EventHub。
在使用EventHub之前,首先需要获取EventHub对象。基类Context提供了EventHub对象,本章节以使用EventHub实现UIAbility与UI之间的数据通信为例进行说明。
- 在UIAbility中调用eventHub.on()方法注册一个自定义事件“event1”,eventHub.on()有如下两种调用方式,使用其中一种即可。
import UIAbility from '@ohos.app.ability.UIAbility';
const TAG: string = '[Example].[Entry].[EntryAbility]';
export default class EntryAbility extends UIAbility {
func1(...data) {
// 触发事件,完成相应的业务操作
console.info(TAG, '1. ' + JSON.stringify(data));
}
onCreate(want, launch) {
// 获取eventHub
let eventhub = this.context.eventHub;
// 执行订阅操作
eventhub.on('event1', this.func1);
eventhub.on('event1', (...data) => {
// 触发事件,完成相应的业务操作
console.info(TAG, '2. ' + JSON.stringify(data));
});
}
}
在UI界面中通过eventHub.emit()方法触发该事件,在触发事件的同时,根据需要传入参数信息。
import common from '@ohos.app.ability.common'; @Entry @Component struct Index { private context = getContext(this) as common.UIAbilityContext; eventHubFunc() { // 不带参数触发自定义“event1”事件 this.context.eventHub.emit('event1'); // 带1个参数触发自定义“event1”事件 this.context.eventHub.emit('event1', 1); // 带2个参数触发自定义“event1”事件 this.context.eventHub.emit('event1', 2, 'test'); // 开发者可以根据实际的业务场景设计事件传递的参数 } // 页面展示 build() { // ... } }
在UIAbility的注册事件回调中可以得到对应的触发事件结果,运行日志结果如下所示。
[] [1] [2,'test']
在自定义事件“event1”使用完成后,可以根据需要调用eventHub.off()方法取消该事件的订阅。
// context为UIAbility实例的AbilityContext this.context.eventHub.off('event1');
使用globalThis进行数据同步
globalThis是ArkTS引擎实例内部的一个全局对象,引擎内部的UIAbility/ExtensionAbility/Page都可以使用,因此可以使用globalThis全局对象进行数据同步。
从如下三个场景和一个注意点来介绍globalThis的使用:
- UIAbility和Page之间使用globalThis
- UIAbility和UIAbility之间使用globalThis
- UIAbility和ExtensionAbility之间使用globalThis
- globalThis使用的注意事项
UIAbility和Page之间使用globalThis
globalThis为ArkTS引擎实例下的全局对象,可以通过globalThis绑定属性/方法来进行UIAbility组件与UI的数据同步。例如在UIAbility组件中绑定want参数,即可在UIAbility对应的UI界面上使用want参数信息。
调用startAbility()方法启动一个UIAbility实例时,被启动的UIAbility创建完成后会进入onCreate()生命周期回调,且在onCreate()生命周期回调中能够接受到传递过来的want参数,可以将want参数绑定到globalThis上。
import UIAbility from '@ohos.app.ability.UIAbility' export default class EntryAbility extends UIAbility { onCreate(want, launch) { globalThis.entryAbilityWant = want; // ... } // ... }
在UI界面中即可通过globalThis获取到want参数信息。
let entryAbilityWant; @Entry @Component struct Index { aboutToAppear() { entryAbilityWant = globalThis.entryAbilityWant; } // 页面展示 build() { // ... } }
UIAbility和UIAbility之间使用globalThis
同一个应用中UIAbility和UIAbility之间的数据传递,可以通过将数据绑定到全局变量globalThis上进行同步,如在AbilityA中将数据保存在globalThis,然后跳转到AbilityB中取得该数据:
AbilityA中保存数据一个字符串数据并挂载到globalThis上。
import UIAbility from '@ohos.app.ability.UIAbility' export default class AbilityA extends UIAbility { onCreate(want, launch) { globalThis.entryAbilityStr = 'AbilityA'; // AbilityA存放字符串“AbilityA”到globalThis // ... } }
AbilityB中获取对应的数据。
import UIAbility from '@ohos.app.ability.UIAbility' export default class AbilityB extends UIAbility { onCreate(want, launch) { // AbilityB从globalThis读取name并输出 console.info('name from entryAbilityStr: ' + globalThis.entryAbilityStr); // ... } }
UIAbility和ExtensionAbility之间使用globalThis
同一个应用中UIAbility和ExtensionAbility之间的数据传递,也可以通过将数据绑定到全局变量globalThis上进行同步,如在AbilityA中保存数据,在ServiceExtensionAbility中获取数据。
AbilityA中保存数据一个字符串数据并挂载到globalThis上。
import UIAbility from '@ohos.app.ability.UIAbility' export default class AbilityA extends UIAbility { onCreate(want, launch) { // AbilityA存放字符串“AbilityA”到globalThis globalThis.entryAbilityStr = 'AbilityA'; // ... } }
ExtensionAbility中获取数据。
import Extension from '@ohos.app.ability.ServiceExtensionAbility' export default class ServiceExtAbility extends Extension { onCreate(want) { // ServiceExtAbility从globalThis读取name并输出 console.info('name from entryAbilityStr: ' + globalThis.entryAbilityStr); // ... } }
globalThis使用的注意事项
- Stage模型下进程内的UIAbility组件共享ArkTS引擎实例,使用globalThis时需要避免存放相同名称的对象。例如AbilityA和AbilityB可以使用globalThis共享数据,在存放相同名称的对象时,先存放的对象会被后存放的对象覆盖。
- 对于绑定在globalThis上的对象,其生命周期与ArkTS虚拟机实例相同,建议在使用完成之后将其赋值为null,以减少对应用内存的占用。
组件间交互(设备内)
UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,该UIAbility可以是应用内的其他UIAbility,也可以是其他应用的UIAbility(例如启动三方支付UIAbility)。
- 启动应用内的UIAbility
- 启动应用内的UIAbility并获取返回结果
- 启动其他应用的UIAbility
- 启动其他应用的UIAbility并获取返回结果
- 启动UIAbility的指定页面
- 通过Call调用实现UIAbility交互(仅对系统应用开放)
启动应用内的UIAbility
当一个应用内包含多个UIAbility时,存在应用内启动UIAbility的场景。例如在支付应用中从入口UIAbility启动收付款UIAbility。
假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在应用的一个Module中,也可以在的不同Module中),需要从EntryAbility的页面中启动FuncAbility。
在EntryAbility中,通过调用startAbility()方法启动UIAbility,want为UIAbility实例启动的入口参数,其中bundleName为待启动应用的Bundle名称,abilityName为待启动的UIAbility名称,moduleName在待启动的UIAbility属于不同的Module时添加,parameters为自定义信息参数。
let wantInfo = { deviceId: '', // deviceId为空表示本设备 bundleName: 'com.example.myapplication', abilityName: 'FuncAbility', moduleName: 'module1', // moduleName非必选 parameters: { // 自定义信息 info: '来自EntryAbility Index页面', }, } // context为调用方UIAbility的AbilityContext this.context.startAbility(wantInfo).then(() => { // ... }).catch((err) => { // ... })
在FuncAbility的生命周期回调文件中接收EntryAbility传递过来的参数。
import UIAbility from '@ohos.app.ability.UIAbility'; import Window from '@ohos.window'; export default class FuncAbility extends UIAbility { onCreate(want, launchParam) { // 接收调用方UIAbility传过来的参数 let funcAbilityWant = want; let info = funcAbilityWant?.parameters?.info; // ... } }
在FuncAbility业务完成之后,如需要停止当前UIAbility实例,在FuncAbility中通过调用terminateSelf()方法实现。
// context为需要停止的UIAbility实例的AbilityContext this.context.terminateSelf((err) => { // ... });
启动应用内的UIAbility并获取返回结果
在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和帐号登录功能分别设计为两个独立的UIAbility,在帐号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。
在EntryAbility中,调用startAbilityForResult()接口启动FuncAbility,异步回调中的data用于接收FuncAbility停止自身后返回给EntryAbility的信息。
let wantInfo = { deviceId: '', // deviceId为空表示本设备 bundleName: 'com.example.myapplication', abilityName: 'FuncAbility', moduleName: 'module1', // moduleName非必选 parameters: { // 自定义信息 info: '来自EntryAbility Index页面', }, } // context为调用方UIAbility的AbilityContext this.context.startAbilityForResult(wantInfo).then((data) => { // ... }).catch((err) => { // ... })
在FuncAbility停止自身时,需要调用terminateSelfWithResult()方法,入参abilityResult为FuncAbility需要返回给EntryAbility的信息。
const RESULT_CODE: number = 1001; let abilityResult = { resultCode: RESULT_CODE, want: { bundleName: 'com.example.myapplication', abilityName: 'FuncAbility', moduleName: 'module1', parameters: { info: '来自FuncAbility Index页面', }, }, } // context为被调用方UIAbility的AbilityContext this.context.terminateSelfWithResult(abilityResult, (err) => { // ... });
FuncAbility停止自身后,EntryAbility通过startAbilityForResult()方法回调接收被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致。
const RESULT_CODE: number = 1001; // ... // context为调用方UIAbility的AbilityContext this.context.startAbilityForResult(want).then((data) => { if (data?.resultCode === RESULT_CODE) { // 解析被调用方UIAbility返回的信息 let info = data.want?.parameters?.info; // ... } }).catch((err) => { // ... })
启动其他应用的UIAbility
启动其他应用的UIAbility,通常用户只需要完成一个通用的操作(例如需要选择一个文档应用来查看某个文档的内容信息),推荐使用隐式Want启动。系统会根据调用方的want参数来识别和启动匹配到的应用UIAbility。
启动UIAbility有显式Want启动和隐式Want启动两种方式。
- 显式Want启动:启动一个确定应用的UIAbility,在want参数中需要设置该应用bundleName和abilityName,当需要拉起某个明确的UIAbility时,通常使用显式Want启动方式。
- 隐式Want启动:根据匹配条件由用户选择启动哪一个UIAbility,即不明确指出要启动哪一个UIAbility(abilityName参数未设置),在调用startAbility()方法时,其入参want中指定了一系列的entities字段(表示目标UIAbility额外的类别信息,如浏览器、视频播放器)和actions字段(表示要执行的通用操作,如查看、分享、应用详情等)等参数信息,然后由系统去分析want,并帮助找到合适的UIAbility来启动。当需要拉起其他应用的UIAbility时,开发者通常不知道用户设备中应用的安装情况,也无法确定目标应用的bundleName和abilityName,通常使用隐式Want启动方式。
隐式Want启动其他应用的UIAbility:
将多个待匹配的文档应用安装到设备,在其对应UIAbility的module.json5配置文件中,配置skills的entities字段和actions字段。
{ "module": { "abilities": [ { // ... "skills": [ { "entities": [ // ... "entity.system.default" ], "actions": [ // ... "ohos.want.action.viewData" ] } ] } ] } }
在调用方want参数中的entities和action需要被包含在待匹配UIAbility的skills配置的entities和actions中。系统匹配到符合entities和actions参数条件的UIAbility后,会弹出选择框展示匹配到的UIAbility实例列表供用户选择使用。
let wantInfo = { deviceId: '', // deviceId为空表示本设备 // uncomment line below if wish to implicitly query only in the specific bundle. // bundleName: 'com.example.myapplication', action: 'ohos.want.action.viewData', // entities can be omitted. entities: ['entity.system.default'], } // context为调用方UIAbility的AbilityContext this.context.startAbility(wantInfo).then(() => { // ... }).catch((err) => { // ... })
在文档应用使用完成之后,如需要停止当前UIAbility实例,通过调用terminateSelf()方法实现。
// context为需要停止的UIAbility实例的AbilityContext this.context.terminateSelf((err) => { // ... });
启动其他应用的UIAbility并获取返回结果
当使用隐式Want启动其他应用的UIAbility并希望获取返回结果时,调用方需要使用startAbilityForResult()方法启动目标UIAbility。例如主应用中需要启动三方支付并获取支付结果。
在支付应用对应UIAbility的module.json5配置文件中,配置skills的entities字段和actions字段。
{ "module": { "abilities": [ { // ... "skills": [ { "entities": [ // ... "entity.system.default" ], "actions": [ // ... "ohos.want.action.editData" ] } ] } ] } }
调用方使用startAbilityForResult()方法启动支付应用的UIAbility,在调用方want参数中的entities和action需要被包含在待匹配UIAbility的skills配置的entities和actions中。异步回调中的data用于后续接收支付UIAbility停止自身后返回给调用方的信息。系统匹配到符合entities和actions参数条件的UIAbility后,会弹出选择框展示匹配到的UIAbility实例列表供用户选择使用。
let wantInfo = { deviceId: '', // deviceId为空表示本设备 // uncomment line below if wish to implicitly query only in the specific bundle. // bundleName: 'com.example.myapplication', action: 'ohos.want.action.editData', // entities can be omitted. entities: ['entity.system.default'], } // context为调用方UIAbility的AbilityContext this.context.startAbilityForResult(wantInfo).then((data) => { // ... }).catch((err) => { // ... })
在支付UIAbility完成支付之后,需要调用terminateSelfWithResult()方法实现停止自身,并将abilityResult参数信息返回给调用方。
const RESULT_CODE: number = 1001; let abilityResult = { resultCode: RESULT_CODE, want: { bundleName: 'com.example.myapplication', abilityName: 'EntryAbility', moduleName: 'entry', parameters: { payResult: 'OKay', }, }, } // context为被调用方UIAbility的AbilityContext this.context.terminateSelfWithResult(abilityResult, (err) => { // ... });
在调用方startAbilityForResult()方法回调中接收支付应用返回的信息,RESULT_CODE需要与前面terminateSelfWithResult()返回的数值保持一致。
const RESULT_CODE: number = 1001; let want = { // Want参数信息 }; // context为调用方UIAbility的AbilityContext this.context.startAbilityForResult(want).then((data) => { if (data?.resultCode === RESULT_CODE) { // 解析被调用方UIAbility返回的信息 let payResult = data.want?.parameters?.payResult; // ... } }).catch((err) => { // ... })
启动UIAbility的指定页面
一个UIAbility可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。
调用方UIAbility指定启动页面
调用方UIAbility启动另外一个UIAbility时,通常需要跳转到指定的页面。例如FuncAbility包含两个页面(Index对应首页,Second对应功能A页面),此时需要在传入的want参数中配置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。
let wantInfo = {
deviceId: '', // deviceId为空表示本设备
bundleName: 'com.example.myapplication',
abilityName: 'FuncAbility',
moduleName: 'module1', // moduleName非必选
parameters: { // 自定义参数传递页面信息
router: 'funcA',
},
}
// context为调用方UIAbility的AbilityContext
this.context.startAbility(wantInfo).then(() => {
// ...
}).catch((err) => {
// ...
})
目标UIAbility首次启动
目标UIAbility首次启动时,在目标UIAbility的onWindowStageCreate()生命周期回调中,解析EntryAbility传递过来的want参数,获取到需要加载的页面信息url,传入windowStage.loadContent()方法。
import UIAbility from '@ohos.app.ability.UIAbility'
import Window from '@ohos.window'
export default class FuncAbility extends UIAbility {
funcAbilityWant;
onCreate(want, launchParam) {
// 接收调用方UIAbility传过来的参数
this.funcAbilityWant = want;
}
onWindowStageCreate(windowStage: Window.WindowStage) {
// Main window is created, set main page for this ability
let url = 'pages/Index';
if (this.funcAbilityWant?.parameters?.router) {
if (this.funcAbilityWant.parameters.router === 'funA') {
url = 'pages/Second';
}
}
windowStage.loadContent(url, (err, data) => {
// ...
});
}
}
目标UIAbility非首次启动
经常还会遇到一类场景,当应用A已经启动且处于主页面时,回到桌面,打开应用B,并从应用B再次启动应用A,且需要跳转到应用A的指定页面。例如联系人应用和短信应用配合使用的场景。打开短信应用主页,回到桌面,此时短信应用处于已打开状态且当前处于短信应用的主页。再打开联系人应用主页,进入联系人用户A查看详情,点击短信图标,准备给用户A发送短信,此时会再次拉起短信应用且当前处于短信应用的发送页面。
针对以上场景,即当应用A的UIAbility实例已创建,并且处于该UIAbility实例对应的主页面中,此时,从应用B中需要再次启动应用A的该UIAbility,并且需要跳转到不同的页面,这种情况下要如何实现呢?
在目标UIAbility中,默认加载的是Index页面。由于当前UIAbility实例之前已经创建完成,此时会进入UIAbility的onNewWant()回调中且不会进入onCreate()和onWindowStageCreate()生命周期回调,在onNewWant()回调中解析调用方传递过来的want参数,并挂在到全局变量globalThis中,以便于后续在页面中获取。
import UIAbility from '@ohos.app.ability.UIAbility' export default class FuncAbility extends UIAbility { onNewWant(want, launchParam) { // 接收调用方UIAbility传过来的参数 globalThis.funcAbilityWant = want; // ... } }
在FuncAbility中,此时需要在Index页面中通过页面路由Router模块实现指定页面的跳转,由于此时FuncAbility对应的Index页面是处于激活状态,不会重新变量声明以及进入aboutToAppear()生命周期回调中。因此可以在Index页面的onPageShow()生命周期回调中实现页面路由跳转的功能。
import router from '@ohos.router'; @Entry @Component struct Index { onPageShow() { let funcAbilityWant = globalThis.funcAbilityWant; let url2 = funcAbilityWant?.parameters?.router; if (url2 && url2 === 'funcA') { router.replaceUrl({ url: 'pages/Second', }) } } // 页面展示 build() { // ... } }
当被调用方Ability的启动模式设置为standard启动模式时,每次启动都会创建一个新的实例,那么onNewWant()回调就不会被用到。
通过Call调用实现UIAbility交互(仅对系统应用开放)
Call调用是UIAbility能力的扩展,它为UIAbility提供一种能够被外部调用并与外部进行通信的能力。Call调用支持前台与后台两种启动方式,使UIAbility既能被拉起到前台展示UI,也可以在后台被创建并运行。Call调用在调用方与被调用方间建立了IPC通信,因此应用开发者可通过Call调用实现不同UIAbility之间的数据共享。
Call调用的核心接口是startAbilityByCall方法,与startAbility接口的不同之处在于:
- startAbilityByCall支持前台与后台两种启动方式,而startAbility仅支持前台启动。
- 调用方可使用startAbilityByCall所返回的Caller对象与被调用方进行通信,而startAbilty不具备通信能力。
Call调用的使用场景主要包括:
- 需要与被启动的UIAbility进行通信。
- 希望被启动的UIAbility在后台运行。