鸿蒙ASCF权限拒绝后openSetting引导设置与状态重置
在鸿蒙 ASCF 开发权限相关功能时,常见现象是:用户拒绝授权后,再调用 has.authorize 不再弹窗,而是直接进入 fail。此时不能继续死等系统弹窗,需要使用设置类 API 把用户引导到元服务设置页,并在返回后重新确认权限状态。ASCF 里主要涉及两个方法:has.openSetting 用来打开元服务设置页,has.getSetting 用来查询已授权的权限列表。一、openSetting 与 getSetting 的分工
has.openSetting 调用后拉起元服务设置页面,用户可在其中手动开启或关闭权限。调用示例:
has.openSetting({
success: (res) => {
console.info('设置页返回:', res);
// res 是用户在设置页操作后的权限状态
},
fail: (err) => {
console.error('打开设置页失败:', err);
}
});
has.getSetting 查询当前已授权的权限列表:
has.getSetting({
success: (res) => {
console.info('已授权权限:', res);
if (res['scope.userLocation']) {
console.info('定位权限已开启');
}
if (res['scope.camera']) {
console.info('相机权限已开启');
}
},
fail: (err) => {
console.error('查询失败:', err);
}
});
返回值是一个对象,key 是 scope 名称,value 是 boolean。只会返回明确授权或拒绝的权限,没申请过的权限不会出现在结果里。两个方法的 success 返回值格式一样,都是 { 'scope.xxx': true/false } 对象。
设置页中显示给用户的权限名称,和代码里的 scope 不一定一样。例如设置页显示“位置信息”“相机”,而代码里是 scope.userLocation、scope.camera。弹窗引导时不要对用户说“请开启 scope.camera”,应说“请开启相机权限”。
二、最容易踩的坑:openSetting 必须先 authorize
openSetting 必须在 has.authorize 之后调用。如果项目从未调用过 authorize,直接调用 openSetting 会报错:
{"errMsg":"operateWXData:fail no authorize"}
也就是说,至少先弹过一次授权弹窗,不管用户同意还是拒绝,之后才能打开设置页。正确顺序是:先 authorize(成功或失败都算),再 openSetting。
三、设置页返回后状态会重置
用户在设置页操作后,之前 authorize 的授权状态会被重置。从设置页返回后,需要重新调用 authorize 或 getSetting 获取最新状态。
同时,openSetting 的 success 回调里的权限状态有些情况下可能不是最新的。保险起见,从设置页返回后再调一次 getSetting 确认。
另外,openSetting 不能代替 authorize。它只是引导用户手动操作,用户可以在设置页选择开启或关闭,开发者无法控制。
getSetting 的另一个限制是:它只返回之前 authorize 过的 scope。从来没申请过的权限不会出现在结果里。要检查某个权限是否已授权,得先 authorize 过一次。
四、典型使用场景
场景一:授权失败后弹窗引导去设置页。这是最常见流程:authorize 失败后调用 has.showModal,用户点“去设置”再调用 has.openSetting。
Page({
getLocationWithGuide() {
has.authorize({
scope: 'scope.userLocation',
success: () => {
has.getLocation({
success: (res) => {
console.info('位置:', res);
}
});
},
fail: (err) => {
console.info('授权失败,引导去设置:', err);
has.showModal({
title: '需要定位权限',
content: '请在设置中开启定位权限,否则无法使用此功能',
confirmText: '去设置',
cancelText: '取消',
success: (modalRes) => {
if (modalRes.confirm) {
has.openSetting({
success: (settingRes) => {
console.info('用户从设置页返回');
}
});
}
}
});
}
});
}
});
场景二:先用 getSetting 检查,未授权再申请。
Page({
checkAndAuthorize() {
has.getSetting({
success: (res) => {
if (res['scope.camera']) {
this.openCamera();
} else {
has.authorize({
scope: 'scope.camera',
success: () => {
this.openCamera();
},
fail: () => {
has.showToast({ title: '需要相机权限' });
}
});
}
}
});
},
openCamera() {
const ctx = has.createCameraContext();
// ...
}
});
场景三:页面加载时检查所有权限状态,适合设置页展示开关。
Page({
data: {
permissions: {
location: false,
camera: false,
microphone: false,
contact: false
}
},
onShow() {
this.checkPermissions();
},
checkPermissions() {
has.getSetting({
success: (res) => {
this.setData({
permissions: {
location: !!res['scope.userLocation'],
camera: !!res['scope.camera'],
microphone: !!res['scope.record'],
contact: !!res['scope.contact']
}
});
}
});
},
goToSetting() {
has.openSetting();
}
});
场景四:结合辅助功能权限。项目若用 has.openAccessibility 做辅助功能检测,用户拒绝后可引导去设置。err.code === 203 表示用户手动关闭了辅助功能。
has.openAccessibility({
success: () => {
console.info('辅助功能已开启');
},
fail: (err) => {
if (err.code === 203) {
has.showModal({
title: '需要辅助功能',
content: '请在设置中开启辅助功能',
confirmText: '去设置',
success: (res) => {
if (res.confirm) {
has.openSetting();
}
}
});
}
}
});
五、完整流程与封装
authorize + openSetting 的流程可以概括为:
调用 has.authorize
├── success → 权限已拿到,继续业务
└── fail
├── 弹窗提示用户
│ ├── 用户点“去设置”
│ │ └── 调用 has.openSetting
│ │ └── 用户在设置页操作
│ │ └── 返回后重新 authorize/getSetting
│ └── 用户点“取消”
│ └── 结束或降级处理
└── getSetting 检查是否还有其他权限需要申请
由于流程固定,可以封装 ensurePermission:
function ensurePermission(scope, scopeName) {
return new Promise((resolve, reject) => {
has.authorize({
scope: scope,
success: () => resolve(),
fail: () => {
has.showModal({
title: '需要' + scopeName + '权限',
content: '请在设置中开启' + scopeName + '权限',
confirmText: '去设置',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
has.openSetting({
success: () => reject(new Error('需要用户重新授权'))
});
} else {
reject(new Error('用户拒绝授权'));
}
}
});
}
});
});
}
async function getLocation() {
try {
await ensurePermission('scope.userLocation', '定位');
const res = await new Promise((resolve, reject) => {
has.getLocation({ success: resolve, fail: reject });
});
return res;
} catch (err) {
console.error(err.message);
}
}
六、调试与落地提醒
在 DevEco Studio 的模拟器上,openSetting 可能表现和真机不一样,建议真机测试。项目里的 openSetting Demo 已经注册到“开放能力”分类下,可以直接体验;getSetting 的示例没有单独做,但文中代码可直接复制使用。
最后记住几个关键点:openSetting 必须在 authorize 之后;设置页返回后授权状态会重置,要重新确认;getSetting 只返回申请过的权限;openSetting 回调状态可能不是最新,必要时用 getSetting 二次确认。
Re: 鸿蒙ASCF权限拒绝后openSetting引导设置与状态重置
感谢楼主分享,写得很清楚。之前也遇到过用户拒绝后 has.authorize 直接进 fail 不弹窗的情况,确实不能一直等系统弹窗。openSetting 之前必须先 authorize 这一点很关键,不然报 no authorize 很容易让人摸不着头脑。还有设置页返回后状态会重置,最好再调一次 getSetting 确认,这个细节也很有用。场景一里先用 showModal 说明原因再引导去设置,比直接拉设置页体验好很多。另外设置页显示名称和 scope 不一样这点也提醒得好,给用户提示时要说相机权限、位置信息权限,别直接说 scope.camera。整体流程先 authorize 再判断,失败后引导 openSetting,返回后再 getSetting 或重新 authorize,思路很顺。收藏了。Re: 鸿蒙ASCF权限拒绝后openSetting引导设置与状态重置
这个整理很实用,几个点都踩在关键上。openSetting 前必须先 authorize,这个坑确实容易忽略,不然直接报 no authorize;从设置页回来后授权状态会重置,不能只看 openSetting 的 success,最好再 getSetting 确认一次。getSetting 只返回之前 authorize 过的 scope,所以没申请过的权限查不到,检查前先走一次 authorize 是必要前置。引导用户时用“相机权限”“位置信息”这种说法,而不是 scope.camera、scope.userLocation,体验会好很多。场景一那种 authorize 失败后 showModal 引导去 openSetting 的流程最常用,场景二先 getSetting 再 authorize 也适合按需申请。整体思路很清晰。Re: 鸿蒙ASCF权限拒绝后openSetting引导设置与状态重置
感谢分享,这块权限流程梳理得很实用。openSetting 必须在 authorize 之后调用、提前授权过哪怕被拒才能进设置页,这个确实容易踩坑;从设置页返回后状态会重置,再调 getSetting 确认也更稳妥。弹窗引导用用户能看懂的名称,不说 scope 名称,这个细节很赞。场景二代码好像没贴完,如果方便可以补全一下,尤其是 openCamera 和授权失败后的处理,整体流程就更完整了。
页:
[1]