探秘鸿蒙 HarmonyOS NEXT:权限申请策略指南
鸿蒙 ArkTS 语言中 abilityAccessCtrl.createAtManager() 申请权限解析
1. 概述
本文章基于HarmonyOS NEXT操作系统,API12以上的版本。
在鸿蒙 HarmonyOS NEXT 系统中,abilityAccessCtrl.createAtManager()
提供了一种更细粒度的权限管理方式,用于程序访问控制提供程序的权限管理能力,包括鉴权、授权等,(App Trust List,简称 ATManager),即访问控制管理:获取访问控制模块对象。
1.1 ATManager 权限管理机制
在HarmonyOS开发中,应用访问如相机、麦克风、位置、图库等系统资源或系统能力时,需通过授权使用等方式来访问,以确保用户隐私安全。
1.2 ATManager 主要用途
ATManager 主要用于:
- 动态管理应用权限,如特定应用间的访问控制。
- 基于可信列表进行权限验证,确保只有受信任的应用能够访问特定资源。
- 适用于系统级或高级安全需求,例如控制某些 API 调用是否允许特定应用执行。
2. 使用方式
2.1 权限申请时机
为了应用能够发挥其完整功能,可能需要访问系统的特定资源,而这些资源的访问通常需要获得相应的权限许可。在应用进行权限申请时,选择合适的权限申请时机是提升用户体验和保护用户隐私安全的关键。主要可分为两点:
按需请求权限
- 核心原则:应用应遵循“最小权限原则”,即仅申请应用实际需要使用到的权限。
- 实施策略:将权限请求与应用内的具体功能场景紧密结合。应避免在应用首次启动时,立即请求了大量权限,应在用户实际用到某项功能,而该功能又依赖于特定权限时,再向用户请求相应的权限。以示例代码为例,当用户点击“获取当前位置”按钮时,触发查看位置相关信息的场景,此时弹出请求位置权限的弹框。
尊重用户选择,避免强制请求
- 核心原则:应尊重用户的选择权,不应强制用户授予权限。
- 实施策略:若用户拒绝了某项权限申请,应用应避免二次弹框申请该权限,应该在页面内的合适位置添加清晰的提示语,引导用户开启权限或退出当前需要该权限的场景,直至用户再次触发时再引导用户进行授权。
2.2 系统弹框一般有三种操作
- 仅使用期间允许:点击后应用直接获取该权限,且再次调用
requestPermissionsFromUser()
方法无法拉起该权限设置弹框; - 本次使用允许:点击后将会对应用授予临时的权限,向用户申请单次授权;若临时权限被取消,再次调用
requestPermissionsFromUser()
方法将会拉起该权限设置弹框; - 不允许:点击后应用无法获取该权限,且再次调用
requestPermissionsFromUser()
方法无法拉起该权限设置弹框。那就需要调用requestPermissionOnSetting()
方法直接拉起权限设置弹框,引导用户授予权限。
2.3 具体流程
3. API 介绍
abilityAccessCtrl.createAtManager()
返回一个 ATManager 实例,用于管理应用权限。
API 方法 | 说明 |
---|---|
createAtManager() | 创建 ATManager 实例 |
checkAccessTokenSync(tokenID: number, permissionName: Permissions): GrantStatus | 校验应用是否被授予权限,同步返回结果 |
requestPermissionsFromUser(context: Context, permissionList: Array<Permissions>):Promise<PermissionRequestResult> | 用于UIAbility/UIExtensionAbility拉起弹框请求用户授权。使用promise异步回调 |
requestPermissionOnSetting(context: Context, permissionList: Array<Permissions>): Promise<Array<GrantStatus>> | 用于UIAbility/UIExtensionAbility二次拉起权限设置弹框 |
4. 权限申请示例
4.1 创建 ATManager 并校验是否已经授权
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
/**
* 校验是否已经授权
*/
private static checkAccessToken(permission: Permissions): abilityAccessCtrl.GrantStatus {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
let grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED
let tokenId: number = 0
try {
let bundleInfo: bundleManager.BundleInfo = bundleManager.getBundleInfoForSelfSync(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
)
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo
tokenId = appInfo.accessTokenId
} catch (error) {
console.error(TAG, "failed to get tokenId ,message = " + JSON.stringify(error))
}
//校验应用是否被授权
try {
grantStatus = atManager.checkAccessTokenSync(tokenId, permission)
} catch (error) {
console.error(TAG, "error = " + JSON.stringify(error))
}
return grantStatus
}
4.2 创建 ATManager 请求授权权限
/**
* 向用户请求授权
*/
async requestPermission(
context: common.UIAbilityContext,
permissions: Array<Permissions>
): Promise<PermissionResult> {
let deniedArr: Array<Permissions> = permissions
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
let permissionResult: PermissionRequestResult =
await atManager.requestPermissionsFromUser(context, deniedArr)
permissionResult.authResults.forEach((authResult, index) => {
if (authResult === 0) {
//授权成功,从未授权数组中删除
deniedArr.splice(index, 1)
}
})
if (deniedArr.length === 0) {
//全部授权成功
return {
granted: true,
deniedArr: deniedArr
}
} else {
//部分授权失败
return {
granted: false,
deniedArr: deniedArr
}
}
}
4.3 用户拒绝授权后,直接拉起权限设置弹框,引导用户授予权限
/**
* 用户拒绝授权后,直接拉起权限设置弹框,引导用户授予权限
*/
async requestPermissionOnSetting(
context: common.UIAbilityContext,
permissions: Array<Permissions>
): Promise<PermissionResult> {
let deniedArr: Array<Permissions> = permissions
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
let grantStatus: abilityAccessCtrl.GrantStatus[] =
await atManager.requestPermissionOnSetting(context, permissions)
grantStatus.forEach((status, index) => {
if (status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
//授权成功,从未授权数组中删除
deniedArr.splice(index, 1)
}
})
return {
granted: deniedArr.length === 0,
deniedArr: deniedArr
}
}
4.4 在系统设置中打开App信息页
/**
* 在系统设置中打开App信息页
*/
static openSystemSettings(context: common.UIAbilityContext) {
let wantInfo: Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
pushParams: context.applicationInfo.name // 打开指定应用的详情页面 bundleId
}
}
context.startAbility(wantInfo).then(() => {
}).catch((err: BusinessError) => {
console.error(TAG, "startAbility failed, error = " + err.message)
})
}
5. 总结
本文详细阐述了 HarmonyOS NEXT 操作系统中申请权限的机制,为开发者梳理出一套清晰的基本流程,并附上相关代码示例,助力开发者深入理解并高效实现申请权限功能。希望本文能成为开发者在鸿蒙开发过程中的得力助手,顺利攻克权限申请这一关键环节。