鸿蒙开发:了解Context

前言

之前在封装图片滑动验证,还有当下的一个自适应背景颜色功能时,都需要获取到image.PixelMap对象,于是就使用了getMediaContent方法,代码如下:

TypeScript 复制代码
const resourceMgr: resourceManager.ResourceManager = this.getUIContext().getHostContext()!!.resourceManager;
const fileData: Uint8Array = await resourceMgr.getMediaContent($r("app.media.banner_001").id)
const buffer = fileData.buffer as ArrayBuffer;
const imageSource: image.ImageSource = image.createImageSource(buffer);
const pixelMap: image.PixelMap = await imageSource.createPixelMap();

然而,以上的代码,却报了如下错误:

TypeScript 复制代码
Failed to get media data in getMediaFunc

后续经过排查,发现了问题原因,因为我是在单独的共享包中调用的,造成了跨模块访问资源时 Context 不正确,所以导致了资源获取失败。

解决以上的问题也很简单,通过createModuleContext创建目标模块的Context,然后再获取资源管理器即可,代码如下:

TypeScript 复制代码
  const ctx = this.getUIContext().getHostContext()!!
  const context = await application.createModuleContext(ctx, "模块名字")

当然了,还有一种解决方式,直接使用getMediaByName方法,传入资源的名字也可以。

TypeScript 复制代码
 const resourceMgr: resourceManager.ResourceManager = this.getUIContext().getHostContext()!!.resourceManager;
 const fileData: Uint8Array = await resourceMgr.getMediaByName("banner_001")
 const buffer = fileData.buffer as ArrayBuffer;
 const imageSource: image.ImageSource = image.createImageSource(buffer);
 const pixelMap: image.PixelMap = await imageSource.createPixelMap();

我们可以发现,很多场景下都会用到Context,比如showToast,比如获取缓存路径等等,那么什么是Context,Context在实际的开发中又是扮演着怎样的角色呢,下面,我们就来一起了解一下。

什么是Context

官方解读为:Context是应用中对象的上下文,其提供了应用的一些基础信息,例如resourceManager(资源管理)、applicationInfo(当前应用信息)、area(文件分区)等。

我们在实际的开发中,可能遇到过不同的Context,比如最常见的是UIContext,然后就是ApplicationContext,除此之外,还有很多的Context,比如基类Context、ApplicationContext、AbilityStageContext、UIAbilityContext、ExtensionContext等Context,不同类型Context的获取方式与使用场景也是不同的。

不同类型Context的继承关系如下:

不同类型Context的获取方式和使用场景如下:

Context类型 说明 获取方式 使用场景
ApplicationContext 应用的全局上下文,提供应用级别的信息和能力。 - 从API version 14开始,可以直接使用getApplicationContext获取。- API version 14以前版本,只能使用其他Context实例的getApplicationContext方法获取。 - 获取当前应用的基本信息。- 获取应用级别的文件路径。- 获取和修改加密分区。- 监听应用前后台变化。
AbilityStageContext 模块级别的上下文,提供模块级别的信息和能力。 - 如果需要获取当前AbilityStage的Context,可以直接通过AbilityStage实例获取context属性。- 如果需要获取同一应用中其他Module的Context,可以通过createModuleContext方法。 - 获取当前模块的基本信息。- 获取模块级别的文件路径。
UIAbilityContext UIAbility组件对应的上下文,提供UIAbility对外的信息和能力。 - 通过UIAbility实例直接获取context属性。- 在UIAbility的窗口中加载的UI组件实例,需要使用@ohos.arkui.UIContext提供的getHostContext方法。 - 获取当前UIAbility的基本信息。- 启动其他应用或元服务、连接/断连系统应用创建的ServiceExtensionAbility等。- 销毁自身的UIAbility。
ExtensionContext ExtensionAbility组件对应的上下文,每种类型的ExtensionContext提供不同的信息和能力。 通过ExtensionAbility实例直接获取Context属性。 不同类型的ExtensionAbility对应的Context提供的能力不同。以输入法上下文InputMethodExtensionContext为例,主要提供如下能力:- 获取InputMethodExtensionAbility的基本信息。- 销毁当前输入法。
UIContext ArkUI的UI实例上下文,提供UI操作相关的能力。与上述其他类型的Context无直接关系。 - 在UI组件内获取UIContext,直接使用组件内置的getUIContext方法。- 在存在Window实例的情况下,使用@ohos.window提供的getUIContext方法。 主要用于UI实例中UI相关操作,例如:- 获取当前UI实例的字体。- 显示不同类型的弹框。- 设置软键盘弹出时UI避让模式。

