鸿蒙权限管理:手动设置授权(五)
本文介绍了鸿蒙系统中manual_settings权限的申请流程,这是权限级别最高、管控最严格的一类权限,如拦截键盘输入事件等敏感能力。文章详细说明了manual_settings权限的特点、与user_grant权限的区别,并重点讲解了四步申请流程:先在AGC申请Profile文件并添加ACL权限,再在module.json5中声明权限,运行时检查权限状态,最后引导用户跳转系统设置开启权限。同时
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
前言
前两篇文章中介绍了user_grant权限的首次申请和再次申请。huanyou另一种特殊的权限类型——manual_settings权限。
manual_settings权限是鸿蒙系统中权限级别最高、管控最严格的一类权限,例如拦截键盘输入事件等敏感能力。
一、manual_settings权限
manual_settings权限指的是需要用户在系统设置中手动开启的权限,这类权限涉及用户隐私或可能对系统产生严重影响。
典型manual_settings权限:
-
ohos.permission.HOOK_KEY_EVENT- 拦截键盘输入事件(PC/2in1设备) -
其他涉及系统核心能力的敏感权限
1.2 manual_settings权限的特点
| 特点 | 说明 |
|---|---|
| 授权方式 | 手动设置授权,无法通过弹窗申请 |
| 涉及数据 | 用户个人信息或对系统有严重影响的操作 |
| 申请流程 | 需要AGC Profile + ACL权限 + 引导设置 |
| 弹窗能力 | 不能直接申请,只能引导用户去设置 |
1.3 与user_grant权限的对比
| 对比项 | user_grant权限 | manual_settings权限 |
|---|---|---|
| 授权方式 | 弹窗授权 | 手动设置 |
| 申请接口 | requestPermissionsFromUser | openPermissionOnSetting |
| 再次申请 | requestPermissionOnSetting | openPermissionOnSetting |
| AGC配置 | 普通声明即可 | 需要Profile + ACL |
| 敏感程度 | 较高 | 最高 |
二、申请manual_settings权限的流程
2.1 四步走
步骤1:在AGC申请Profile文件并添加ACL权限
↓
步骤2:在module.json5中声明权限
↓
步骤3:运行时检查权限 → 未授权则引导用户去设置
↓
步骤4:处理授权结果
2.2 步骤1:AGC侧申请Profile
因为manual_settings权限级别很高,普通应用默认无法申请,需要通过ACL(访问控制列表)方式申请。
操作步骤:
-
进入"我的应用" → 选择应用
-
进入"用户与权限" → "权限管理"
-
申请发布Profile,并在Profile内添加ACL权限
详细步骤请参考:申请发布Profile
2.3 步骤2:在module.json5中声明权限
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.HOOK_KEY_EVENT",
"reason": "$string:hook_key_event_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
注意:即使是manual_settings权限,也需要填写reason和usedScene字段。
三、核心开发步骤
3.1 导入所需模块
import { abilityAccessCtrl, bundleManager, Permissions, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
3.2 检查权限是否已授权
// PermissionChecker.ets
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;
// 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 checkHookKeyEventPermission(): Promise<void> {
let permission = 'ohos.permission.HOOK_KEY_EVENT';
let grantStatus: boolean = await checkPermissionGrant(permission)
=== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
if (grantStatus) {
// 已经授权,可以继续访问目标操作
console.info('permission is granted.');
this.startHookKeyEvent();
} else {
// 未授权,引导用户跳转到系统设置
console.info('permission is not granted.');
this.guideToPermissionSetting();
}
}
3.3 引导用户跳转到设置页面
方式一:在UIAbility中引导
// OpenPermAbility.ets
import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
function openPermOnSetting(permission: Permissions, context: common.UIAbilityContext): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// openPermissionOnSetting会判断权限的授权状态来决定是否唤起弹窗
atManager.openPermissionOnSetting(context, permission)
.then((data: abilityAccessCtrl.SelectedResult) => {
if (data === abilityAccessCtrl.SelectedResult.REJECTED) {
// 用户不允许跳转到"设置"
console.info('user not allowed.');
} else if (data === abilityAccessCtrl.SelectedResult.OPENED) {
// 用户选择跳转到"设置"
console.info('user allowed to setting.');
} else {
// 权限已授权,无需弹窗
console.info('permission is granted.');
}
})
.catch((err: BusinessError) => {
console.error(`Failed to openPermissionOnSetting, code: ${err.code}, message: ${err.message}`);
});
}
export default class OpenPermAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 重要:需要在loadContent回调中调用
windowStage.loadContent('openpermpages/Index', (err) => {
if (!err) {
openPermOnSetting('ohos.permission.HOOK_KEY_EVENT', this.context);
}
});
}
}
方式二:在UI中引导
// Index.ets
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
function openPermOnSetting(permission: Permissions, context: common.UIAbilityContext): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
atManager.openPermissionOnSetting(context, permission)
.then((data: abilityAccessCtrl.SelectedResult) => {
if (data === abilityAccessCtrl.SelectedResult.REJECTED) {
console.info('user not allowed.');
this.showManualGuide();
} else if (data === abilityAccessCtrl.SelectedResult.OPENED) {
console.info('user allowed to setting.');
// 等待用户从设置返回后重新检查权限
setTimeout(() => {
this.checkPermissionAgain();
}, 1000);
} else {
console.info('permission is granted.');
this.startHookKeyEvent();
}
})
.catch((err: BusinessError) => {
console.error(`Failed to openPermissionOnSetting, code: ${err.code}`);
});
}
@Entry
@Component
struct Index {
@State permissionGranted: boolean = false;
aboutToAppear() {
const context: common.UIAbilityContext =
this.getUIContext().getHostContext() as common.UIAbilityContext;
// 先检查权限状态
this.checkInitialPermission(context);
}
async checkInitialPermission(context: common.UIAbilityContext) {
let granted = await this.checkPermission('ohos.permission.HOOK_KEY_EVENT');
if (granted) {
this.permissionGranted = true;
this.startHookKeyEvent();
} else {
// 未授权,引导用户
this.showPermissionDialog(context);
}
}
showPermissionDialog(context: common.UIAbilityContext) {
AlertDialog.show({
title: '需要键盘输入权限',
message: '应用需要拦截键盘输入事件来实现快捷操作,请在设置中开启权限',
primaryButton: {
value: '去设置',
action: () => {
openPermOnSetting('ohos.permission.HOOK_KEY_EVENT', context);
}
},
secondaryButton: {
value: '暂不'
}
});
}
showManualGuide() {
AlertDialog.show({
message: '您可以在系统设置中手动开启权限:\n设置 → 隐私和安全 → 键盘输入辅助 → 本应用',
primaryButton: {
value: '我知道了'
}
});
}
async checkPermission(permission: string): Promise<boolean> {
// 实现权限检查逻辑
return false;
}
async checkPermissionAgain() {
let granted = await this.checkPermission('ohos.permission.HOOK_KEY_EVENT');
this.permissionGranted = granted;
if (granted) {
this.startHookKeyEvent();
}
}
startHookKeyEvent() {
console.info('开始拦截键盘输入事件');
// 业务逻辑
}
build() {
Column() {
Text(this.permissionGranted ? '权限已开启' : '权限未开启')
.fontSize(16)
.margin(20)
if (!this.permissionGranted) {
Button('再次申请权限')
.onClick(() => {
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
this.showPermissionDialog(context);
})
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
3.4 处理授权结果
调用openPermissionOnSetting()方法后,应用程序需重新校验是否已经授权。
// 权限检查结果处理
if (data === abilityAccessCtrl.SelectedResult.REJECTED) {
// 用户不允许跳转到"设置"
// 可以提示用户手动去设置开启
this.showManualGuide();
} else if (data === abilityAccessCtrl.SelectedResult.OPENED) {
// 用户选择跳转到"设置"
// 等待用户返回后重新检查权限
setTimeout(async () => {
let granted = await this.checkPermission('ohos.permission.HOOK_KEY_EVENT');
if (granted) {
// 用户已授权
this.startHookKeyEvent();
} else {
// 用户仍未授权,继续引导
this.showPermissionDialog(context);
}
}, 1000);
} else {
// 权限已授权,无需弹窗
this.startHookKeyEvent();
}
四、设置路径说明
用户在系统设置中开启权限的路径:
路径一:隐私和安全入口
设置 → 隐私和安全 → 权限类型(如键盘输入辅助) → 某个应用
路径二:应用信息入口
设置 → 应用和元服务 → 某个应用 → 权限类型(如键盘输入辅助)
五、注意事项
5.1 调用时机
| 场景 | 要求 |
|---|---|
| 在UIAbility的onWindowStageCreate中调用 | 需要等待loadContent/setUIContent执行结束后,或在回调中调用 |
| 原因 | 在Content加载完成前,openPermissionOnSetting会调用失败 |
5.2 返回值
openPermissionOnSetting返回的SelectedResult有三种可能:
| 返回值 | 说明 |
|---|---|
| REJECTED | 用户不允许跳转到"设置" |
| OPENED | 用户选择跳转到"设置" |
| 其他 | 权限已授权,无需弹窗 |
更多推荐


所有评论(0)