Harmony os——UIAbility 组件基本用法:启动页、Context、终止与拉起方信息全流程

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 运行时的环境和能力集合",你可以通过它:

  • 拿到各种配置:abilityInfocurrentHapModuleInfo 等;

  • 做很多动作:

    • 启动其他 UIAbility:startAbility()
    • 连接 ServiceExtension:connectServiceExtensionAbility()
    • 终止当前 UIAbility:terminateSelf()
    • ......

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.');
     });
   }
 }

这个能力适合用于:

  • 做简单的"来源判断"(例如:从首页打开和从通知打开的逻辑区分);

  • 日志埋点:记录调用链;

相关推荐
用户463989754321 小时前
Harmony os——启动应用内的 UIAbility:跨 Ability 跳转、回传结果 & 指定页面全流程
harmonyos
用户463989754321 小时前
Harmony os——UIAbility 组件生命周期|我按自己的理解梳了一遍
harmonyos
汉堡黄2 小时前
鸿蒙开发:案例集合Tabs:自定义tabs突出(凸出)球体左右跟随滑动动画
harmonyos
Q***l6873 小时前
HarmonyOS在智能穿戴中的Huawei Watch
华为·harmonyos
p***43487 小时前
HarmonyOS系统架构
华为·系统架构·harmonyos
Y***K43410 小时前
HarmonyOS在智能穿戴中的健康算法
华为·harmonyos
1***815314 小时前
HarmonyOS在智能车载中的娱乐系统
华为·harmonyos·娱乐
4***R24014 小时前
HarmonyOS在智能车载中的车载娱乐
华为·harmonyos·娱乐
食品一少年14 小时前
【DAY1】零基础Flutter 编译开发 鸿蒙HarmonyOS
华为·harmonyos