✅ OpenHarmony API 9 升级到 API 10 权限与接口变更实战指南
📌 适用版本:
API 9 → API 10🎯 目标:确保应用在新系统中正常运行,符合隐私合规要求,避免崩溃或被拒上线。
一、权限变更详解
🔹 1. 新增权限:更细粒度的位置权限控制
为加强用户隐私保护,OpenHarmony API 10 引入了分场景、分精度、分使用时机的精细化权限模型:
| 权限名称 | 用途说明 | 使用场景 |
|---|---|---|
ohos.permission.APPROXIMATELY_LOCATION |
仅获取近似位置(如城市/区域级别) | 地图默认显示、天气预报、本地推荐 |
ohos.permission.LOCATION |
获取精确位置(街道级) | 导航、打车、签到、实景搜索 |
ohos.permission.LOCATION_IN_BACKGROUND |
后台持续定位权限(需额外审批) | 跑步记录、车载导航、远程追踪 |
⚠️ 重要提示:
- 不再支持单一
ohos.permission.LOCATION覆盖所有场景。- 若申请
LOCATION_IN_BACKGROUND,必须在module.json5中明确声明"后台使用"场景,并通过审核。- 用户首次授权后,若后续拒绝,需引导用户手动开启(不可强制弹窗)。
二、配置文件更新:从 config.json 到 module.json5
❌ API 9 旧写法(已弃用)
json
{
"reqPermissions": [
{
"name": "ohos.permission.LOCATION",
"reason": "获取定位服务",
"usedScene": {
"ability": ["MainAbility"],
"when": "always"
}
}
]
}
✅ API 10 正确写法(module.json5 必须使用)
json
{
"requestPermissions": [
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "获取近似位置以提供周边服务",
"usedScene": {
"abilities": ["EntryAbility"], // ✅ 复数形式!
"when": "inuse" // ✅ 只允许 "inuse" 或 "always"
}
},
{
"name": "ohos.permission.LOCATION",
"reason": "精确获取当前位置用于导航",
"usedScene": {
"abilities": ["MapAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION_IN_BACKGROUND",
"reason": "后台持续定位用于运动轨迹记录",
"usedScene": {
"abilities": ["LocationServiceAbility"],
"when": "inuse"
}
}
]
}
✅ 关键变更点总结:
reqPermissions→requestPermissionsability→abilities(必须是数组,即使只有一个)when字段仅支持"inuse"(前台使用)、"always"(始终可用)- 所有权限必须绑定具体
Ability,不能全局声明 - 不再支持
when: "onDemand"等非标准值
🛠️ 工具建议 :使用 DevEco Studio 3.7+ 自动校验
module.json5格式,可实时提示错误。
三、动态权限申请流程升级(重点!)
❌ 错误示例(API 9 风格,无法在 API 10 运行)
ts
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
const atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(['ohos.permission.LOCATION'])
.then(() => console.log('授权成功'))
.catch(err => console.error('授权失败:', err));
❌ 问题分析:
createAtManager()不再推荐,且未关联上下文。requestPermissionsFromUser()已废弃,应改用requestPermissionsFromUser基于context的方式。
✅ 正确方式(推荐使用 UIAbility.context 获取上下文)
✅ 示例:在 EntryAbility 中申请前台定位权限
ts
// entryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { Context } from '@ohos.app.ability.Context';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
// 1. 获取当前上下文
const context: Context = this.context;
// 2. 创建权限管理器实例
const atManager = abilityAccessCtrl.createAtManager();
// 3. 申请单个权限(精确位置)
const permissions = ['ohos.permission.LOCATION'];
// 4. 动态申请(注意:必须通过 context)
atManager.requestPermissionsFromUser(context, permissions)
.then((result) => {
if (result[0] === true) {
console.info('✅ 用户已授权精确位置');
this.startLocationService();
} else {
console.warn('❌ 用户拒绝授权,请引导设置');
this.showPermissionGuideDialog();
}
})
.catch((err) => {
console.error('⛔ 权限申请失败:', err);
});
}
// 4. 引导用户去设置页开启权限
showPermissionGuideDialog() {
// 可使用 Dialog 组件或跳转系统设置页
this.context.startActivity({
action: 'android.settings.APPLICATION_DETAILS_SETTINGS',
uri: 'package:' + this.context.getPackageName()
});
}
// 5. 启动后台定位服务(需提前申请后台权限)
startLocationService() {
// 仅当已获得 LOCATION_IN_BACKGROUND 权限时才启动
console.info('🚀 启动后台定位服务...');
}
}
✅ 关键要点:
- 必须通过
this.context传入上下文。- 不能直接调用
abilityAccessCtrl.createAtManager()而不带参数。- 推荐封装成工具函数,便于复用。
🧩 封装通用权限请求工具类(推荐)
ts
// utils/PermissionHelper.ts
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { Context } from '@ohos.app.ability.Context';
export class PermissionHelper {
static async requestPermission(context: Context, permission: string): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(context, [permission]);
return result[0] === true;
} catch (error) {
console.error('权限申请异常:', error);
return false;
}
}
// 批量申请
static async requestMultiplePermissions(context: Context, permissions: string[]): Promise<boolean[]> {
const atManager = abilityAccessCtrl.createAtManager();
try {
const results = await atManager.requestPermissionsFromUser(context, permissions);
return results;
} catch (error) {
console.error('批量权限申请失败:', error);
return permissions.map(() => false);
}
}
}
// 使用示例
await PermissionHelper.requestPermission(this.context, 'ohos.permission.LOCATION');
四、地理位置接口重构(重点!)
❌ 旧接口(API 9)已废弃
ts
import location from '@ohos.location';
const locationManager = location.getLocationManager();
locationManager.on('locationChange', (locationData) => {
console.log('位置更新:', locationData.latitude, locationData.longitude);
});
✅ 新接口(API 10):使用 @ohos.location.LocationManager
ts
import LocationManager from '@ohos.location.LocationManager';
let locationManager: LocationManager;
export function initLocation() {
try {
locationManager = new LocationManager();
// 1. 设置定位参数
const options = {
interval: 5000, // 每5秒更新一次
minDistance: 10, // 最小距离变化(米)
enableGps: true,
enableNetwork: true,
priority: 'high_accuracy' // 高精度模式
};
// 2. 开始定位
locationManager.startLocation(options)
.then(() => {
console.info('✅ 定位已启动');
registerLocationCallback();
})
.catch((err) => {
console.error('定位启动失败:', err);
handleLocationError(err);
});
} catch (e) {
console.error('初始化定位失败:', e);
}
}
function registerLocationCallback() {
locationManager.on('locationChange', (locationData) => {
console.log('📍 当前位置:', locationData.latitude, locationData.longitude);
// 处理位置数据
});
locationManager.on('locationError', (error) => {
console.warn('📍 定位错误:', error.code, error.message);
});
}
// 停止定位
export function stopLocation() {
if (locationManager) {
locationManager.stopLocation().catch(err => console.error('停止定位失败:', err));
}
}
✅ 新特性:
LocationManager是类实例化对象,不再静态调用。支持
startLocation(options)+stopLocation()显式控制生命周期。
on('locationChange')回调仍保留,但必须先startLocation。
⚠️ 注意事项:必须在
Ability上下文中调用initLocation(),否则可能因无权限而失败。启动前请务必检查是否已获得
LOCATION权限!
五、常见坑点 & 避坑建议
| 问题 | 原因 | 解决方案 |
|---|---|---|
requestPermissionsFromUser 报错"context is null" |
未正确传递 this.context |
一定要用 this.context 作为参数 |
权限申请总是返回 false |
未在 module.json5 中正确定义 usedScene |
检查 abilities 和 when 值 |
| 后台定位不生效 | 缺少 LOCATION_IN_BACKGROUND 权限或未在后台服务中注册 |
在 module.json5 中添加并验证 |
LocationManager 启动失败 |
未申请权限或设备未开启定位开关 | 提前判断 isLocationEnabled() |
| 应用被拒上线 | 未填写合理的 reason 描述或滥用权限 |
保证 reason 与功能强相关,避免"获取位置以提升体验"等模糊描述 |
六、最佳实践总结
✅升级流程步骤

