Harmony os——应用上下文 Context:我理解的几种「视角」

65 阅读3分钟

应用上下文 Context:我理解的几种「视角」

可以把 Context 理解成: 「系统给你的一张工作证 + 能力集合,不同层级的证能做的事不一样。」


1. Context 总体概念

  • Context = 当前对象的运行环境 + 能力入口

  • 提供信息:

    • resourceManager(资源)
    • applicationInfo(应用信息)
    • area(文件加密分区)
    • 各种路径(cacheDir、filesDir 等)
    • 各类监听与能力(前后台、生命周期、清理数据、设置语言等)

2. 常见几类 Context 对比

记忆口诀:App(全局) → Module → Ability → Extension → UI(窗口)

类型作用层级主要能力获取方式典型场景
ApplicationContext应用级(整个 APP)应用基本信息、应用级路径、环境/前后台/生命周期监听、加密分区、清理数据等this.context.getApplicationContext()需要全局视角:监听整个应用前后台、UIAbility 生命周期、设置应用语言/主题等
AbilityStageContextModule 级HapModuleInfo、Configuration、模块级路径AbilityStage 中直接 this.context在 AbilityStage 里做模块初始化、获取模块路径
UIAbilityContext单个 UIAbilityabilityInfo、currentHapModuleInfo、startAbility/terminateSelf、连接服务等UIAbilitythis.context;在页面中 this.getUIContext().getHostContext()第三方应用最常用:页面里启动其他 Ability、结束当前 Ability、拿 BundleName 等
ExtensionContext单个 ExtensionAbility每种 Extension 有专属能力,例如 FormExtensionContext 支持卡片 API在 ExtensionAbility 中 this.context卡片、输入法、AppServiceExtension 等组件内部用
UIContextArkUI UI 实例级UI 相关能力:弹 Toast、Alert、软键盘避让模式、获取字体等组件内 this.getUIContext();Window 上 window.getUIContext()纯 UI 操作,不管 Bundle/Ability,只管「这个 UI 实例」

重要注意:

不同 Context 能力不同,不能强行互转。 比如 ApplicationContextsetFontSizeScale()UIAbilityContext 没有, 即使你「强转」也没用,方法本身就不存在。


3. 各类 Context 的获取方式速记

3.1 ApplicationContext(全局)

在 UIAbility 里:

 import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
 ​
 export default class EntryAbility extends UIAbility {
   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
     const applicationContext = this.context.getApplicationContext();
     // 在这里可以注册前后台监听、生命周期监听、获取应用信息等
   }
 }

在 AbilityStage / ExtensionAbility 中也类似:this.context.getApplicationContext()


3.2 AbilityStageContext(模块级)

 import { AbilityStage } from '@kit.AbilityKit';
 ​
 export default class MyAbilityStage extends AbilityStage {
   onCreate(): void {
     const abilityStageContext = this.context;
     // 拿模块信息、模块级路径等
   }
 }

3.3 获取其他 Module 的 Context(同一应用)

 import { common, application } from '@kit.AbilityKit';
 import { BusinessError } from '@kit.BasicServicesKit';
 ​
 @Entry
 @Component
 struct Page_Context {
   private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
 ​
   build() {
     // ...
     ListItem() {
       Row() { /* ... */ }
         .onClick(() => {
           const moduleName2 = 'entry';
           application.createModuleContext(this.context, moduleName2)
             .then((data: common.Context) => {
               console.info(`CreateModuleContext success, data: ${JSON.stringify(data)}`);
               if (data) {
                 this.getUIContext().getPromptAction().showToast({ message: '成功获取Context' });
               }
             })
             .catch((err: BusinessError) => {
               console.error(`CreateModuleContext failed, err code:${err.code}, err msg: ${err.message}`);
             });
         })
     }
   }
 }

3.4 UIAbilityContext

在 UIAbility 类里:

 export default class EntryAbility extends UIAbility {
   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
     const context = this.context;  // UIAbilityContext
   }
 }

