一、前言
权限是所有商业化App必备的基础能力,相机、相册、定位、麦克风、存储等敏感权限,必须用户授权后才能使用。鸿蒙系统采用隐私权限动态申请机制,禁止App默认获取敏感权限,大幅保障用户隐私安全。
很多开发者在权限开发中频繁踩坑,导致App上线驳回、功能异常、闪退崩溃:
本篇全方位讲解鸿蒙权限机制、静态/动态权限区别、权限状态判断、批量权限申请、商用权限工具类封装、拒绝引导策略,所有代码可直接落地商用项目,规避上架审核风险。
二、鸿蒙权限核心机制
2.1 权限分类
鸿蒙将权限分为普通权限与敏感权限两类,管控机制完全不同。
权限类型 | 授权方式 | 特点 | 常见权限 |
|---|
普通权限 | 安装自动授权 | 无用户弹窗,无需动态申请 | 网络、蓝牙、震动等 |
敏感权限 | 运行时动态授权 | 必须弹窗申请,用户手动确认 | 相机、相册、定位、麦克风、存储 |
2.2 权限三种状态(核心重点)
绝大多数权限Bug,都是因为没有处理永久拒绝场景。
三、权限基础配置(前置必备)
动态权限申请前,必须在项目配置文件声明权限,否则申请直接失效。
3.1 module.json5 配置权限
在 module.json5 文件中添加对应权限声明与权限描述,上架应用市场必须填写规范描述,否则审核驳回。
"requestPermissions": [ { "name": "ohos.permission.CAMERA", "reason": "用于扫码、拍照、拍摄视频功能", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }, { "name": "ohos.permission.READ_IMAGEVIDEO", "reason": "用于读取本地相册图片、视频资源", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }]
四、基础权限判断与单权限申请
鸿蒙通过 accessToken 模块判断权限状态,通过 permission 模块发起动态申请。
4.1 判断权限是否授权
import accessToken from '@ohos.security.accesstoken';import common from '@ohos.app.ability.common';// 判断单权限是否已授权export async function checkPermission(context: common.UIAbilityContext, permission: string): Promise<boolean> { let tokenId = context.applicationInfo.accessTokenId; let res = await accessToken.verifyAccessToken(tokenId, permission); // 0 代表已授权 return res === 0;}
4.2 单权限动态申请
import permission from '@ohos.ability.permission';import common from '@ohos.app.ability.common';// 申请单个权限export async function requestSinglePermission(context: common.UIAbilityContext, permission: string) { // 先判断是否已授权 let hasAuth = await checkPermission(context, permission); if (hasAuth) { return true; } // 发起权限申请 let res = await permission.requestPermissionsFromUser(context, [permission]); // 申请结果 0=授权 1=拒绝 2=永久拒绝 return res.authResults[0] === 0;}
五、批量权限申请实战
项目中常需要同时申请相册、相机、存储等多个权限,支持批量统一申请,减少弹窗次数。
// 批量申请权限export async function requestMultiPermission(context: common.UIAbilityContext, permissionList: string[]) { let res = await permission.requestPermissionsFromUser(context, permissionList); // 返回全部授权结果 return res.authResults;}
调用示例:一次性申请相机+相册权限
let permissionList = [ 'ohos.permission.CAMERA', 'ohos.permission.READ_IMAGEVIDEO'];let result = await requestMultiPermission(getContext(this) as common.UIAbilityContext, permissionList);
六、核心难点:永久拒绝权限适配
用户勾选「始终拒绝」后,系统不再弹出授权弹窗,必须手动跳转应用设置页引导用户开启权限,这是商用项目必适配场景。
6.1 跳转系统权限设置页
import abilityAccessCtrl from '@ohos.abilityaccessctrl';import common from '@ohos.app.ability.common';// 跳转应用权限设置页面export function jumpPermissionSetting(context: common.UIAbilityContext) { let wantInfo = { bundleName: context.abilityInfo.bundleName, abilityName: 'com.huawei.hmos.settings.MainAbility', uri: 'application_info' }; context.startAbility(wantInfo);}
6.2 完整权限申请策略(含拒绝重试)
完整流程:判断权限 - 未授权申请 - 拒绝弹窗提示 - 永久拒绝引导跳转设置。
// 完整带容错的权限申请方法export async function requestPermissionWithTip(context: common.UIAbilityContext, permission: string): Promise<boolean> { let hasAuth = await checkPermission(context, permission); if (hasAuth) return true; let res = await permission.requestPermissionsFromUser(context, [permission]); let status = res.authResults[0]; // 0:授权成功 if (status === 0) return true; // 2:永久拒绝,弹窗引导 if (status === 2) { promptAction.showDialog({ title: '权限开启提示', message: '当前权限已被永久拒绝,请前往设置手动开启', confirmText: '去设置', cancelText: '取消' }).then((data) => { if (data.index === 0) { jumpPermissionSetting(context); } }) } else { promptAction.showToast({ message: '权限申请失败,部分功能无法使用' }); } return false;}
七、商用全局权限工具类完整版
整合所有能力,封装成全局通用工具类,项目全局复用,统一权限处理逻辑。
// common/PermissionUtil.etsimport accessToken from '@ohos.security.accesstoken';import permission from '@ohos.ability.permission';import promptAction from '@ohos.promptAction';import common from '@ohos.app.ability.common';export class PermissionUtil { // 校验权限是否已授权 static async check(context: common.UIAbilityContext, permission: string): Promise<boolean> { let tokenId = context.applicationInfo.accessTokenId; let result = await accessToken.verifyAccessToken(tokenId, permission); return result === 0; } // 申请单个权限(带完整容错策略) static async apply(context: common.UIAbilityContext, permission: string, tip: string = '该权限为功能必备权限'): Promise<boolean> { if (await this.check(context, permission)) return true; let res = await permission.requestPermissionsFromUser(context, [permission]); let state = res.authResults[0]; if (state === 0) return true; if (state === 2) { promptAction.showDialog({ title: '权限提示', message: tip, confirmText: '前往设置' }).then((data) => { data.index === 0 && this.jumpSetting(context); }) } else { promptAction.showToast({ message: '权限申请失败' }); } return false; } // 跳转系统设置页 static jumpSetting(context: common.UIAbilityContext) { let want = { bundleName: context.abilityInfo.bundleName, abilityName: 'com.huawei.hmos.settings.MainAbility', uri: 'application_info' }; context.startAbility(want); }}
八、页面调用极简示例
import { PermissionUtil } from './common/PermissionUtil';@Entry@Componentstruct PermissionPage { async requestCamera() { let context = getContext(this) as common.UIAbilityContext; // 申请相机权限 let result = await PermissionUtil.apply(context, 'ohos.permission.CAMERA', '需要相机权限以支持拍照、扫码功能'); if (result) { promptAction.showToast({ message: '相机权限授权成功' }); // 执行相机业务逻辑 } } build() { Column() { Button('申请相机权限') .onClick(() => this.requestCamera()) } .width('100%') .justifyContent(FlexAlign.Center) }}
九、权限开发高频坑点汇总
- 未配置权限声明:module.json5 未注册权限,申请直接无效,上架驳回;
- 忽略永久拒绝场景:用户拒绝后功能永久失效,无引导策略,体验极差;
- 重复频繁申请权限:未先判断授权状态,每次进入页面都弹窗,遭用户投诉;
- 权限描述不规范:reason 填写模糊、无实际用途,应用市场审核不通过;
- 主线程阻塞申请:权限申请为异步操作,禁止同步阻塞UI;
- 批量权限不做容错:多个权限仅部分授权,未单独判断处理,导致功能异常。
十、全文总结
鸿蒙权限开发的核心不在于「弹窗申请权限」,而在于全状态容错处理。已授权、临时拒绝、永久拒绝三种场景全覆盖,搭配统一工具类封装,是商用项目的标准开发规范。
本文封装的 PermissionUtil 工具类,可直接接入任何鸿蒙商用项目,彻底解决权限重复代码、适配不全、上架驳回、功能失效等问题,大幅提升项目稳定性与用户体验。