一、ApplicationContext

ApplicationContext 是应用级别的全局上下文,继承自 Context,提供了应用生命周期监听、进程管理、应用环境设置等应用级别的管控能力。有一个需要注意的点是,一个应用只有一个 ApplicationContext 实例,可以在 UIAbility、ExtensionAbility、AbilityStage 中获取。

获取方式

从 API version 14 开始,可以直接通过 application.getApplicationContext()获取,无需依赖 Context 基类;API version 14 以前,只能使用其他 Context 实例的 getApplicationContext()方法获取。

TypeScript 复制代码
// 方式一:API 14+ 直接获取(推荐)
import { application, common } from "@kit.AbilityKit";

let appContext: common.ApplicationContext = application.getApplicationContext();

// 方式二:通过其他 Context 实例获取(API 9+ 通用)
// 在 UIAbility 中
import { UIAbility, common } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want): void {
    let appContext: common.ApplicationContext = this.context.getApplicationContext();
  }
}

核心方法与能力

方法/能力 说明
on('abilityLifecycle') 注册应用内组件生命周期变化监听
on('environment') 注册系统环境变化监听(语言、颜色模式等)
on('systemMemoryLevel') 注册系统内存变化监听
off(...) 取消对应的事件监听
getApplicationInfo() 获取应用信息(继承自 Context)
getCacheDir()/ getFilesDir() 获取应用级文件路径(继承自 Context)
area 获取/设置加密分区模式
setColorMode() 设置应用颜色模式
setLanguage() 设置应用语言

典型使用场景

  • 获取当前应用的基本信息(name、应用版本等)
  • 获取应用级别的文件路径(如缓存目录、文件目录)
  • 获取和修改加密分区
  • 监听应用前后台变化、系统内存变化、环境变化
  • 设置应用语言和颜色模式
TypeScript 复制代码
import { application, common, AbilityConstant } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const DOMAIN: number = 0x0000;
const TAG: string = 'AppContextDemo';

// 获取应用上下文并监听生命周期
let appContext: common.ApplicationContext = application.getApplicationContext();

let abilityLifecycleCallback: AbilityLifecycleCallback = {

  onAbilityCreate(ability): void {
    hilog.info(DOMAIN, TAG, `Ability创建: ${ability.context.abilityInfo.name}`);
  },
  onAbilityForeground(ability): void {
    hilog.info(DOMAIN, TAG, `Ability切到前台: ${ability.context.abilityInfo.name}`);
  },
  onAbilityBackground(ability): void {
    hilog.info(DOMAIN, TAG, `Ability切到后台: ${ability.context.abilityInfo.name}`);
  },
  onAbilityDestroy(ability): void {
    hilog.info(DOMAIN, TAG, `Ability销毁: ${ability.context.abilityInfo.name}`);
  },
  onWindowStageCreate(ability, windowStage) {
    console.info(`AbilityLifecycleCallback onWindowStageCreate ability: ${ability}`);
    console.info(`AbilityLifecycleCallback onWindowStageCreate windowStage: ${windowStage}`);
  },
  onWindowStageActive(ability, windowStage) {
    console.info(`AbilityLifecycleCallback onWindowStageActive ability: ${ability}`);
    console.info(`AbilityLifecycleCallback onWindowStageActive windowStage: ${windowStage}`);
  },
  onWindowStageInactive(ability, windowStage) {
    console.info(`AbilityLifecycleCallback onWindowStageInactive ability: ${ability}`);
    console.info(`AbilityLifecycleCallback onWindowStageInactive windowStage: ${windowStage}`);
  },
  onWindowStageDestroy(ability, windowStage) {
    console.info(`AbilityLifecycleCallback onWindowStageDestroy ability: ${ability}`);
    console.info(`AbilityLifecycleCallback onWindowStageDestroy windowStage: ${windowStage}`);
  },
  onAbilityContinue(ability) {
    console.info(`AbilityLifecycleCallback onAbilityContinue ability: ${ability}`);
  }
}