在页面里:

写法 1:先定义成员变量:

 import { common, Want } from '@kit.AbilityKit';
 ​
 @Entry
 @Component
 struct Page_EventHub {
   private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
 ​
   startAbilityTest(): void {
     const want: Want = { /* ... */ };
     this.context.startAbility(want);
   }
 }

写法 2:临时获取:

 @Entry
 @Component
 struct Page_UIAbilityComponentsBasicUsage {
   startAbilityTest(): void {
     const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
     const want: Want = { /* ... */ };
     context.startAbility(want);
   }
 }

结束当前 UIAbility:

 import { common } from '@kit.AbilityKit';
 import { BusinessError } from '@kit.BasicServicesKit';
 ​
 @Entry
 @Component
 struct Page_UIAbilityComponentsBasicUsage {
   build() {
     Column() {
       Button('FuncAbilityB')
         .onClick(() => {
           const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
           try {
             context.terminateSelf((err: BusinessError) => {
               if (err.code) {
                 console.error(`terminateSelf failed, code is ${err.code}, message is ${err.message}.`);
                 return;
               }
               console.info(`terminateSelf succeed.`);
             });
           } catch (err) {
             const code = (err as BusinessError).code;
             const message = (err as BusinessError).message;
             console.error(`terminateSelf failed, code is ${code}, message is ${message}.`);
           }
         })
     }
   }
 }

3.5 ExtensionContext(以 FormExtension 为例)

 import { FormExtensionAbility, formBindingData } from '@kit.FormKit';
 import { Want } from '@kit.AbilityKit';
 ​
 export default class MyFormExtensionAbility extends FormExtensionAbility {
   onAddForm(want: Want) {
     const formExtensionContext = this.context;
     // ... 使用卡片上下文能力
     const dataObj: Record<string, string> = {
       temperature: '11c',
       time: '11:00'
     };
     return formBindingData.createFormBindingData(dataObj);
   }
 }

4. 文件路径与应用沙箱:不同 Context 得到的路径有啥区别?

记忆点:

  • ApplicationContext → 应用级目录(不带模块名)
  • AbilityStageContext / UIAbilityContext / ExtensionContext → 模块级目录(路径里带 <module-name>

典型属性(简化版):

属性ApplicationContext 的路径AbilityStage / UIAbility / Extension 的路径
bundleCodeDir<前缀>/el1/bundle<前缀>/el1/bundle(一样)
cacheDir<前缀>/<加密等级>/base/cache<前缀>/<加密等级>/base/haps/<module-name>/cache
filesDir<前缀>/<加密等级>/base/files<前缀>/<加密等级>/base/haps/<module-name>/files
preferencesDir<前缀>/<加密等级>/base/preferences<前缀>/<加密等级>/base/haps/<module-name>/preferences
tempDir<前缀>/<加密等级>/base/temp<前缀>/<加密等级>/base/haps/<module-name>/temp
databaseDir<前缀>/<加密等级>/database<前缀>/<加密等级>/database/<module-name>

📌 共同点:都是在应用沙箱目录里,卸载应用时会被清理(应用级/模块级略有差别)。


4.1 获取缓存目录 cacheDir(示例)

 import { common } from '@kit.AbilityKit';
 ​
 const TAG: string = '[Page_Context]';
 const DOMAIN_NUMBER: number = 0xFF00;
 ​
 @Entry
 @Component
 struct Index {
   @State message: string = 'Hello World';
   private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
 ​
   build() {
     Button('create file')
       .onClick(() => {
         const applicationContext = this.context.getApplicationContext();
         const cacheDir = applicationContext.cacheDir;
         // 在 cacheDir 下面存放缓存文件
       });
   }
 }

4.2 获取 filesDir 并读写文件(示例)

import { common } from '@kit.AbilityKit';
import { buffer } from '@kit.ArkTS';
import { fileIo, ReadOptions } from '@kit.CoreFileKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = '[Page_Context]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  private context = this.getUIContext().getHostContext() as common.UIAbilityContext;

  build() {
    Button('create file')
      .onClick(() => {
        const applicationContext = this.context.getApplicationContext();
        const filesDir = applicationContext.filesDir;
        hilog.info(DOMAIN_NUMBER, TAG, `filePath: ${filesDir}`);

        const file = fileIo.openSync(
          filesDir + '/test.txt',
          fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE
        );

        const writeLen = fileIo.writeSync(file.fd, 'Try to write str.');

        const arrayBuffer = new ArrayBuffer(1024);
        const readOptions: ReadOptions = { offset: 0, length: arrayBuffer.byteLength };
        const readLen = fileIo.readSync(file.fd, arrayBuffer, readOptions);

        const buf = buffer.from(arrayBuffer, 0, readLen);
        hilog.info(DOMAIN_NUMBER, TAG, `the content of file: ${buf.toString()}`);

        fileIo.closeSync(file);
      });
  }
}

