OpenHarmony API 9 升级到 API 10 权限与接口变更实战指南

✅ 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.jsonmodule.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"
      }
    }
  ]
}

关键变更点总结

  • reqPermissionsrequestPermissions
  • abilityabilities(必须是数组,即使只有一个)
  • 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 检查 abilitieswhen
后台定位不生效 缺少 LOCATION_IN_BACKGROUND 权限或未在后台服务中注册 module.json5 中添加并验证
LocationManager 启动失败 未申请权限或设备未开启定位开关 提前判断 isLocationEnabled()
应用被拒上线 未填写合理的 reason 描述或滥用权限 保证 reason 与功能强相关,避免"获取位置以提升体验"等模糊描述

六、最佳实践总结

✅升级流程步骤

必做清单

  1. ✅ 更新 module.json5,将 reqPermissions 改为 requestPermissions
  2. ✅ 所有权限绑定具体 abilities 数组,禁止全局声明;
  3. ✅ 使用 this.context 作为 requestPermissionsFromUser() 的上下文;
  4. ✅ 申请 LOCATION_IN_BACKGROUND 时,需在 module.json5 中明确说明用途;
  5. ✅ 使用 LocationManager 类实例化方式启动定位;
  6. ✅ 对每个权限申请结果进行处理,引导用户前往设置页;
  7. ✅ 添加权限状态检测逻辑,避免无效调用;
  8. ✅ 提供清晰的权限说明文案(reason),增强用户信任。

七、附录:权限对照表(快速参考)

权限 是否需要 module.json5 是否需动态申请 是否可后台使用
ohos.permission.APPROXIMATELY_LOCATION
ohos.permission.LOCATION
ohos.permission.LOCATION_IN_BACKGROUND

💡 提示:LOCATION_IN_BACKGROUND 会触发更高安全审查,请确保业务真实必要。


🎯 结语

本次升级不仅是接口变更,更是对用户隐私权尊重的体现。遵循本指南,不仅能顺利通过审核,还能提升用户体验与信任度。

📘 推荐文档


立即行动建议

  1. 检查项目中所有 config.json → 替换为 module.json5
  2. 逐个替换 requestPermissionsFromUser 调用
  3. 重写 LocationManager 初始化逻辑
  4. 测试各权限申请流程与后台定位行为

🚀 升级完成,发布无忧!

相关推荐
zjeweler2 小时前
云服务器centos7.6搭建个人网站教程
运维·服务器
liyunlong-java2 小时前
单服务器 MySQL 主从同步部署教程(宝塔 + MySQL 8.0)
服务器·mysql·adb
橙子也要努力变强2 小时前
信号捕捉的底层机制-内核态和用户态初识
linux·服务器·c++
枫叶丹42 小时前
【HarmonyOS 6.0】ArkWeb新特性:PDF加载成功/失败回调及滚动到底部监听
华为·pdf·harmonyos
j_xxx404_2 小时前
Linux C 语言编译链接全解析:静态库与动态库从原理到实战
linux·运维·服务器·c语言·编辑器
wanhengidc2 小时前
云手机 云端运行托管
运维·服务器·网络·安全·web安全·智能手机
橙子也要努力变强2 小时前
信号捕捉底层机制-进程与OS
linux·服务器·c++
南村群童欺我老无力.2 小时前
鸿蒙 - Progress进度条从手工拼装到原生组件的重构
华为·重构·harmonyos
埃伊蟹黄面2 小时前
网络层 IP 协议
服务器·网络·tcp/ip