为什么访问需要权限?
默认情况下,应用只能访问有限的系统资源。但某些情况下,应用存在扩展功能的诉求,需要访问额外的系统数据(包括用户个人数据)和功能,系统也必须以明确的方式对外提供接口来共享其数据或功能。
试想一下,如果不需要权限就可以访问一些手机的敏感数据不需要权限,某个恶意的app挂羊头卖狗肉,在用户不知情的情况下就扫描完了手机内的相册、视频、联系人等。这是非常危险的行为。
鸿蒙的访问控制权限大体如下图:
权限级别整体分为三大类,从安全程度以及申请的难易程度,从浅到深为系统授权(system_grant)、用户授权(user_grant)和受限开放权限。
一、系统授权(system_grant)
系统授权只需在module.json5声明即可,无需在代码里面弹窗向用户确认,比如网络权限ohos.permission.INTERNET
权限列表可以参考developer.huawei.com/consumer/cn…
kotlin 代码解读复制代码{
"module" : {
// ...
"requestPermissions":[
{
"name" : "ohos.permission.PERMISSION1",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"inuse"
}
},
{
"name" : "ohos.permission.PERMISSION2",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"always"
}
}
]
}
}
二、用户授权(user_grant)
这部分权限除了要在module.json内声明,还需要在代码里面弹窗向用户确认,让用户能够显示的感知到app在申请这个权限。当然一般是要求app在使用时才申请权限,比如用户想拍照时才弹窗申请camera权限,而不是一启动app就把camera权限申请了。
向用户申请权限:
typescript 代码解读复制代码// 使用UIExtensionAbility:将import { UIAbility } from '@kit.AbilityKit' 替换为import { UIExtensionAbility } from '@kit.AbilityKit';
import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
const permissions: Array<Permissions> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array, 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;
}
}
// 授权成功
}).catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
// 使用UIExtensionAbility:将 UIAbility 替换为UIExtensionAbility
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// ...
windowStage.loadContent('pages/Index', (err, data) => {
reqPermissionsFromUser(permissions, this.context);
// ...
});
}
// ...
}
其中也有一些需要注意的点,比如申请前先通过checkAccessToken()检查是否已授权。
用户拒绝授权后,通过requestPermissionsFromUser()和requestPermissionOnSetting()申请二次授权等。
三、受限开放权限
这部分权限属于安全级别最高,普通三方应用都没有权限去开通。如果一定是强需求,可以通过官网的申请流程向应用商店发起流程申请。
四、系统picker和安全控件
user_agent以上的权限都需要用户弹窗感知同意,开发者也要多写一些代码来处理这块逻辑。鸿蒙推出了系统picker和安全控件,目的是为了在一些通用场景减少开发者和用户的负担。
4.1系统picker
应用拉起系统Picker组件(文件选择器、照片选择器、联系人选择器等),由用户在Picker上选择对应的文件、照片、联系人等资源,应用即可获取到Picker的返回结果。
由于系统Picker已经获取了对应权限的预授权,开发者使用系统Picker时,无需再次申请权限也可临时受限访问对应的资源。例如,当应用需要读取用户图片时,可通过使用照片Picker,在用户选择所需要的图片资源后,直接返回该图片资源,而不需要授予应用读取图片文件的权限。
以选择联系人号码为例子:
javascript 代码解读复制代码 contact.selectContacts({
isMultiSelect: false
}, (err: BusinessError, data) => {
if (err) {
console.error(`selectContact callback: err->${JSON.stringify(err)}`);
success('')
return;
}
console.log(`selectContact callback: success data->${JSON.stringify(data)}`);
try {
success(data[0]?.phoneNumbers?.[0]?.phoneNumber ?? '')
} catch (e) {
success('')
}
});
无需上面提到的检查权限、动态申请权限这么麻烦,直接拿着内置的contact类用就行了。
4.2 安全控件
安全控件分为粘贴控件、保存控件、位置控件。
分别对应剪切板共享、保存文件、获取位置信息的场景,也是不需要额外申请权限。
安全控件和picker不太一样的是,控件属于ui组件会有统一的系统级别ui。
从用户角度看,不管在哪个app 安全控件的ui都是差不多的。因为系统限制了安全控件ui没法自由定制,需要按照系统的模板来。目的应该也是让用户一看就知道这个是安全控件的按钮。
五、总结
鸿蒙的权限随着安全程度提高,使用的复杂度也跟着提高。整体来看是为了让用户能感知到权限被使用了。
包括user_grant的弹窗,以及更高的受限开放权限。picker需要跳到系统应用,用户能感知到;安全控件有特定的ui用户也能感知到。
评论记录:
回复评论: