大家好,我是不想掉发的鸿蒙开发工程师 城中的雾,我们已经搞定了上下文的配置以及页面上的使用,但光有界面是不够的。App 得动起来,得和系统交互,得跳来跳去。这时候,光靠 UIContext 那个只管画图的小管家是不够的,我们需要权限更高、路子更野的角色。本期主要聊一聊:AbilityContext。它是 UIAbility 的“分身”,掌握着应用组件的生杀大权。

1. 它是谁?部门经理!

如果说 ApplicationContext 是公司老板,负责定战略;那 AbilityContext 就是部门经理,负责具体的业务执行。

  • 生命周期:它与 UIAbility 绑定。当你打开一个 App 的界面时,它就诞生了;当你把 App 从后台划掉(或者调用 terminateSelf)时,它就下岗了。
  • 职责:专门处理 “能力 (Ability)” 相关的交互。比如启动另一个 App、申请系统权限、连接 Service 等。

核心区别

  • router (UIContext):是在同一个 Ability 内部的页面之间切换(相当于在部门内部换座位)。
  • startAbility (AbilityContext):是启动一个新的 Ability,或者跳转到其他 App(相当于去别的部门办事,或者去别的公司出差)。

2. 如何获取:找到你的经理

在 Stage 模型中,获取 AbilityContext 的方式取决于你现在的代码位置。

场景 A:在 UIAbility 文件中 (EntryAbility.ets)

通过UIAbility直接拿 this.context 即可。

import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 这里的 this.context 就是 AbilityContext
    console.info('Ability ID:', this.context.abilityInfo.name);
  }
}

场景 B:在 UI 页面中 (Index.ets)

在 UI 页面里,我们需要通过 UIContext 顺藤摸瓜找到它。

import { common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  // 1. 定义一个变量来接收
  private context = getContext(this) as common.UIAbilityContext;

  build() {
    Button('获取经理')
      .onClick(() => {
        // 推荐方式 (API 11+):通过 UIContext 获取宿主
        let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
        
        if (context) {
           console.info('当前 Ability 名字:', context.abilityInfo.name);
        }
      })
  }
}

3. 核心能力一:跳转 (startAbility)

在鸿蒙里,只要是“跨越”了 Ability 的跳转,都要找它。

1. 跳转到应用内的另一个 UIAbility

比如从“主页 Ability”跳转到“支付 Ability”。

let want: Want = {
  deviceId: '', // 空表示本设备
  bundleName: 'com.example.myapp', // 包名
  abilityName: 'PayAbility' // 目标 Ability 名
};

context.startAbility(want).then(() => {
  console.info('跳转支付成功');
}).catch((err: BusinessError) => {
  console.error('跳转失败:', err.code);
});

2. 跳转到系统应用 (如拨号盘、浏览器)

这是最常用的场景。比如点击电话号码直接跳到拨号盘。

let want: Want = {
  action: 'ohos.want.action.viewData',
  entities: ['entity.system.home'],
  uri: 'tel:10086'
};

context.startAbility(want);

3. 打开网页 (拉起浏览器)

let want: Want = {
  action: 'ohos.want.action.viewData',
  entities: ['entity.system.browsable'],
  uri: '[https://developer.huawei.com](https://developer.huawei.com)'
};

context.startAbility(want);

4. 核心能力二:权限申请 (requestPermissionsFromUser)

在鸿蒙中,申请动态权限(如相机、麦克风、位置)必须使用 AbilityContextUIContext(API 12+)。

虽然 UIContext 也能申请,但目前 AbilityContext 的兼容性更强。

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';

// 定义要申请的权限列表
const permissions: Array<Permissions> = ['ohos.permission.CAMERA'];

// 使用 AtManager 检查是否已授权
let atManager = abilityAccessCtrl.createAtManager();
// ... 省略检查步骤,假设未授权 ...

// 向用户弹窗申请
context.requestPermissionsFromUser(permissions).then((data) => {
  let grantStatus: Array<number> = data.authResults;
  if (grantStatus.length > 0 && grantStatus[0] === 0) {
    console.info('用户同意了相机权限');
  } else {
    console.warn('用户拒绝了');
  }
});

5. 核心能力三:结束进程 (terminateSelf)

有时候我们需要代码控制退出当前 Ability(注意:不是退出 App,除非这是最后一个 Ability)。

场景:用户点击“完成”按钮,关闭当前的“设置页 Ability”,返回上一级。

// 相当于 Android 的 finish()
context.terminateSelf().then(() => {
  console.info('关闭成功');
});

带结果返回 (setResult):

如果你想告诉上一个页面“我处理完了,结果是OK”,需要在 terminateSelf 之前调用 terminateSelfWithResult。

// 返回数据给上一个页面
let result: common.AbilityResult = {
  resultCode: 1, // 自定义结果码
  want: {
    parameters: {
      'pay_status': 'success'
    }
  }
};

context.terminateSelfWithResult(result);

6. 避坑指南:Context 混用惨案

这是新手最容易犯的错误:在 AbilityContext 里干 UIContext 的活,或者反过来。

惨案 A:用 AbilityContext 弹窗

// 错误示范
// 虽然代码提示可能有 showDialog,但在多窗口场景下,系统不知道弹在哪
context.getPromptAction().showToast(...) // 可能会报错或不显示

** 修正**:弹窗请认准 this.getUIContext().getPromptAction()

惨案 B:用 ApplicationContext 跳转

// 错误示范
// ApplicationContext 没有 startAbility 方法(或者受限)
let appContext = context.getApplicationContext();
appContext.startAbility(...) // 报错:方法不存在

** 修正**:跳转必须用 AbilityContext

总结:AbilityContext 业务速查表

需求场景 方法 API 关键参数
跳内部页面 router.pushUrl (找 UIContext)
跳外部 App startAbility Want (bundleName, abilityName)
打电话/打开网页 startAbility Want (uri: ‘tel:xxx’)
申请权限 requestPermissionsFromUser Permissions[]
关闭当前页 terminateSelf
关闭并返回数据 terminateSelfWithResult AbilityResult

下一期预告:

到现在为止,我们已经在 UI 里面处理了很对上下文的使用场景。但是,如果我们把代码抽离到 utils 工具类,或者 ViewModel 里,脱离了 UI 组件的 this,我们该怎么拿到这些 Context 呢?

  • 全局单例 Context 到底能不能用?
  • 怎么优雅地封装一个全局 Toast 工具类?
  • 下一篇,我们来聊聊 脱离 UI 怎么用 Context?

📚 充电时间

如果有想加入鸿蒙生态的大佬们,快来加入鸿蒙认证吧!初高级证书还没获取的,点这里:

🔗 HarmonyOS第一课:官方认证培训

如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信中提出,非常感谢您的支持。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