5. 加密分区 area:EL1 ~ EL5 怎么理解?

Context 上有一个关键属性:area,控制当前读写使用哪个加密分区。

大致理解:

  • EL1:设备级加密,锁屏前后都能访问。适合私有但不敏感数据(闹铃、壁纸等)。
  • EL2:用户级更敏感数据。
  • EL3:锁屏时仍需读写、创建文件的场景(步数、下载、音乐播放等)。
  • EL4:安全信息,锁屏后不读写、不创建。
  • EL5:更高隐私,锁屏后默认不可读写,如需锁屏后继续访问要额外申请。

切换分区的例子:

// EntryAbility.ets
import { UIAbility, contextConstant, AbilityConstant, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 存普通信息 → 切到 EL1
    this.context.area = contextConstant.AreaMode.EL1;

    // 存更敏感信息 → EL2
    this.context.area = contextConstant.AreaMode.EL2;

    // 需要锁屏也读写 → EL3
    this.context.area = contextConstant.AreaMode.EL3;

    // 安全信息锁屏不读写 → EL4
    this.context.area = contextConstant.AreaMode.EL4;

    // 高敏隐私 → EL5
    this.context.area = contextConstant.AreaMode.EL5;
  }
}

在页面里动态切换并提示:

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

@Entry
@Component
struct Page_Context {
  private context = this.getUIContext().getHostContext() as common.UIAbilityContext;

  build() {
    // 切到 EL1
    ListItem()
      .onClick(() => {
        if (this.context.area === contextConstant.AreaMode.EL2) {
          this.context.area = contextConstant.AreaMode.EL1;
          this.getUIContext().getPromptAction().showToast({ message: 'SwitchToEL1' });
        }
      });

    // 切到 EL2
    ListItem()
      .onClick(() => {
        if (this.context.area === contextConstant.AreaMode.EL1) {
          this.context.area = contextConstant.AreaMode.EL2;
          this.getUIContext().getPromptAction().showToast({ message: 'SwitchToEL2' });
        }
      });
  }
}

6. 基于 ApplicationContext 的全局监听

6.1 监听应用前后台切换

 import { UIAbility, ApplicationStateChangeCallback } from '@kit.AbilityKit';
 import { BusinessError } from '@kit.BasicServicesKit';
 ​
 export default class LifecycleAbility extends UIAbility {
   onCreate() {
     const applicationStateChangeCallback: ApplicationStateChangeCallback = {
       onApplicationForeground() {
         console.info('applicationStateChangeCallback onApplicationForeground');
       },
       onApplicationBackground() {
         console.info('applicationStateChangeCallback onApplicationBackground');
       }
     };
 ​
     const applicationContext = this.context.getApplicationContext();
     try {
       applicationContext.on('applicationStateChange', applicationStateChangeCallback);
     } catch (paramError) {
       console.error(
         `error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`
       );
     }
   }
 }

