技术栈:HarmonyOS 5.0 + ArkTS + abilityAccessCtrl
适用场景:音频录制、设备控制、隐私数据访问
前言
HarmonyOS采用严格的权限管理机制,敏感权限需要在配置文件声明并动态申请。本文将介绍如何正确处理麦克风、震动等常用权限。
一、权限分类
| 权限类型 | 说明 | 示例 |
|---|---|---|
| system_grant | 系统自动授予 | 网络访问 |
| user_grant | 需用户授权 | 麦克风、相机 |
二、配置文件声明
2.1 module.json5配置
json
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:microphone_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.VIBRATE",
"reason": "$string:vibrate_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
2.2 字符串资源
json
// resources/base/element/string.json
{
"string": [
{
"name": "microphone_reason",
"value": "用于检测环境噪音分贝值,保护您的听力健康"
},
{
"name": "vibrate_reason",
"value": "用于操作反馈和手机排水功能"
}
]
}
三、动态权限申请
3.1 权限工具类
typescript
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
import common from '@ohos.app.ability.common';
export class PermissionUtil {
/**
* 检查权限是否已授予
*/
static async checkPermission(permission: string): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const bundleInfo = await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
);
const tokenId = bundleInfo.appInfo.accessTokenId;
const grantStatus = await atManager.checkAccessToken(tokenId, permission);
return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
/**
* 请求单个权限
*/
static async requestPermission(
context: common.UIAbilityContext,
permission: string
): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(context, [permission]);
return result.authResults[0] === 0;
} catch (err) {
console.error('请求权限失败:', err);
return false;
}
}
/**
* 请求多个权限
*/
static async requestPermissions(
context: common.UIAbilityContext,
permissions: string[]
): Promise<Map<string, boolean>> {
const atManager = abilityAccessCtrl.createAtManager();
const resultMap = new Map<string, boolean>();
try {
const result = await atManager.requestPermissionsFromUser(context, permissions);
for (let i = 0; i < permissions.length; i++) {
resultMap.set(permissions[i], result.authResults[i] === 0);
}
} catch (err) {
console.error('请求权限失败:', err);
permissions.forEach(p => resultMap.set(p, false));
}
return resultMap;
}
}
3.2 麦克风权限申请
typescript
@Entry
@Component
struct DecibelMeterPage {
@State hasPermission: boolean = false;
@State isMonitoring: boolean = false;
private decibelDetector: DecibelDetector | null = null;
aboutToAppear(): void {
this.checkAndRequestPermission();
}
private async checkAndRequestPermission(): Promise<void> {
const context = getContext(this) as common.UIAbilityContext;
// 先检查是否已有权限
this.hasPermission = await PermissionUtil.checkPermission('ohos.permission.MICROPHONE');
if (!this.hasPermission) {
// 请求权限
this.hasPermission = await PermissionUtil.requestPermission(
context,
'ohos.permission.MICROPHONE'
);
}
if (this.hasPermission) {
this.initDecibelDetector();
}
}
private initDecibelDetector(): void {
this.decibelDetector = new DecibelDetector((db: number) => {
// 处理分贝值
});
this.decibelDetector.start();
this.isMonitoring = true;
}
build() {
Column() {
if (!this.hasPermission) {
Column() {
Text('需要麦克风权限')
.fontSize(18)
Text('请授权麦克风权限以使用分贝检测功能')
.fontSize(14)
.fontColor('#666')
Button('授权')
.onClick(() => this.checkAndRequestPermission())
}
} else {
// 正常功能界面
Text(`${this.isMonitoring ? '检测中...' : '未启动'}`)
}
}
}
}
四、权限被拒绝的处理
4.1 引导用户到设置页
typescript
import Want from '@ohos.app.ability.Want';
async function openAppSettings(context: common.UIAbilityContext): Promise<void> {
const want: Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
pushParams: context.abilityInfo.bundleName
}
};
try {
await context.startAbility(want);
} catch (err) {
console.error('打开设置失败:', err);
}
}
4.2 友好的权限说明弹窗
typescript
@CustomDialog
struct PermissionDialog {
controller: CustomDialogController;
permissionName: string = '麦克风';
permissionReason: string = '用于检测环境噪音';
onConfirm: () => void = () => {};
onCancel: () => void = () => {};
build() {
Column() {
Text(`需要${this.permissionName}权限`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(this.permissionReason)
.fontSize(14)
.fontColor('#666')
.margin({ top: 10 })
Row() {
Button('取消')
.onClick(() => {
this.onCancel();
this.controller.close();
})
Button('去授权')
.onClick(() => {
this.onConfirm();
this.controller.close();
})
}
.margin({ top: 20 })
.justifyContent(FlexAlign.SpaceEvenly)
.width('100%')
}
.padding(20)
}
}
五、常用权限列表
| 权限名称 | 用途 | 类型 |
|---|---|---|
| ohos.permission.MICROPHONE | 麦克风录音 | user_grant |
| ohos.permission.VIBRATE | 设备震动 | system_grant |
| ohos.permission.INTERNET | 网络访问 | system_grant |
| ohos.permission.CAMERA | 相机拍照 | user_grant |
| ohos.permission.READ_MEDIA | 读取媒体文件 | user_grant |
六、避坑指南
- 声明与申请:user_grant权限需要在配置文件声明且动态申请
- reason字段:必须提供清晰的权限使用说明,审核会检查
- 时机选择:在需要使用时再申请,不要一启动就申请所有权限
- 拒绝处理:用户拒绝后要有友好的引导,不能强制退出
- 隐私政策:应用商店要求在隐私政策中说明权限用途
七、华为应用市场审核要点
- 权限申请必须有明确的使用场景
- reason字段要清晰说明用途
- 不能申请与功能无关的权限
- 用户拒绝权限后应用仍能正常使用其他功能
总结
本文介绍了HarmonyOS权限管理的完整流程,包括配置声明、动态申请、拒绝处理等。正确的权限管理不仅是应用上架的必要条件,也是保护用户隐私的重要措施。