appContext.on('abilityLifecycle',abilityLifecycleCallback)

// 获取应用级缓存目录
let cacheDir: string = appContext.cacheDir;
hilog.info(DOMAIN, TAG, `缓存目录: ${cacheDir}`);

二、AbilityStageContext(模块上下文)

AbilityStageContext 是 AbilityStage 的上下文环境,继承自 Context,提供访问特定于 AbilityStage 的资源的能力,包括获取 AbilityStage 对应的 ModuleInfo 对象、环境变化对象****。AbilityStage 是 Module 级别的组件管理器,与 Module 一一对应,应用的 HAP/HSP 在首次加载时会创建一个 AbilityStage 实例。

获取方式

通过 AbilityStage 实例的 context属性直接获取;如果需要获取同一应用中其他 Module 的 Context,可以通过 createModuleContext方法创建。

TypeScript 复制代码
import { AbilityStage } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    // 获取当前模块的 AbilityStageContext
    let stageContext: common.AbilityStageContext = this.context;

    // 获取当前模块信息
    let moduleInfo: common.ModuleInfo = stageContext.currentHapModuleInfo;
    console.info(`模块名: ${moduleInfo.moduleName}`);
  }
}

核心属性与方法

属性/方法 说明
currentHapModuleInfo 获取当前 AbilityStage 对应的 ModuleInfo 对象
getCacheDir()/ getFilesDir() 获取模块级文件路径(继承自 Context)

典型使用场景

  • 获取当前模块的基本信息(moduleName、moduleInfo 等)
  • 获取模块级别的文件路径
  • 在应用启动框架(AppStartup)中作为启动任务的入参传递****

三、UIAbilityContext(UIAbility 组件上下文)

UIAbilityContext 是 UIAbility 组件的上下文,继承自 Context。每个 UIAbility 组件实例化时,系统都会自动创建对应的 UIAbilityContext。开发者可以通过它获取组件信息 AbilityInfo、应用信息 ApplicationInfo、拉起其他 UIAbility、连接系统服务、销毁 UIAbility 等****。

获取方式

在 UIAbility 中直接通过 this.context获取;在页面/组件中,需要先获取 UIContext,再通过 getHostContext()获取关联的 UIAbilityContext****。

TypeScript 复制代码
// 方式一:在 UIAbility 中直接获取
import { UIAbility, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want): void {
    let uiAbilityContext: common.UIAbilityContext = this.context;
    console.info(`Ability名称: ${uiAbilityContext.abilityInfo.name}`);
  }
}

// 方式二:在页面组件中获取(推荐方式)
@Entry
  @Component
  struct Index {
    build() {
      Column() {
        Button('获取上下文')
          .onClick(() => {
            // 通过 getUIContext 获取 UIContext,再通过 getHostContext 获取 UIAbilityContext
            let uiAbilityContext: common.UIAbilityContext =
              this.getUIContext().getHostContext() as common.UIAbilityContext;
            console.info(`Ability名称: ${uiAbilityContext.abilityInfo.name}`);
          })
      }
    }
  }