6.2 监听 UIAbility 生命周期变化

 import {
   AbilityConstant,
   AbilityLifecycleCallback,
   UIAbility,
   Want
 } from '@kit.AbilityKit';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { window } from '@kit.ArkUI';
 import { BusinessError } from '@kit.BasicServicesKit';
 ​
 const TAG: string = '[LifecycleAbility]';
 const DOMAIN_NUMBER: number = 0xFF00;
 ​
 export default class LifecycleAbility extends UIAbility {
   lifecycleId: number = -1;
 ​
   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
     const abilityLifecycleCallback: AbilityLifecycleCallback = {
       onAbilityCreate(uiAbility) {
         hilog.info(DOMAIN_NUMBER, TAG, `onAbilityCreate: ${JSON.stringify(uiAbility.launchWant)}`);
       },
       onWindowStageCreate(uiAbility, windowStage: window.WindowStage) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onWindowStageCreate');
       },
       onWindowStageActive(uiAbility, windowStage: window.WindowStage) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onWindowStageActive');
       },
       onWindowStageInactive(uiAbility, windowStage: window.WindowStage) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onWindowStageInactive');
       },
       onWindowStageDestroy(uiAbility, windowStage: window.WindowStage) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onWindowStageDestroy');
       },
       onAbilityDestroy(uiAbility) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onAbilityDestroy');
       },
       onAbilityForeground(uiAbility) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onAbilityForeground');
       },
       onAbilityBackground(uiAbility) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onAbilityBackground');
       },
       onAbilityContinue(uiAbility) {
         hilog.info(DOMAIN_NUMBER, TAG, 'onAbilityContinue');
       }
     };
 ​
     const applicationContext = this.context.getApplicationContext();
     try {
       this.lifecycleId = applicationContext.on('abilityLifecycle', abilityLifecycleCallback);
     } catch (err) {
       const code = (err as BusinessError).code;
       const message = (err as BusinessError).message;
       hilog.error(DOMAIN_NUMBER, TAG, `register failed, code=${code}, msg=${message}`);
     }
 ​
     hilog.info(DOMAIN_NUMBER, TAG, `register callback number: ${this.lifecycleId}`);
   }
 ​
   onDestroy(): void {
     const applicationContext = this.context.getApplicationContext();
     try {
       applicationContext.off('abilityLifecycle', this.lifecycleId);
     } catch (err) {
       const code = (err as BusinessError).code;
       const message = (err as BusinessError).message;
       hilog.error(DOMAIN_NUMBER, TAG, `unregister failed, code=${code}, msg=${message}`);
     }
   }
 }

7. 一口气记住的「考试版总结」

Context 是什么?

  • 是对象的运行上下文,提供资源管理、应用信息、沙箱路径、加密分区和各种系统能力的入口。

有哪几种?

  • ApplicationContext:应用级,全局监听/应用路径/语言主题设置/清理数据。
  • AbilityStageContext:模块级,Module 信息 + 模块级路径。
  • UIAbilityContext:单个 UIAbility 的上下文,负责启动/结束 Ability,拿 BundleName 等。
  • ExtensionContext:各类 ExtensionAbility 的上下文,有各自专属能力。
  • UIContext:ArkUI UI 实例的上下文,做弹框、软键盘避让等纯 UI 操作。

路径差异?

  • ApplicationContext → 应用级 <...>/base/files
  • 其他 Context → 带 Module 名 <...>/base/haps/<module-name>/files

关键场景?

  • ApplicationContext:监听应用前后台/能力生命周期、设置语言/主题、获取加密分区。
  • UIAbilityContext:页面里 startAbility()terminateSelf()、拿 bundleName / abilityName
  • AbilityStageContext:Module 初始化、环境监听、onAcceptWant(specified 模式)。
  • ExtensionContext:卡片/输入法/后台服务等内部使用。