HarmonyOS权限管理

837 阅读4分钟

先了解应用权限的基本概念,知道:权限级别授权方式

在鸿蒙开发中,调用部分 API 时需要申请权限后,才能调用,如:网络请求,获取网络信息等。 部分 API 调用的时候还会弹窗,如:麦克风(录音)、日历。

通知授权比较特殊,申请通知授权

申请应用权限时,需要注意两个关键信息:1. 权限级别 2. 授权方式

权限级别

系统根据应用的APL等级设置进程域和数据域标签,并通过访问控制机制限制应用可访问的数据范围,从而实现在机制上消减应用数据泄露的风险 查看对所有应用开放的权限

应用APL等级

(Ability Privilege Level,元能力权限等级)应用的 APL 等级可以分为以下三个等级,等级依次提高。

APL级别说明大白话
normal默认情况下,应用的APL等级都为normal等级。都能用
system_basic该等级的应用服务提供系统基础服务。要签名证书
system_core该等级的应用服务提供操作系统核心能力。仅对系统应用开放不开放

授权方式概述

根据授权方式的不同,权限类型可分为 system_grant(系统授权) 和 user_grant(用户授权)。 例如 网络权限是系统授权,在应用中配置即可;日历、相机、麦克风等为用户授权,在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。

应用权限列表
  • 对所有应用开放的权限(normal) - 都能用
  • 允许ACL跨级别申请权限(system_basic) - 要签名证书
申请目标权限流程图

75a03671d81cc96032e5b6da416cc51e.jpeg

申请 user_grant 用户授权

以日历权限举例,相机、麦克风、位置的权限同理。参考文档

1. 配置声明权限

在 module.json5 中添加权限说明

{
  "module": {
  //...
    "requestPermissions":[{
        {
          //日历权限  读
          "name": "ohos.permission.READ_CALENDAR",
          "reason": "$string:permission_reason_calendar",
          "usedScene": {}
        },
        {
          //日历权限  写
          "name": "ohos.permission.WRITE_CALENDAR",
          "reason": "$string:permission_reason_calendar",
          "usedScene": {}
        }
    }] 
  }
}
2.检查当前是否已授权

在进行权限申请之前,通常先检查当前应用程序是否已经被授予权限。

核心API:atManager.checkAccessTokenSync(tokenID, 权限名称)

/**
 * 检查是否授权
 * @param permissions 权限列表
 * @returns 返回授权结果
 */
checkPermissions(permissions: Permissions[]) {
  // 1. 创建应用权限管理器
  const atManager = abilityAccessCtrl.createAtManager()
  // 2. 获取 bundle 包信息,Sync 写法
  const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
  // 3. 提取 tokenID
  const tokenID = bundleInfo.appInfo.accessTokenId
  // 4. 检测是否授权,Sync 写法,升级成遍历权限组(数组)!!!
  const grantStatus = permissions.map(item => atManager.checkAccessTokenSync(tokenID, item))
  // 返回权限数组的检测结果
  return grantStatus.every(v => v === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
  // 温馨提示:当前函数没有用到 Promise,都是用 Sync 函数,好处:可直接再组件渲染权限检测结果
}
3. 动态向用户申请授权(弹窗)

动态向用户申请权限是指在应用程序运行时向用户请求授权的过程。

核心API:atManager.requestPermissionsFromUser()

/**
 * 动态申请授权(首次弹窗申请)
 * @param permissions 权限列表
 * @returns 返回授权结果,授权成功为 Promise.resolve(), 拒绝授权为 Promise.reject()
 */
async requestPermissions(permissions: Permissions[]) {
  // 1. 创建应用权限管理器
  const atManager = abilityAccessCtrl.createAtManager()
  // 2. 向用户申请 user_grant 权限(温馨提示:首次申请时会弹窗,后续申请则不会再出现弹窗)
  const requestResult = await atManager.requestPermissionsFromUser(
    getContext(), // 应用上下文
    permissions   // 参数:权限列表(数组)
  )
  // 通过 every 检查权限是否都成功授权
  const isAuth = requestResult.authResults.every(item => item === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
  return isAuth === true ? Promise.resolve(true) : Promise.reject(false)
}
4. 处理授权结果

弹窗申请授权之后,如果用户拒绝授权,因为弹窗的一次性,下次如需授权可引导用户打开系统设置页

/**
 * 打开系统设置的权限管理页(处理授权结果)
 */
openPermissionSettingsPage() {
  // 1. 获取应用上下文,并通过 as 断言收窄类型为 UIAbilityContext,否则 context 默认类型无法调用 startAbility 方法
  const context = getContext() as common.UIAbilityContext
  // 2. 获取 bundle 包信息
  const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
  // 3. 通过 startAbility 打开 系统设置 页
  context.startAbility({
    bundleName: 'com.huawei.hmos.settings', // 设置页的包名
    abilityName: 'com.huawei.hmos.settings.MainAbility', // 设置页的 ability 名
    uri: 'application_info_entry', // 打开 设置->应用和元服务
    parameters: {
      // 打开指定应用(包)的详情页面
      // pushParams: 'com.itheima.hm_guardian'
      // 应用包名可通过 bundleManager 动态获取
      pushParams: bundleInfo.name
    }
  })
}
5. 跨级别申请权限

权限等级应用APL等级是一一对应的。原则上,拥有低APL等级的应用默认无法申请更高等级的权限。访问控制列表ACL(Access Control List)提供了解决低等级应用访问高等级权限问题的特殊渠道。

从 DevEco Studio 4.0 Release 版本起,支持在调测阶段自动签名快速申请ACL权限

  1. 确保已连接真机或模拟器
  2. 登录华为帐号后,勾选“Automatically generate signature”,即可完成签名
  3. 在 module.json5 中添加权限说明
  4. ....