调用 uni.openSetting 前必须先用 uni.getAuthSetting 检查权限状态:undefined 时应调 uni.authorize,false 时才调 uni.openSetting;iOS 仅跳主设置页,需引导用户手动进入子页;onShow 中须重检权限并更新 UI。

uni.openSetting 调用前必须先确认权限真实拒绝状态
直接调用 uni.openSetting 很可能无反应或报错,尤其在 iOS 首次未授权时——此时 uni.getAuthSetting 返回的 scope.userLocation 等字段是 undefined,不是 false。Android 则可能返回 false(已拒绝)或 undefined(未询问)。不加判断就跳,iOS 会静默失败,Android 可能闪退。
正确做法是:先调 uni.getAuthSetting 拿到结果,再检查对应 scope 是否明确为 false:
- 如果是
false,说明用户点过“拒绝”,此时调uni.openSetting才有效 - 如果是
undefined,说明还没问过,应先调uni.authorize弹原生授权框 - 如果返回
true,权限已开,无需跳转
Android 和 iOS 的跳转行为根本不同
uni.openSetting 在两端表现不一致,不能当成同一功能对待:
- Android:跳转到「设置 > 应用 > [你的App名] > 权限」,可直接开关具体权限(如位置、相机)
- iOS:只跳到「设置 > [你的App名]」主页面,**不会进入权限子页**,用户必须手动点击「隐私与安全性」→「定位服务」等路径才能修改
- iOS 不支持通过 URL Scheme 直达蓝牙、Wi-Fi、通知等二级设置页(系统限制,非 uni-app 能绕过)
这意味着你在 iOS 上引导用户“开启定位”,弹出的只是 App 主设置页,UI 上必须同步提示“请手动进入「定位服务」中开启”。
onShow 中必须重检权限并更新 UI
用户从设置页返回后,权限状态可能已变,但 Vue 组件不会自动刷新。如果你只在 onLoad 或按钮点击时检查一次,UI 就会滞后。
必须在 onShow 生命周期里再次调 uni.getAuthSetting,并根据结果更新按钮文案、禁用状态或隐藏功能入口:
- 比如按钮文字从「去设置」变成「已授权」
- 比如隐藏「使用定位」开关,改为显示当前位置
- 避免用户以为“刚在设置里开了权限,怎么 App 还没反应”
不要依赖 plus.runtime.openURL("app-settings:")
部分老教程提到用 plus.runtime.openURL("app-settings:"),这在 iOS 上看似能跳,但实际有严重问题:
- HBuilderX 3.9+ 和 iOS 16+ 后,该 Scheme 已被系统限制,多数情况直接失败且无提示
- 它不触发
uni.openSetting的 success/fail 回调,无法做后续逻辑(比如重试获取位置) - uni-app 官方文档已明确将
uni.openSetting列为唯一推荐方式,plus方式属于历史兼容层,稳定性差
真要兜底,也只应在 uni.openSetting 的 fail 回调里尝试一次 plus.runtime.openURL,并加日志埋点观察失败率。