核心方法与能力

方法 说明
startAbility(want) 启动其他 UIAbility(支持 callback 和 Promise 两种方式)
startAbilityForResult(want) 启动 UIAbility 并获取返回结果
terminateSelf() 销毁当前 UIAbility
terminateSelfWithResult() 销毁当前 UIAbility 并返回结果
connectServiceExtensionAbility(want) 连接 ServiceExtensionAbility
disconnectServiceExtensionAbility(connection) 断开 ServiceExtensionAbility 连接
abilityInfo 获取当前 UIAbility 的配置信息
currentHapModuleInfo 获取当前 HAP 模块信息
config 获取配置信息

典型使用场景

  • 获取当前 UIAbility 的基本信息
  • 启动其他应用或元服务
  • 连接/断连系统应用创建的 ServiceExtensionAbility
  • 销毁自身的 UIAbility
  • 页面间传参与结果回传
TypeScript 复制代码
import { UIAbility, Want, common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const DOMAIN: number = 0x0000;
const TAG: string = 'UIAbilityContextDemo';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want): void {
    let context: common.UIAbilityContext = this.context;

    // 启动另一个 UIAbility
    let wantInfo: Want = {
      bundleName: 'com.example.demo',
      abilityName: 'OtherAbility'
    };
    context.startAbility(wantInfo)
      .then(() => {
        hilog.info(DOMAIN, TAG, '启动成功');
      })
      .catch((err: BusinessError) => {
        hilog.error(DOMAIN, TAG, `启动失败: ${err.message}`);
      });
  }

  onBackPress(): boolean {
    // 销毁当前 UIAbility
    this.context.terminateSelf();
    return true;
  }
}

四、ExtensionContext(扩展能力上下文)

ExtensionContext 是 ExtensionAbility 组件对应的上下文,继承自 Context。每种类型的 ExtensionAbility 都有对应的 ExtensionContext 子类,提供不同的信息和能力****。ExtensionContext 本身是基类,实际使用时通常操作其子类。

常见子类

子类 对应 ExtensionAbility 核心能力
FormExtensionContext FormExtensionAbility 查询该扩展的FormExtensionAbility所属HAP包等信息。
InputMethodExtensionContext InputMethodExtensionAbility 获取输入法信息、销毁当前输入法
AccessibilityExtensionContext AccessibilityExtensionAbility 配置辅助功能、查询节点信息、手势注入
PushExtensionContext PushExtensionAbility 访问推送扩展资源
AgentExtensionContext AgentExtensionAbility 访问智能体配置的 AgentCard 信息
AppServiceExtensionContext AppServiceExtensionAbility 连接/断开系统应用后台服务

获取方式

通过 ExtensionAbility 实例直接获取 context属性****。

TypeScript 复制代码
import { FormExtensionAbility, formBindingData } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';

export default class MyFormExtensionAbility extends FormExtensionAbility {
  onAddForm(want: Want) {
    console.info(`FormExtensionAbility onAddForm, want: ${want.abilityName}`);
    let extensionContext = this.context;
    let hapInfo = extensionContext.currentHapModuleInfo;
    console.info(`HAP name is: ${hapInfo.name}`);
    let dataObj1: Record<string, string> = {
      'temperature': '11c',
      'time': '11:00'
    };
    let obj1: formBindingData.FormBindingData = formBindingData.createFormBindingData(dataObj1);
    return obj1;
  }
};

典型使用场景

  • 不同类型的 ExtensionAbility 对应不同的后台服务场景
  • 获取当前 ExtensionAbility 的基本信息
  • 启动/停止/绑定/解绑其他 Ability
  • 销毁当前 ExtensionAbility

五、UIContext(UI 实例上下文)

UIContext 是 UI 实例运行环境的抽象概念,用于关联窗口与 UI 页面,管理组件、布局、动画以及交互事件等 UI 功能。UIContext 与上述四种 Context 无继承关系,它由窗口对象创建并管理,每个窗口对应一个 UIContext 实例****。

