OpenHarmony API8升API9:权限与接口变更实战指南
功能模块API8 (旧版)API9 (新版)核心变更点Context 获取(在 Ability 内部)摆脱对的依赖,使用原生生命周期属性。权限管理结合使用结合实例使用接口调用更加面向对象,参数传递更规范。全局变量依赖模块单例推荐使用GlobalThis解决跨模块 Context 丢失和单例失效问题。媒体库旧版接口等接口重构,初始化强依赖 Context。通过以上步骤和代码示例,即使是初学者也能清晰
OpenHarmony API8 升级到 API9 权限与接口修改详解
问题解构
OpenHarmony 从 API8 升级到 API9 是一个重要的版本跨越,涉及到底层运行机制和开发框架的调整。对于初学者而言,核心的痛点主要集中在以下三个维度的变更:
- Context(上下文)获取方式的变更:权限申请等系统级操作不再依赖旧的 Ability 获取方式。
- 系统权限申请参数的调整:申请权限时的接口调用方法发生了改变。
- 媒体库初始化接口的迭代:图片、视频等多媒体资源的初始化逻辑需要重写。
- 全局变量存储机制的演进:单例模式在特定场景下失效,需要引入新的全局存储方案。
以下将结合具体代码和场景,详细解析这些变更。
方案推演与代码详解
1. Context 获取方式的变更
在 API8 中,开发者习惯使用 featureAbility 模块来获取 Context,进而申请权限。但在 API9 中,推荐直接在 EntryAbility(主入口)中获取 Context,并将其传递或存储起来供全局使用。
API8 写法(旧版):
通常通过导入 featureAbility 直接获取上下文。
// API8 示例代码
import featureAbility from '@ohos.ability.featureAbility';
// 获取当前 Ability 的 Context
let context = featureAbility.getContext();
API9 写法(新版):
在 MainAbility 或 EntryAbility 的 onCreate 生命周期中,直接使用 this.context。
// API9 示例代码 (EntryAbility.ets)
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 1. 直接获取 Context
let context = this.context;
// 2. 建议将此 context 存入 GlobalThis 以便在其他页面访问
// 关于 GlobalThis 的使用详见下文第 3 点
globalThis.context = context;
console.info('[EntryAbility] onCreate Context obtained.');
}
// ... 其他生命周期方法
}
2. 系统权限申请接口修改
权限申请是应用开发中的高频操作。在升级过程中,不仅获取 Context 的方式变了,调用权限验证的接口逻辑也有所调整。
场景分析:
假设我们需要申请读取存储的权限(例如 ohos.permission.READ_IMAGEVIDEO,具体权限名需根据实际配置文件 module.json5 确定)。
API8 写法(旧版):
使用 verifyAccessToken 接口,通常结合 featureAbility 获取的 Context 使用。
// API8 权限验证示例
import featureAbility from '@ohos.ability.featureAbility';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
let context = featureAbility.getContext();
let manager = abilityAccessCtrl.createAtContext();
// 验证权限
manager.verifyAccessToken(context.applicationInfo.accessTokenId, "ohos.permission.READ_IMAGEVIDEO")
.then((data) => {
if (data === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
console.log('API8: 权限已授予');
}
});
API9 写法(新版):
API9 中,abilityAccessCtrl 的使用方式更加规范,通常通过实例来管理权限状态,且 Context 的传递更加明确。
// API9 权限验证示例
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';
// 假设我们已经通过 globalThis.context 获取了上下文
let context = globalThis.context as common.UIAbilityContext;
let atManager = abilityAccessCtrl.createAtContext();
// 验证权限
atManager.verifyAccessToken(context.applicationInfo.accessTokenId, 'ohos.permission.READ_IMAGEVIDEO')
.then((grantStatus: number) => {
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
console.info('API9: 权限已授予');
} else {
console.error('API9: 权限未授予');
}
})
.catch((err: BusinessError) => {
console.error(`API9: 验证权限失败, code: ${err.code}, message: ${err.message}`);
});
3. 全局变量存储与单例失效问题
在 API8 升级到 API9 的过程中,很多开发者反馈原有的单例模式失效,或者在非 UI 页面(如公共工具类)中无法获取到 Context。这是因为模块加载机制或实例化时机发生了变化。
解决方案:利用 GlobalThisGlobalThis 是一个全局对象,其特性是在应用生命周期内属性保持不变。利用它可以存储 Context 或其他全局单例对象,从而解决跨模块访问的问题 。
代码示例:
首先,在 EntryAbility.ets 中进行初始化存储:
// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 将 Context 存入 GlobalThis
globalThis.abilityContext = this.context;
// 也可以存储其他全局单例对象
globalThis.globalDataManager = new GlobalDataManager();
}
}
然后,在任意页面(例如 Index.ets)或工具类中读取:
// Index.ets 或其他工具类文件
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
// 定义一个类来测试全局访问
class GlobalDataManager {
data: string = "我是全局单例数据";
}
export struct Index {
aboutToAppear() {
// 1. 从 GlobalThis 获取 Context
let context = globalThis.abilityContext;
if (context) {
console.info('成功获取到全局 Context');
// 在这里可以使用 context 进行权限申请等操作
} else {
console.error('获取 Context 失败,请检查 EntryAbility 中的赋值');
}
// 2. 从 GlobalThis 获取业务单例对象
let manager = globalThis.globalDataManager as GlobalDataManager;
console.info(manager.data);
}
build() {
// UI 渲染代码
}
}
4. 媒体库接口初始化修改
如果应用涉及图片或视频处理,媒体库的初始化接口在 API9 中也有显著变化,通常需要传入正确的 Context。
API8 -> API9 变更要点:
- API8 中可能使用旧的
media库接口。 - API9 中推荐使用
@ohos.file.photoAccessHelper等新接口,且初始化时必须传入 Context。
代码示例:
// API9 媒体库辅助类初始化示例
import photoAccessHelper from '@ohos.file.photoAccessHelper';
class MediaManager {
// 初始化方法
static init() {
// 必须传入从 GlobalThis 获取的 Context
let context = globalThis.abilityContext;
if (!context) {
console.error("MediaManager init failed: Context is null");
return;
}
try {
// 使用 Context 获取媒体资源示例(此处仅展示接口依赖 Context)
let helper = photoAccessHelper.getPhotoAccessHelper(context);
// 后续可以使用 helper 进行图片查询等操作
console.info('媒体库初始化成功');
} catch (err) {
console.error(`媒体库初始化失败: ${JSON.stringify(err)}`);
}
}
}
总结对比表
下表总结了从 API8 迁移到 API9 的关键差异点:
| 功能模块 | API8 (旧版) | API9 (新版) | 核心变更点 |
|---|---|---|---|
| Context 获取 | featureAbility.getContext() |
this.context (在 Ability 内部) |
摆脱对 featureAbility 的依赖,使用原生生命周期属性 。 |
| 权限管理 | 结合 featureAbility 使用 |
结合 abilityAccessCtrl 实例使用 |
接口调用更加面向对象,参数传递更规范。 |
| 全局变量 | 依赖模块单例 | 推荐使用 GlobalThis |
解决跨模块 Context 丢失和单例失效问题 。 |
| 媒体库 | 旧版接口 | photoAccessHelper 等 |
接口重构,初始化强依赖 Context。 |
通过以上步骤和代码示例,即使是初学者也能清晰地理解 API8 升级到 API9 的核心逻辑。在升级过程中,务必检查官方接口文档,重点关注所有需要传入 Context 的地方,并将其替换为从 GlobalThis 或生命周期中获取的新 Context 。
更多推荐

所有评论(0)