✅ 必做清单:
- ✅ 更新
module.json5,将reqPermissions改为requestPermissions; - ✅ 所有权限绑定具体
abilities数组,禁止全局声明; - ✅ 使用
this.context作为requestPermissionsFromUser()的上下文; - ✅ 申请
LOCATION_IN_BACKGROUND时,需在module.json5中明确说明用途; - ✅ 使用
LocationManager类实例化方式启动定位; - ✅ 对每个权限申请结果进行处理,引导用户前往设置页;
- ✅ 添加权限状态检测逻辑,避免无效调用;
- ✅ 提供清晰的权限说明文案(
reason),增强用户信任。
七、附录:权限对照表(快速参考)
| 权限 | 是否需要 module.json5 |
是否需动态申请 | 是否可后台使用 |
|---|---|---|---|
ohos.permission.APPROXIMATELY_LOCATION |
✅ | ✅ | ❌ |
ohos.permission.LOCATION |
✅ | ✅ | ❌ |
ohos.permission.LOCATION_IN_BACKGROUND |
✅ | ✅ | ✅ |
💡 提示:
LOCATION_IN_BACKGROUND会触发更高安全审查,请确保业务真实必要。
🎯 结语 :
本次升级不仅是接口变更,更是对用户隐私权尊重的体现。遵循本指南,不仅能顺利通过审核,还能提升用户体验与信任度。
📘 推荐文档:
✅ 立即行动建议:
- 检查项目中所有
config.json→ 替换为module.json5 - 逐个替换
requestPermissionsFromUser调用 - 重写
LocationManager初始化逻辑 - 测试各权限申请流程与后台定位行为
🚀 升级完成,发布无忧!