鸿蒙中 应用的权限:申请授权(三)
本文同步发表于我的微信公众号微信搜索程语新视界即可关注每个工作日都有文章更新鸿蒙应用开发中当应用需要访问用户的隐私信息或使用系统能力时如获取位置、使用相机、访问日历等必须向用户申请授权。这些权限属于user_grant类型。user_grant权限指的是需要用户明确授权的权限通常涉及用户隐私信息或系统能力。常见user_grant权限位置信息精确/模糊相机拍摄麦克风录音日历访问通讯录读取健身运动数据user_grant权限的申请原则原则说明用户可知可控必须由用户主动授权系统弹窗提示最小化原则只申请业务必需的权限动态申请在需要使用权限时申请而非启动时全部申请不频繁弹窗避免频繁打扰用户二、user_grant权限申请流程2.1 四步走流程步骤1在配置文件中声明权限 ↓ 步骤2将权限与目标操作关联开发阶段 ↓ 步骤3运行时检查权限 → 未授权则动态申请 ↓ 步骤4处理授权结果同意/拒绝2.2 步骤1声明权限module.json5{ module: { requestPermissions: [ { name: ohos.permission.LOCATION, reason: $string:location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.APPROXIMATELY_LOCATION, reason: $string:approximately_location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }注意user_grant权限必须填写reason和usedScene字段用于上架审核和用户知情。2.3 步骤2权限与目标操作关联在代码层面将需要权限的操作与权限检查逻辑关联。三、核心开发步骤步骤3-43.1 导入所需模块import { abilityAccessCtrl, bundleManager, Permissions, common } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit;3.2 检查权限是否已授权在进行权限申请之前需要先检查当前应用是否已被授予权限。// PermissionUtil.ets import { abilityAccessCtrl, bundleManager, Permissions } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; async function checkPermissionGrant(permission: Permissions): PromiseabilityAccessCtrl.GrantStatus { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; // 1. 获取应用程序的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(Failed to get bundle info, code: ${err.code}, message: ${err.message}); } // 2. 校验应用是否被授予权限 try { grantStatus await atManager.checkAccessToken(tokenId, permission); } catch (error) { const err: BusinessError error as BusinessError; console.error(Failed to check access token, code: ${err.code}, message: ${err.message}); } return grantStatus; } // 检查多个权限的状态 async function checkPermissions(): Promisevoid { // 获取精确定位权限状态 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) { // 已有模糊权限需要申请精确定位权限 console.info(Need to request precise location permission); } else if (!grantStatus1 !grantStatus2) { // 两种权限都没有需要申请模糊定位权限与精确定位权限 console.info(Need to request both permissions); } else { // 已经授权可以继续访问目标操作 console.info(Permissions already granted); } }3.3 动态向用户申请授权通过requestPermissionsFromUser()方法向用户请求授权。方式一在UIAbility中申请授权// SecondAbility.ets import { abilityAccessCtrl, common, Permissions, UIAbility } from kit.AbilityKit; import { window } from kit.ArkUI; import { BusinessError } from kit.BasicServicesKit; const permissions: Permissions[] [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; function reqPermissionsFromUser(permissions: ArrayPermissions, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 atManager.requestPermissionsFromUser(context, permissions) .then((data) { let grantStatus: number[] data.authResults; for (let i 0; i grantStatus.length; i) { if (grantStatus[i] 0) { // 用户授权 console.info(${permissions[i]} is granted by user.); } else { // 用户拒绝授权 console.warn(${permissions[i]} is denied by user.); // 引导用户到设置中开启 this.guideToSettings(); } } }) .catch((err: BusinessError) { console.error(Failed to request permissions, code: ${err.code}, message: ${err.message}); }); } export default class SecondAbility extends UIAbility { onWindowStageCreate(windowStage: window.WindowStage): void { // 重要需要在loadContent回调中申请权限 windowStage.loadContent(secondpages/Index, (err) { if (!err) { reqPermissionsFromUser(permissions, this.context); } }); } private guideToSettings(): void { // 引导用户去设置页面 console.info(Guide user to settings); } }方式二在UI中申请授权// Index.ets import { abilityAccessCtrl, common, Permissions } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; const permissions: Permissions[] [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; function reqPermissionsFromUser(permissions: ArrayPermissions, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(context, permissions) .then((data) { let grantStatus: number[] data.authResults; for (let i 0; i grantStatus.length; i) { if (grantStatus[i] 0) { console.info(${permissions[i]} is granted.); } else { console.warn(${permissions[i]} is denied.); // 可以在UI上提示用户 } } }) .catch((err: BusinessError) { console.error(Failed to request permissions, code: ${err.code}); }); } Entry Component struct Index { aboutToAppear() { const context: common.UIAbilityContext this.getUIContext().getHostContext() as common.UIAbilityContext; reqPermissionsFromUser(permissions, context); } build() { Column() { Text(位置权限示例) .fontSize(20) .margin(20) Button(获取位置) .onClick(() { // 每次使用前最好再检查一次权限 // 因为用户可能在设置中关闭了权限 }) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }3.4 处理授权结果用户同意授权if (grantStatus[i] 0) { // 用户授权可以继续访问目标操作 this.accessLocation(); }用户拒绝授权当用户拒绝授权时有几种处理方式方式1引导用户到系统设置中开启import { common } from kit.AbilityKit; private guideToSettings() { let context getContext(this) as common.UIAbilityContext; context.startAbility({ action: action.settings.app.info, parameters: { bundleName: com.example.myapp } }); }方式2调用requestPermissionOnSetting拉起权限设置弹窗// 从API 12开始支持 async function requestPermissionInSetting(permission: Permissions) { let atManager abilityAccessCtrl.createAtManager(); try { await atManager.requestPermissionOnSetting(this.context, permission); // 用户已在设置中授权 console.info(Permission granted in settings); } catch (error) { console.error(Failed to request permission in setting); } }四、限制4.1 弹窗规则规则说明不可被遮挡系统权限弹窗不可被其他组件或控件遮挡完整展示弹窗信息需完整展示便于用户识别优先级最高如果与其他组件同时展示系统权限弹窗将默认覆盖其他组件4.2 调用时机限制场景要求在UIAbility的onWindowStageCreate中申请需要等待loadContent/setUIContent执行结束后或在回调中调用在UIExtensionAbility中申请需要在onWindowStageCreate函数执行结束后或在回调中调用原因在Content加载完成前requestPermissionsFromUser会调用失败4.3 权限状态不可持久化// 错误做法缓存授权状态 let cachedPermission true; // 假设用户之前授权了 if (cachedPermission) { this.accessLocation(); // 可能失败因为用户可能在设置中关闭了权限 } // 正确做法每次使用前检查 async function accessLocation() { let grantStatus await checkPermissionGrant(ohos.permission.LOCATION); if (grantStatus abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { // 已授权可以访问 } else { // 未授权重新申请 } }原因用户可能在动态授予权限后通过系统设置来取消应用的权限因此不能将之前授予的授权状态持久化。五、完整示例5.1 权限声明module.json5{ module: { requestPermissions: [ { name: ohos.permission.APPROXIMATELY_LOCATION, reason: $string:approximately_location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.LOCATION, reason: $string:location_permission_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }5.2 权限工具类// PermissionManager.ets import { abilityAccessCtrl, bundleManager, Permissions, common } from kit.AbilityKit; import { BusinessError } from kit.BasicServicesKit; export class PermissionManager { private static instance: PermissionManager; private atManager: abilityAccessCtrl.AtManager; private constructor() { this.atManager abilityAccessCtrl.createAtManager(); } static getInstance(): PermissionManager { if (!PermissionManager.instance) { PermissionManager.instance new PermissionManager(); } return PermissionManager.instance; } // 检查单个权限 async checkPermission(permission: Permissions): Promiseboolean { try { let bundleInfo await bundleManager.getBundleInfoForSelf( bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION ); let tokenId bundleInfo.appInfo.accessTokenId; let grantStatus await this.atManager.checkAccessToken(tokenId, permission); return grantStatus abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; } catch (error) { console.error(Check permission failed, error); return false; } } // 申请权限 async requestPermissions(permissions: Permissions[], context: common.UIAbilityContext): Promiseboolean { try { let result await this.atManager.requestPermissionsFromUser(context, permissions); // 检查是否所有权限都被授予 return result.authResults.every(status status 0); } catch (error) { console.error(Request permissions failed, error); return false; } } // 检查并申请权限一步到位 async checkAndRequestPermissions(permissions: Permissions[], context: common.UIAbilityContext): Promiseboolean { // 先检查是否都已授权 for (let perm of permissions) { let granted await this.checkPermission(perm); if (!granted) { // 有未授权的权限发起申请 return await this.requestPermissions(permissions, context); } } return true; // 全部已授权 } }5.3 在页面中使用// LocationPage.ets import { PermissionManager } from ./PermissionManager; import { common } from kit.AbilityKit; Entry Component struct LocationPage { State hasPermission: boolean false; State locationText: string 未知位置; async aboutToAppear() { const context this.getUIContext().getHostContext() as common.UIAbilityContext; const permissions [ ohos.permission.LOCATION, ohos.permission.APPROXIMATELY_LOCATION ]; // 检查并申请权限 this.hasPermission await PermissionManager.getInstance() .checkAndRequestPermissions(permissions, context); } async getLocation() { if (!this.hasPermission) { // 再次尝试申请 const context this.getUIContext().getHostContext() as common.UIAbilityContext; this.hasPermission await PermissionManager.getInstance() .requestPermissions([ohos.permission.LOCATION], context); if (!this.hasPermission) { // 引导用户去设置 this.showSettingsDialog(); return; } } // 获取位置逻辑 this.locationText 北京市朝阳区; } showSettingsDialog() { AlertDialog.show({ message: 需要位置权限才能使用此功能请在设置中开启, primaryButton: { value: 去设置, action: () { // 跳转到应用设置页 } }, secondaryButton: { value: 取消 } }); } build() { Column() { Text(this.locationText) .fontSize(16) .margin(20) Button(获取当前位置) .enabled(this.hasPermission) .onClick(() this.getLocation()) if (!this.hasPermission) { Text(需要位置权限才能使用此功能) .fontColor(#FF0000) .fontSize(14) .margin(10) } } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2419505.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!