一、背景

在鸿蒙开发中,应用上下文Context是一个很重要的知识点,特此整理下加深印象

二、概念

Context是应用的核心上下文对象,提供基础信息与能力。

2.1 核心理解 -

身份凭证:标识应用身份信息(包名、版本、权限等)

能力入口:提供访问系统服务和资源的统一接口

通信桥梁:连接应用内部组件与外部系统

2.2 类型体系

Context
├── ApplicationContext (应用级上下文)
├── UIAbilityContext (UIAbility上下文)
├── ExtensionContext (扩展能力上下文)
└── FormExtensionContext (卡片上下文)

2.3 持有关系

- 每个UIAbility实例持有自己的UIAbilityContext

- ApplicationContext由整个应用共享

- 组件通过getContext()获取所属Ability的上下文

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

不同类型Context的持有关系如下:

三、为什么需要 Context

3.1、解决的核心问题

在没有Context的情况下,面临的问题

问题 解决前 解决后
资源访问混乱 每个组件自行管理资源,容易冲突 统一资源管理,安全隔离
组件通信困难 组件间直接依赖,耦合度高 通过Context解耦,标准化通信
权限管理分散 权限检查逻辑重复,安全性差 集中权限管理,安全可控
生命周期复杂 各组件自行管理状态,难以维护 统一生命周期管理

简言之,主要是为了简化数据共享和系统交互

四、Context 的主要作用

作用类别 具体功能
资源管理 获取 ResourceManager、访问应用资源
组件启动 启动 Ability、Service、DataAbility
文件操作 获取应用文件目录、缓存目录
权限管理 权限申请和验证
系统服务 访问窗口管理、通知服务等
配置信息 获取应用包名、版本信息等

五、Context使用场景

场景1、资源管理能力

5.1.1、同步获取格式化字符串

解决的问题:

  • 字符串格式化:处理带占位符的字符串资源(如:"欢迎%s,今天是第%d天")

  • 同步执行:在需要立即获取字符串值的场景使用

  • 类型安全:参数类型明确为 string | number

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

export function getStringFromResourceSync(resource: Resource, ...args: Array<string | number>): string {
  const context = getContext() as common.UIAbilityContext;
  return context.resourceManager.getStringSync(resource.id, ...args)
}

使用场景:

import { getStringFromResourceSync } from '../view/utils'

@Entry
@Component
struct Index {
  build() {
    // 资源定义:app.string.welcome_message = "欢迎%s,您是第%d位访客"
    Text(getStringFromResourceSync($r('app.string.welcome_message'), '张三', 5))
    // 结果: "欢迎张三,您是第5位访客"
  }
}

5.1.2、同步获取普通字符串

解决的问题:

  • 简单字符串访问:不需要格式化的普通字符串资源

  • 零延迟获取:同步调用,立即返回值

  • 错误传播:如果资源不存在会直接抛出异常

export function getStringResourceSync(resource: Resource) {
  const context = getContext() as common.UIAbilityContext;
  return context.resourceManager.getStringSync(resource)
}

使用场景:

import { getStringResourceSync } from '../view/utils'
import { router } from '@kit.ArkUI'

@Entry
@Component
struct Index {
  build() {
    Column({ space: 20 }) {
      Button('点击')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/mine',
            params: {
              key: getStringResourceSync($r('app.string.scroll_open_accurate_search'))
            }
          })
        })
    }
  }
}

说明:

此处是将 Resource 对象转换为实际的 string 值,在需要传递字符串值的场景(路由、API、配置等)中必不可少

场景二、组件启动与管理

// 启动其他Ability
let want: Want = {
  bundleName: 'com.example.app',
  abilityName: 'DetailAbility',
  parameters: { id: 123 }
};
await context.startAbility(want);

// 启动服务
await context.startServiceExtensionAbility(want);

场景三、权限管理

具体能力:

  • 权限申请abilityAccessCtrl.AtManager.requestPermissionsFromUser()

  • 上下文获取:通过UI组件的上下文获取UIAbilityContext

  • 用户交互:显示系统原生的权限申请对话框

前提:在 module.json5 中进行权限声明

动态申请权限:

import { abilityAccessCtrl, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit'
import { BusinessError } from '@kit.BasicServicesKit'

@Entry
@Component
struct Index {
  build() {
    Column({ space: 20 }) {
      Button('点击获取位置权限')
        .onClick(() => {
          this.goPermission()
        })
    }
  }

  goPermission() {
    // 位置权限申请
    const locationPermissions: Array<Permissions> = [
      'ohos.permission.APPROXIMATELY_LOCATION',
      'ohos.permission.LOCATION',
    ];
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    atManager.requestPermissionsFromUser(context, locationPermissions,
      (err: BusinessError, data: PermissionRequestResult) => {
        if (err) {
          console.error(`requestPermissionsFromUser fail, code: ${err.code}, message: ${err.message}`);
        } else {
          console.info(`requestPermissionsFromUser success, result: ${data}`);
          console.info('requestPermissionsFromUser data permissions:' + data.permissions);
          console.info('requestPermissionsFromUser data authResults:' + data.authResults);
          console.info('requestPermissionsFromUser data dialogShownResults:' + data.dialogShownResults);
        }
      })
  }
}

场景四、系统服务访问

在窗口设置沉浸式页面

使用Window.setWindowLayoutFullScreen()方法设置窗口为全屏模式。

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';


export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    // 1.Get the main window of the application.
    let windowClass: window.Window | undefined = undefined;
    windowStage.getMainWindow().then(windowClass => {
      console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(windowClass));
      // 2.Set the window to full screen to achieve immersive effects.
      windowClass.setWindowLayoutFullScreen(true).then(() => {
        console.info('Succeeded in setting the window layout to full-screen mode.');
      }).catch((e: BusinessError) => {
        console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(e));
      })
    }).catch((err: BusinessError) => {
      console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
    })
    // 3.Load the corresponding target page for the immersive window.
    windowStage.loadContent("pages/Index", (err) => {
      if (err.code) {
        console.error('Failed to load the content. Cause:' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in loading the content.');
    });
  }
};

场景五、事件通信

@Entry
@Component
struct Index {
  aboutToDisappear(): void {
    //组件销毁时取消事件订阅
    getContext().eventHub.off('dataUpdate')
  }

  build() {
    Column({ space: 20 }) {
      Button('点击')
        .onClick(() => {
          //发送事件
          getContext().eventHub.emit('dataUpdate', (data: string) => {
            console.log('收到数据更新:', data);
          });
        })
    }
  }
}

六、Context 解决的问题

6.1、架构层面

通过Context实现组件间安全通信

统一资源调度,避免冲突

标准化组件生命周期

6.2、开发效率与安全上

通用能力封装,减少重复代码

安全数据共享机制

组件访问权限验证

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