从 API version 10 开始,许多全局接口(如 @ohos.promptAction@ohos.routerAlertDialog等)因多 UI 实例场景下上下文不明确而被废弃,需要通过 UIContext 提供的对应方法获取实例后调用****。

获取方式

UIContext 有三种获取方式****:

TypeScript 复制代码
// 方式一:在自定义组件中通过内置方法获取(最常用)
@Entry
  @Component
  struct Index {
    build() {
      Column() {
        Button('获取UIContext')
          .onClick(() => {
            let uiContext: UIContext = this.getUIContext();
          })
      }
    }
  }

// 方式二:在 UIAbility 中通过窗口获取
import { UIAbility, window } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    let uiContext: UIContext = windowStage.getMainWindowSync().getUIContext();
  }
}

// 方式三:通过 UIContext 静态方法获取
import { UIContext } from '@kit.ArkUI';

let uiContext: UIContext | undefined = UIContext.getCallingScopeUIContext();

核心方法与能力

UIContext 提供了大量 UI 相关的接口,用于替代被废弃的全局接口:

方法 说明 替代的全局接口
getPromptAction() 获取 PromptAction 对象,用于弹窗、Toast 等 @ohos.promptAction
getRouter() 获取 Router 对象,用于页面路由 @ohos.router
showAlertDialog() 显示警告弹窗 AlertDialog.show()
showActionSheet() 显示列表选择弹窗 ActionSheet.show()
getComponentUtils() 获取 ComponentUtils 对象,用于组件坐标和尺寸信息 @ohos.arkui.componentUtils
getMediaQuery() 获取 MediaQuery 对象,用于媒体查询 @ohos.mediaquery
getHostContext() 获取关联的 UIAbilityContext 或 ExtensionContext getContext()
getSharedLocalStorage() 获取共享的 LocalStorage -
runScopedTask() 在指定 UI 上下文中执行任务 -

典型使用场景

  • 替代全局接口进行弹窗操作(AlertDialog、ActionSheet、PromptAction)
  • 页面路由跳转
  • 获取组件坐标和尺寸信息
  • 在页面/组件中获取关联的 UIAbilityContext
  • 多 UI 实例场景下确保 UI 操作在正确的上下文中执行
TypeScript 复制代码
import { UIContext, PromptAction, router } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
  @Component
  struct Index {
    build() {
      Column() {
        // 弹窗示例
        Button('显示Toast')
          .onClick(() => {
            let uiContext: UIContext = this.getUIContext();
            let promptAction: PromptAction = uiContext.getPromptAction();
            promptAction.showToast({
              message: '这是一条Toast消息',
              duration: 2000
            });
          })

        // 页面路由示例
        Button('跳转页面')
          .onClick(() => {
            let uiContext: UIContext = this.getUIContext();
            let routerInstance: router.Router = uiContext.getRouter();
            routerInstance.pushUrl({ url: 'pages/SecondPage' });
          })

        // 警告弹窗示例
        Button('显示警告弹窗')
          .onClick(() => {
            let uiContext: UIContext = this.getUIContext();
            uiContext.showAlertDialog({
              title: '提示',
              message: '确定要执行此操作吗?',
              onConfirm: () => {
                console.info('用户点击了确认');
              }
            });
          })

        // 获取 UIAbilityContext
        Button('获取AbilityContext')
          .onClick(() => {
            let uiContext: UIContext = this.getUIContext();
            let abilityContext: common.UIAbilityContext =
              uiContext.getHostContext() as common.UIAbilityContext;
            console.info(`包名: ${abilityContext.abilityInfo.bundleName}`);
          })
      }
      .width('100%')
        .height('100%')
    }
  }

AppStorage获取Context

