Harmony os------UIAbility 组件基本用法:启动页、Context、终止与拉起方信息全流程
这篇是我整理的 UIAbility 组件基础实战笔记,适合刚上手 HarmonyOS Stage 模型的时候快速过一遍。 重点只有三个:
- UIAbility 启动后怎么指定第一个页面
- 在 Ability 和页面中怎么拿到 UIAbilityContext
- 怎么 终止当前 UIAbility ,以及 如何获取"是谁拉起了我"
一、UIAbility 启动后为什么会白屏?
UIAbility 启动的时候,如果你不指定要加载哪一个页面,系统其实已经把 Ability 拉起来了,但是没有 UI 页面可以画,这时候就会出现:
App 打开了,但是一片白 → 本质是 WindowStage 没有 load 任意内容。
在 Stage 模型里,UIAbility 的 UI 是通过 WindowStage 来加载的,关键点在这个生命周期:
javascript
onWindowStageCreate(windowStage: window.WindowStage): void
在这里用 windowStage.loadContent() 把首页页面加载进去就可以了。
1.1 正确写法:在 onWindowStageCreate 里指定启动页面
javascript
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 主窗口创建完成,设置启动页面
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
console.error(`loadContent failed, code: ${err.code}, msg: ${err.message}`);
return;
}
console.info('Index page loaded.');
});
}
}
几点小注意:
'pages/Index'是页面路径,默认工程会帮你生成 Index 页面;- 如果你把首页改成别的页,比如
pages/Home,记得同时改这里; - 不要在 onCreate 里 load 页面 ,UI 加载统一放在
onWindowStageCreate中。
二、如何获取 UIAbilityContext?
UIAbilityContext 是 Stage 模型里非常关键的一个对象,可以理解为"这个 UIAbility 运行时的环境和能力集合",你可以通过它:
-
拿到各种配置:
abilityInfo、currentHapModuleInfo等; -
做很多动作:
- 启动其他 UIAbility:
startAbility() - 连接 ServiceExtension:
connectServiceExtensionAbility() - 终止当前 UIAbility:
terminateSelf() - ......
- 启动其他 UIAbility:
2.1 在 UIAbility 中获取 Context:直接用 this.context
在 UIAbility 类内部最简单:
scala
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 获取当前 UIAbility 的上下文
const context = this.context;
console.info(`bundleName: ${context.abilityInfo.bundleName}`);
console.info(`abilityName: ${context.abilityInfo.name}`);
// 这里可以做初始化逻辑
}
}
这一招适合在 Ability 生命周期里使用,比如 onCreate、onForeground 等。
2.2 在页面(UI 组件)中获取 Ability 的 Context(方式一:作为成员变量缓存)
在 ArkUI 组件里,我们也经常需要 UIAbilityContext,比如:
- 从页面里跳转到另一个 Ability;
- 从页面里直接结束当前 UIAbility。
常见写法是:在组件上定义一个 context 成员变量:
typescript
import { common, Want } from '@kit.AbilityKit';
@Entry
@Component
struct Page_EventHub {
// 一次性获取并缓存 UIAbilityContext
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
startAbilityTest(): void {
const want: Want = {
// 填写目标 UIAbility 的信息
};
this.context.startAbility(want);
}
build() {
// UI 渲染逻辑
}
}
特点:
- 写法干净,逻辑清晰;
- 适合这个组件里会多次用到
context的场景。
2.3 在页面中获取 Ability 的 Context(方式二:用时再获取)
如果只是偶尔用一下 Context,也可以在函数内按需获取:
typescript
import { common, Want } from '@kit.AbilityKit';
@Entry
@Component
struct Page_UIAbilityComponentsBasicUsage {
startAbilityTest(): void {
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
const want: Want = {
// Want 参数
};
context.startAbility(want);
}
build() {
// UI 渲染逻辑
}
}
对比一下:
- 方式一:成员变量缓存 → 多次使用更方便;
- 方式二:局部变量 → 简单一次性使用的时候更轻量。
三、如何优雅地终止当前 UIAbility?(terminateSelf)
有些页面是从"功能 Ability"跳转过来的,比如"设置结果页 / 授权完成页",用完就可以把这个 UIAbility 关闭掉。
在页面中可以通过 UIAbilityContext.terminateSelf() 来结束当前实例:
typescript
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Page_UIAbilityComponentsBasicUsage {
build() {
Column() {
Button('关闭当前 UIAbility')
.onClick(() => {
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
try {
context.terminateSelf((err: BusinessError) => {
if (err.code) {
console.error(`terminateSelf failed, code: ${err.code}, msg: ${err.message}.`);
return;
}
console.info('terminateSelf succeed.');
});
} catch (err) {
// 同步参数错误,比如 context 异常
const code = (err as BusinessError).code;
const msg = (err as BusinessError).message;
console.error(`terminateSelf failed, code: ${code}, msg: ${msg}.`);
}
})
}
}
}
几点注意:
terminateSelf是异步接口,有回调;- 异步回调里要判断
err.code,为 0 才是成功; - 外面再包一层 try...catch,主要是兜住参数层面的同步错误。
四、如何在 UIAbilityB 中知道"是谁拉起了我"?
在实际业务里,很多时候会有这种需求:
我是 UIAbilityB,我想知道是谁用 startAbility 把我拉起来的? 是哪个 Ability?哪个进程?哪个 Bundle?
在 Stage 模型中,When A 调用 startAbility() 拉起 B 时 ,系统会自动在 Want 的 parameters 里塞入一些"调用方信息":
- 调用方进程 ID:
ohos.aafwk.param.callerPid - 调用方 Bundle 名:
ohos.aafwk.param.callerBundleName - 调用方 Ability 名:
ohos.aafwk.param.callerAbilityName
我们不需要手动传这些字段,系统会帮我们补好,直接在 B 的 onCreate() 里从 want.parameters 读取即可。
4.1 调用者:UIAbilityA 中拉起 UIAbilityB
typescript
import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State context: common.UIAbilityContext =
this.getUIContext().getHostContext() as common.UIAbilityContext;
build() {
List({ space: 4 }) {
ListItem() {
Button('terminateSelf')
.onClick(() => {
this.context.terminateSelf();
})
.width('100%')
}
ListItem() {
Button('拉起UIAbilityB')
.onClick(() => {
const want: Want = {
bundleName: this.context.abilityInfo.bundleName,
abilityName: 'UIAbilityB',
};
this.context.startAbility(want, (err: BusinessError) => {
if (err.code) {
console.error(
`Failed to startAbility. Code: ${err.code}, message: ${err.message}.`
);
}
});
})
.width('100%')
}
}
.listDirection(Axis.Vertical)
.backgroundColor(0xDCDCDC)
.padding(20)
.margin({ top: 250 })
}
}
注意:这里 A 不需要手动去给 want.parameters 填 caller 信息,系统会自动添加。
4.2 被拉起者:UIAbilityB 中读取调用方信息
javascript
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class UIAbilityB extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 系统自动向 Want.parameters 中注入调用方信息
console.info(`onCreate, callerPid: ${want.parameters?.['ohos.aafwk.param.callerPid']}.`);
console.info(`onCreate, callerBundleName: ${want.parameters?.['ohos.aafwk.param.callerBundleName']}.`);
console.info(`onCreate, callerAbilityName: ${want.parameters?.['ohos.aafwk.param.callerAbilityName']}.`);
}
onDestroy(): void {
console.info('UIAbilityB onDestroy.');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
console.info('AbilityB onWindowStageCreate.');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
console.error(`Failed to load content, code: ${err.code}, msg: ${err.message}.`);
return;
}
console.info('Succeeded in loading the content.');
});
}
}
这个能力适合用于:
-
做简单的"来源判断"(例如:从首页打开和从通知打开的逻辑区分);
-
日志埋点:记录调用链;