文章目录
官方文档地址: 应用权限管控概述-应用权限管控-程序访问控制-安全-系统 - 华为HarmonyOS开发者 (huawei.com)
1、权限等级划分
根据权限对于不同等级应用有不同的开放范围,权限类型对应分为以下三个等级,等级依次提高
APL级别 | 说明 | 开放范围 |
---|---|---|
normal | 允许应用访问超出默认规则外的普通系统资源,如配置Wi-Fi信息、调用相机拍摄等。 这些系统资源的开放(包括数据和功能)对用户隐私以及其他应用带来的风险低。 | APL等级为normal及以上的应用。 |
system_basic | 允许应用访问操作系统基础服务(系统提供或者预置的基础功能)相关的资源,如系统设置、身份认证等。 这些系统资源的开放对用户隐私以及其他应用带来的风险较高。 | - APL等级为system_basic及以上的应用。 - 部分权限对normal级别的应用受限开放,这部分权限在本指导中描述为"受限开放权限"。 |
system_core | 涉及开放操作系统核心资源的访问操作。这部分系统资源是系统最核心的底层服务,如果遭受破坏,操作系统将无法正常运行。 | - APL等级为system_core的应用。 - 仅对系统应用开放。 |
2、权限类型
根据授权方式的不同,权限类型可分为system_grant(系统授权)和user_grant(用户授权)
system_grant(系统授权)
system_grant指的是系统授权类型,在该类型的权限许可下,应用被允许访问的数据不会涉及到用户或设备的敏感信息,应用被允许执行的操作对系统或者其他应用产生的影响可控。
如果在应用中申请了system_grant权限,那么系统会在用户安装应用时,自动把相应权限授予给应用。
user_grant(用户授权)
user_grant指的是用户授权类型,在该类型的权限许可下,应用被允许访问的数据将会涉及到用户或设备的敏感信息,应用被允许执行的操作可能对系统或者其他应用产生严重的影响。
该类型权限不仅需要在安装包中申请权限,还需要在应用动态运行时,通过发送弹窗的方式请求用户授权。在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。
3、动态申请权限列表单
权限名称 | 权限级别 | 权限说明 |
---|---|---|
ohos.permission.ANSWER_CALL | system_basic | 允许应用接听来电 |
ohos.permission.READ_CALENDAR | system_basic | 允许应用读取日历信息 |
ohos.permission.READ_CALL_LOG | system_basic | 允许应用读取通话记录 |
ohos.permission.READ_CELL_MESSAGE | system_basic | 允许应用读取设备收到的广播信息 |
ohos.permission.READ_CONTACTS | system_basic | 允许应用读取联系人护具 |
ohos.permission.READ_MESSAGE | system_basic | 允许应用读取短信息 |
ohos.permission.RECEIVE_MMS | system_basic | 允许应用接受和处理彩信 |
ohos.permission.RECEIVE_SMS | system_basic | 允许应用接受和处理短信 |
ohos.permission.RECEIVE_WAP_MESSAGE | system_basic | 允许应用接收和处理Wap消息 |
ohos.permission.MICROPHONE | normal | 允许应用使用麦克风 |
ohos.permission.SEND_MESSAGE | system_basic | 允许应用发送短信 |
ohos.permission.WRITE_CALENDAR | normal | 允许应用添加、移除或者更改日历活动 |
ohos.permission.WRITE_CALL_LOG | system_basic | 允许应用添加、移除或更改通话记录 |
ohos.permission.WRITE_CONTACTS | system_basic | 允许应用添加、移除或者更改联系人数据 |
ohos.permission.DISTRIBUTED_DATASYNC | normal | 允许不同设备间的数据交换 |
ohos.permission.MANAGE_VOICEMAIL | system_basic | 允许应用在语音信箱中留言 |
ohos.permission.LOCAL_IN_BACKGROUND | normal | 允许应用在后台运行时获取设备位置信息 |
ohos.permission.LOCATION | normal | 允许应用获取设备位置信息 |
ohos.permission.APPROXIMATELY_LOCATION | normal | 允许应用获取设备模糊位置信息 |
ohos.permission.MEDIA_LOCATION | normal | 允许应用访问用户媒体文件中的地理位置信息 |
ohos.permission.CAMERA | normal | 允许应用使用相机拍摄照片和录制视频 |
ohos.permission.READ_MEDIA | normal | 允许应用读取用户外部存储中的媒体文件信息 |
ohos.permission.WRITE_MEDIA | normal | 允许应用读写用户外部存储中的媒体文件信息 |
ohos.permission.ACTIVITY_MOTION | normal | 允许应用读取用户当前的运动状态 |
ohos.permission.READ_HEALTH_DATA | normal | 允许应用读取用户的健康数据 |
4、访问控制开发步骤
如果应用需要获取目标权限,需要先进行权限申请。
- 权限申请:开发者需要在配置文件中声明目标权限。
- 权限授权:如果目标权限是system_grant类型,开发者在进行权限申请后,系统会在安装应用时为其进行权限授予,开发者不需要进行其他操作即可使用权限。如果目标权限是user_grant时,开发者在进行权限申请后,在运行时触发动态弹窗,请求用户授权。
4.1、权限申请
应用需要在工程配置文件中对需要的权限逐个神功,没有在配置文件中声明的权限,应用将无法获得授权。
plain
{
"module":{
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason":"$string:Permission_internet_reason",
"usedScene": {
"abilities": ["PermissionDemoAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.CAMERA",
"reason": "$string:Permission_camera_reason",
"usedScene": {
"abilities": ["PermissionDemoAbility"],
"when": "always"
}
}
]
}
}
name | 权限名称 |
---|---|
reason | 当申请权限为user_grant时,此字段必填,描述申请权限的原因 |
usedscreen | 当申请权限为user_grant时,此字段必填,描述权限使用的场景和时机 |
abilities | 标识需要使用该权限的Ability,为数组 |
when | 标识权限使用的时机,inuse/always,标识仅允许前台使用和前后台都可以使用 |
5、实战:访问Camera授权
5.1、申请ohos.permission.Camera权限
plain
{
"name": "ohos.permission.CAMERA",
"reason": "$string:Permission_camera_reason",
"usedScene": {
"abilities": ["PermissionDemoAbility"],
"when": "always"
}
}
5.2、校验当前是否已经授权
在进行权限申请之前,需要先检查当前应用程序是否已经被授予权限。可以通过调用checkAccessToken()方法来校验当前是否已经授权。如果已经授权,则可以直接访问目标操作,否则需要进行下一步操作,即向用户申请授权。
checkAccessToken(tokenID: number, permissionName: Permissions): Promise
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
tokenID | number | 是 | 要校验的目标应用的身份标识。可通过应用的ApplicationInfo的accessTokenId字段获得。 |
permissionName | Permissions | 是 | 需要校验的权限名称,合法的权限名取值可在应用权限列表中查询。 |
plain
const permissions:Array<Permissions> = ["ohos.permission.CAMERA"]
//检查权限
async function checkPermissionGrant(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
// 获取应用程序的accessTokenID
let tokenId: number = 0;
try {
let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
tokenId = appInfo.accessTokenId;
} catch (error) {
// @ts-ignore
const err: BusinessError = error as BusinessError;
console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
}
// 校验应用是否被授予权限
try {
grantStatus = await atManager.checkAccessToken(tokenId, permission);
} catch (error) {
// @ts-ignore
const err: BusinessError = error as BusinessError;
console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
}
return grantStatus;
}
async function checkPermissions(): Promise<void> {
let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant(permissions[0]);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 已经授权,可以继续访问目标操作
hilog.error(0x0000,'check_permission',"获取到Camera权限")
} else {
// 申请麦克风权限
hilog.error(0x0000,'check_permission',"Camera权限未被授予")
}
}
5.3、请求权限
plain
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
return;
}
}
// 授权成功
// @ts-ignore
}).catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
5.4、在UI中进行权限声明
plain
import common from '@ohos.app.ability.common';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
const permissions: Array<Permissions> = ['ohos.permission.CAMERA'];
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
return;
}
}
// 授权成功
// @ts-ignore
}).catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
aboutToAppear() {
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
reqPermissionsFromUser(permissions, context);
}
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}