在HarmonyOS应用开发中,工具类(非UI组件、非UIAbility的普通class)无法直接获取Context对象。标准做法是在UIAbility的生命周期回调中获取Context后,通过AppStorage.setOrCreate将其保存为全局状态数据,随后在工具类中通过AppStorage.get取出使用****。AppStorage是应用启动时创建的单例,提供应用级别的中心存储,支持主线程内多个UIAbility实例间的数据共享。

示例代码

以下示例分为两个步骤:第一步在EntryAbility中存储Context,第二步在工具类中获取Context。

步骤一:在EntryAbility的onCreate回调中存储Context

TypeScript 复制代码
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 将当前UIAbility的上下文存入AppStorage,key为'appContext'
    AppStorage.setOrCreate('appContext', this.context);
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index');
  }
}

步骤二:在工具类中通过AppStorage获取Context

TypeScript 复制代码
import { common } from '@kit.AbilityKit';

class PreferenceUtil {
  // 从AppStorage中获取UIAbilityContext
  static getContext(): common.UIAbilityContext {
    const context = AppStorage.get<common.UIAbilityContext>('appContext');
    if (!context) {
      throw new Error('Context未初始化,请确认AppStorage中已存储appContext');
    }
    return context;
  }

  // 示例:使用Context获取文件路径
  static getFilesDir(): string {
    const context = this.getContext();
    return context.filesDir;
  }
}

补充说明

  1. 存储时机:Context应在onCreate回调中存储,此时this.context已经可用。避免在onWindowStageCreate之前的其他阶段获取,以免Context尚未初始化****。
  2. 类型安全:AppStorage.get返回值为泛型类型,使用时应明确指定泛型参数(如common.UIAbilityContext),并通过空值检查确保Context已正确存储,避免运行时异常。
  3. Context类型选择:根据实际需求选择存储的Context类型。UIAbilityContext提供组件级能力(如获取filesDir、resourceManager等);若仅需应用级能力(如监听应用前后台变化),可存储ApplicationContext,通过this.context.getApplicationContext()获取****。
  4. 非UI场景的通用方案:此方法不仅适用于工具类,也适用于其他非ArkUI页面(如Worker线程外的纯逻辑模块)中需要访问Context的场景。Worker线程中不支持直接使用此方式,需通过消息传递将Context发送至Worker线程。

相关总结

在UI页面中,我们可以很轻松的获取到Context,但是,在工具类中如何获取呢?首先可以明确的是工具类中是无法直接获取Context的,我们可以在获取应用上下文Context后保存至AppStorage,然后通过AppStorage来获取,当然了,也可以通过别的方式,比如全局静态变量,比如一个单例工具类,等等,都是可以的。

相关推荐
404_coder1 小时前
源码视角下的 Android 开机流程(三):从 Launcher Task 到 WindowState 挂载
android
math_hongfan1 小时前
鸿蒙ArkTS手势交互:拖拽、缩放、旋转与组合手势
学习·华为·交互·harmonyos·鸿蒙
zzz海羊1 小时前
2026全平台移动办公远控助手横测:从鸿蒙到工作站,ToDesk、向日葵、TeamViewer、AnyDesk谁更适配?
人工智能·华为·agent·harmonyos·teamviewer
又见情义1 小时前
RK3568 Android 13 移植 EC20-CE 4G 模块全记录
android·arm开发·驱动开发
网安蟹佬霸1 小时前
Android安全攻防实战:从APK逆向到Frida动态Hook全流程详解(附脚本)
android·前端·安全·web安全·逆向·csrf·网安
雨声不在2 小时前
mitmdump Android 抓包
android
less_121382 小时前
HarmonyOS WPS Open SDK:对接文档阅读路径与联调自查
华为·harmonyos·wps
心平气和量大福大2 小时前
android-实例2-数据库sqlite(查询)
android·数据库·sqlite
时代分流2 小时前
云手机推荐2026:安卓全能、批量挂机、原生iOS全覆盖
android·ios·智能手机