先了解应用权限的基本概念,知道:权限级别、授权方式。
在鸿蒙开发中,调用部分 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) - 要签名证书
申请目标权限流程图
申请 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权限。
- 确保已连接真机或模拟器
- 登录华为帐号后,勾选“Automatically generate signature”,即可完成签名
- 在 module.json5 中添加权限说明
- ....