HarmonyOS 权限管理完全指南:从申请到检查

发布时间:2026/6/8 14:57:23

HarmonyOS 权限管理完全指南:从申请到检查 文章目录前言一、权限类型与声明1.1 权限的两种分类1.2 在 module.json5 中声明权限1.3 本项目申请的权限二、PermissionsUtil 源码逐行解析2.1 主入口checkPermissions2.2 核心步骤checkAccessToken2.3 弹窗申请requestPermissions三、完整权限工具类增强版3.1 添加权限被拒后引导设置功能3.2 在页面中使用增强版权限工具四、常见权限错误码总结前言在 HarmonyOS 中应用访问敏感资源定位、摄像头、通讯录等必须经过用户授权。未经授权直接调用相关 API 会触发安全异常。本项目在启动时申请了精确定位和模糊定位两个权限使用了abilityAccessCtrl和bundleManager两个核心模块。本篇通过项目源码PermissionsUtil.ets完整解析 HarmonyOS 权限申请的每个步骤。一、权限类型与声明1.1 权限的两种分类类型特点代表权限普通权限安装时自动授予网络访问、振动敏感权限运行时需弹窗请用户授权定位、摄像头、通讯录1.2 在 module.json5 中声明权限在使用权限之前必须在module.json5中声明相当于提前告知系统和用户// entry/src/main/module.json5 { module: { requestPermissions: [ { name: ohos.permission.LOCATION, reason: $string:reason_location, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.APPROXIMATELY_LOCATION, reason: $string:reason_approx_location, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }提示when: inuse表示仅在使用时需要权限最小权限原则比always更容易被用户接受。1.3 本项目申请的权限// MainPage.etsconstPERMISSIONS:ArrayPermissions[ohos.permission.LOCATION,// 精确定位GPS级别ohos.permission.APPROXIMATELY_LOCATION// 模糊定位网络/基站级别];两个权限的区别APPROXIMATELY_LOCATION定位精度约 5km保护用户隐私必须同时申请LOCATION精确定位GPS精度可到米级需要额外申请二、PermissionsUtil 源码逐行解析2.1 主入口checkPermissionsasynccheckPermissions(permissions:ArrayPermissions,context:Context):Promisevoid{letapplyResult:booleanfalse;// 遍历所有权限逐个检查for(letpermissionofpermissions){letgrantStatus:abilityAccessCtrl.GrantStatusawaitthis.checkAccessToken(permission);if(grantStatusabilityAccessCtrl.GrantStatus.PERMISSION_GRANTED){applyResulttrue;// 已授权}else{applyResultfalse;// 未授权只要有一个未授权就标记为 false}}// 如果有权限未授权弹窗请求if(!applyResult){this.requestPermissions(permissions,context);}}逻辑流程for each permission: 检查该权限状态 → 已授权? → 继续 → 未授权? → applyResult false if !applyResult → 弹窗申请权限2.2 核心步骤checkAccessTokenasynccheckAccessToken(permission:Permissions):PromiseabilityAccessCtrl.GrantStatus{letatManager:abilityAccessCtrl.AtManagerabilityAccessCtrl.createAtManager();letgrantStatus:abilityAccessCtrl.GrantStatusabilityAccessCtrl.GrantStatus.PERMISSION_DENIED;// 步骤1通过 bundleManager 获取当前应用的 accessTokenIdlettokenId:number0;try{letbundleInfo:bundleManager.BundleInfoawaitbundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);letappInfo:bundleManager.ApplicationInfobundleInfo.appInfo;tokenIdappInfo.accessTokenId;// 每个应用有唯一的 Token ID}catch(error){Logger.error(Failed to get bundle info. Code${error.code}, msg${error.message});}// 步骤2用 tokenId 查询具体权限的授权状态try{grantStatusawaitatManager.checkAccessToken(tokenId,permission);}catch(error){Logger.error(Failed to check access token. Code${error.code}, msg${error.message});}returngrantStatus;}关键类型说明abilityAccessCtrl.AtManager权限管理器提供权限检查和申请 APIabilityAccessCtrl.GrantStatus授权状态枚举PERMISSION_GRANTED 0已授权PERMISSION_DENIED -1未授权accessTokenId应用的唯一安全令牌 ID是权限系统识别应用身份的凭据2.3 弹窗申请requestPermissionsrequestPermissions(permissions:ArrayPermissions,context:Context):void{letatManager:abilityAccessCtrl.AtManagerabilityAccessCtrl.createAtManager();// 弹出系统权限申请弹窗atManager.requestPermissionsFromUser(context,permissions).then((){// 用户点击了同意geoLocationManager.getCurrentLocation();// 立即获取一次位置激活权限Logger.info(request Permissions success);}).catch((err:BusinessError){// 用户点击了拒绝Logger.error(Failed to request permissions. Code${err.code}, msg${err.message});});}三、完整权限工具类增强版3.1 添加权限被拒后引导设置功能import{abilityAccessCtrl,bundleManager,Permissions,common}fromkit.AbilityKit;import{BusinessError}fromkit.BasicServicesKit;import{geoLocationManager}fromkit.LocationKit;exportclassEnhancedPermissionsUtil{privateatManager:abilityAccessCtrl.AtManagerabilityAccessCtrl.createAtManager();// 获取应用 Token IDprivateasyncgetTokenId():Promisenumber{try{constbundleInfoawaitbundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);returnbundleInfo.appInfo.accessTokenId;}catch(error){console.error(获取 TokenId 失败${(errorasBusinessError).message});return0;}}// 检查单个权限状态asynccheckSinglePermission(permission:Permissions):Promiseboolean{consttokenIdawaitthis.getTokenId();if(tokenId0)returnfalse;try{conststatusawaitthis.atManager.checkAccessToken(tokenId,permission);returnstatusabilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;}catch{returnfalse;}}// 检查多个权限返回未授权的权限列表asynccheckPermissions(permissions:Permissions[]):PromisePermissions[]{constdeniedPermissions:Permissions[][];for(constpermissionofpermissions){constgrantedawaitthis.checkSinglePermission(permission);if(!granted){deniedPermissions.push(permission);}}returndeniedPermissions;}// 申请权限返回是否全部授权asyncrequestPermissions(permissions:Permissions[],context:common.UIAbilityContext):Promiseboolean{try{constresultawaitthis.atManager.requestPermissionsFromUser(context,permissions);// result.authResults 是每个权限的授权结果数组// 0 已授权-1 拒绝constallGrantedresult.authResults.every(rr0);returnallGranted;}catch(error){console.error(申请权限失败${(errorasBusinessError).message});returnfalse;}}// 引导用户去系统设置开启权限openPermissionSettings(context:common.UIAbilityContext):void{context.startAbility({bundleName:com.huawei.hmos.settings,abilityName:com.huawei.hmos.settings.MainAbility,uri:application_info_entry,parameters:{pushParams:context.applicationInfo.name}}).catch((err:BusinessError){console.error(打开设置失败${err.message});});}// 一站式检查 → 申请 → 引导设置asyncensurePermissions(permissions:Permissions[],context:common.UIAbilityContext,onDenied?:()void):Promiseboolean{// 第一步检查哪些权限缺失constdeniedawaitthis.checkPermissions(permissions);if(denied.length0){returntrue;// 所有权限已有}// 第二步申请缺失权限constgrantedawaitthis.requestPermissions(denied,context);if(granted){returntrue;}// 第三步申请被拒执行回调通常是引导用户去设置if(onDenied){onDenied();}returnfalse;}}3.2 在页面中使用增强版权限工具EntryComponentstruct PermissionDemoPage{StatepermissionStatus:string未知;StatehasLocation:booleanfalse;privatepermUtilnewEnhancedPermissionsUtil();privatecontextthis.getUIContext().getHostContext()ascommon.UIAbilityContext;asyncaboutToAppear():Promisevoid{awaitthis.checkAndRequestLocation();}asynccheckAndRequestLocation():Promisevoid{constLOCATION_PERMISSIONS:Permissions[][ohos.permission.LOCATION,ohos.permission.APPROXIMATELY_LOCATION];this.permissionStatus检查中...;constsuccessawaitthis.permUtil.ensurePermissions(LOCATION_PERMISSIONS,this.context,(){// 权限被拒后的引导this.permissionStatus权限被拒绝;this.showPermissionDeniedDialog();});if(success){this.hasLocationtrue;this.permissionStatus定位权限已获取 ✅;}}showPermissionDeniedDialog():void{this.getUIContext().getPromptAction().showDialog({title:需要定位权限,message:应用需要定位权限才能显示附近加油站请前往设置开启。,buttons:[{text:取消,color:#999999},{text:去设置,color:#1A6FF5}]}).then(result{if(result.index1){this.permUtil.openPermissionSettings(this.context);}});}build(){Column({space:24}){Text(权限管理演示).fontSize(20).fontWeight(FontWeight.Bold)Column({space:12}){Row({space:8}){Text(定位权限状态).fontSize(14).fontColor(#666666)Text(this.permissionStatus).fontSize(14).fontColor(this.hasLocation?#52C41A:#FF4D4F).fontWeight(FontWeight.Bold)}}.padding(20).width(90%).backgroundColor(#F8F9FA).borderRadius(12)Button(重新检查权限).onClick((){this.checkAndRequestLocation();}).width(80%).height(48).backgroundColor(#1A6FF5).fontColor(#FFFFFF).borderRadius(24)}.width(100%).height(100%).justifyContent(FlexAlign.Center)}}四、常见权限错误码错误码含义解决方案201权限被拒绝引导用户去设置页开启401参数错误检查权限名称拼写12100001accessTokenId 无效确保 bundleManager 调用成功12100002权限未在 module.json5 声明在配置文件中添加权限声明总结HarmonyOS 权限申请遵循声明→检查→申请→引导四步流程先在module.json5声明权限运行时通过bundleManager获取应用 Token再通过abilityAccessCtrl检查和申请权限。合理处理用户拒绝的情况——提供友好的引导对话框让用户能方便地前往设置页手动开启——是高质量应用的标配。

相关新闻