一、前言
当应用需要访问用户的隐私信息或使用系统能力时,例如获取位置信息、访问日历、使用相机拍摄照片或录制视频等,应该向用户请求授权,这部分权限是user_grant权限。
当应用申请user_grant权限时,需要完成以下步调:
- 在配置文件中,声明应用需要请求的权限。
- 将应用中需要申请权限的目的对象与对应目的权限进行关联,让用户明白地知道,哪些操纵需要用户向应用授予指定的权限。
- 运行应用时,在用户触发访问操纵目的对象时应该调用接口,精准触发动态授权弹框。该接口的内部会查抄当前用户是否已经授权应用所需的权限,如果当前用户尚未授予应用所需的权限,该接口会拉起动态授权弹框,向用户请求授权。
- 查抄用户的授权结果,确认用户已授权才可以进行下一步操纵。
二、束缚与限制
- user_grant权限授权要基于用户可知可控的原则,需要应用在运行时主动调用系统动态申请权限的接口,系统弹框由用户授权,用户联合应用运行场景的上下文,识别出应用申请相应敏感权限的合理性,从而做出精确的选择。
- 系统不鼓励频繁弹窗打扰用户,如果用户拒绝授权,将无法再次拉起弹窗,需要应用引导用户在系统应用“设置”的界面中手动授予权限。
- 系统权限弹窗不可被遮挡。 系统权限弹窗不可被其他组件/控件遮挡,弹窗信息需要完整展示,以便用户识别并完成授权动作。- 如果系统权限弹窗与其他组件/控件同时同位置展示,系统权限弹窗将默认覆盖其他组件/控件。
- 每次实行需要目的权限的操纵时,应用都必须查抄自己是否已经具有该权限。
- 如需查抄用户是否已向您的应用授予特定权限,可以使用 checkAccessToken() 函数,此方法会返回PERMISSION_GRANTED或PERMISSION_DENIED。详细示例可参考下文。
- 每次访问受目的权限保护的接口之前,都需要使用 requestPermissionsFromUser() 接口请求相应的权限。
- 用户大概在动态授予权限后通过系统设置来取消应用的权限,因此不能将之前授予的授权状态恒久化。
- 应用在onWindowStageCreate()回调中申请授权时,需要等候异步接口loadContent()/setUIContent()实行结束后或在loadContent()/setUIContent()回调中调用requestPermissionsFromUser(),否则在Content加载完成前,requestPermissionsFromUser会调用失败。
- 应用在UIExtensionAbility申请授权时,需要在onWindowStageCreate函数实行结束后或在onWindowStageCreate函数回调中调用requestPermissionsFromUser(),否则在ability加载完成前,requestPermissionsFromUser会调用失败。
GrantStatus 体现授权状态的枚举。
名称
| 值
| 说明
| PERMISSION_DENIED
| -1
| 体现未授权。
| PERMISSION_GRANTED
| 0
| 体现已授权。
| 三、开辟步调
以申请使用位置权限为例进行说明。 效果展示:
- 申请ohos.permission.LOCATION、ohos.permission.APPROXIMATELY_LOCATION权限,配置方式请参见下文。 应用需要在module.json5配置文件的requestPermissions标签中声明权限。示例如下图
- 校验当前是否已经授权。 在进行权限申请之前,需要先查抄当前应用步伐是否已经被授予权限。可以通过调用checkAccessToken()方法来校验当前是否已经授权。如果已经授权,则可以直接访问目的操纵,否则需要进行下一步操纵,即向用户申请授权。
登录后复制 - import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
- import { BusinessError } from '@kit.BasicServicesKit';
- 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) {
- const err: BusinessError = error as BusinessError;
- console.error(`获取应用程序的accessTokenID Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
- }
- // 校验应用是否被授予权限
- try {
- grantStatus = await atManager.checkAccessToken(tokenId, permission);
- } catch (error) {
- 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 grantStatus1: boolean = await checkPermissionGrant('ohos.permission.LOCATION') === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;// 获取精确定位权限状态
- let grantStatus2: boolean = await checkPermissionGrant('ohos.permission.APPROXIMATELY_LOCATION') === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;// 获取模糊定位权限状态
- // 精确定位权限只能跟模糊定位权限一起申请,或者已经有模糊定位权限才能申请精确定位权限
- if (grantStatus2 && !grantStatus1) {
- // 申请精确定位权限
- } else if (!grantStatus1 && !grantStatus2) {
- // 申请模糊定位权限与精确定位权限或单独申请模糊定位权限
- } else {
- // 已经授权,可以继续访问目标操作
- }
- }
复制代码
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
动态向用户申请权限是指在应用步伐运行时向用户请求授权的过程。可以通过调用 requestPermissionsFromUser() 方法来实现。该方法吸收一个权限列表参数,例如位置、日历、相机、麦克风等。用户可以选择授予权限或者拒绝授权。
可以在UIAbility的onWindowStageCreate()回调中调用 requestPermissionsFromUser() 方法来动态申请权限,也可以根据业务需要在UI中向用户申请授权。
应用在onWindowStageCreate()回调中申请授权时,需要等候异步接口loadContent()/setUIContent()实行结束后或在loadContent()/setUIContent()回调中调用requestPermissionsFromUser(),否则在Content加载完成前,requestPermissionsFromUser会调用失败。
应用在UIExtensionAbility申请授权时,需要在onWindowStageCreate函数实行结束后或在onWindowStageCreate函数回调中调用requestPermissionsFromUser(),否则在ability加载完成前,requestPermissionsFromUser会调用失败。
登录后复制 - // 使用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<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;
- }
- }
- // 授权成功
- }).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);
- // ...
- });
- }
- // ...
- }
复制代码
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
登录后复制 - import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
- 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<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;
- }
- }
- // 授权成功
- }).catch((err: BusinessError) => {
- console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
- })
- }
- @Entry
- @Component
- struct Index {
- aboutToAppear() {
- // 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
- const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
- reqPermissionsFromUser(permissions, context);
- }
- build() {
- // ...
- }
- }
复制代码
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 处置惩罚授权结果。 调用requestPermissionsFromUser()方法后,应用步伐将等候用户授权的结果。如果用户授权,则可以继续访问目的操纵。如果用户拒绝授权,则需要提示用户必须授权才能访问当前页面的功能,并引导用户到系统应用“设置”中打开相应的权限。
路径:设置 > 隐私 > 权限管理 > 应用 > 目的应用
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |