本文档面向集成本插件的 App 开发者,说明 必须遵守的约束、推荐做法 和 上架审核注意事项。
requestPermission / requestPermissions 必须由真实用户手势触发,例如按钮 click / tap。
<!-- ✅ 正确 -->
<button @click="handleRequestCamera">申请相机权限</button>
<!-- ❌ 错误:页面 onLoad / onShow 自动批量申请 -->
<script setup>
onMounted(async () => {
await requestPermissions(['camera', 'microphone', 'location']) // 体验差,可能被系统限制
})
</script>
原因:Android / iOS / Harmony 运行时权限弹窗均面向用户明确操作;冷启动批量申请易触发拒绝,且不符合各应用商店审核惯例。
仅安装插件不够,必须在各端配置文件中声明所需权限,否则:
| 平台 | 未声明后果 |
|---|---|
| Android | SecurityException、申请无弹窗或直接失败 |
| iOS | 崩溃或无授权弹窗 |
| Harmony | 系统设置无对应开关,插件返回 restricted 或 9020003 |
详细配置见 权限配置说明.md。
只申请业务实际使用的权限。在功能入口处按需 requestPermission,不要一次性申请全部权限。
// ✅ 审核页
async function handleRequestCamera() {
const granted = await requestPermission('camera')
if (!granted) {
uni.showModal({
title: '需要相机权限',
content: getPermissionSettingsGuide('camera', '相机'),
confirmText: '去设置',
success: (res) => {
if (res.confirm) openPermissionSettings('camera')
},
})
return
}
// 继续业务逻辑
}
调用前可通过 getSupportedPermissions() 过滤当前平台不支持的 Key,避免向用户展示无效入口。
const supported = getSupportedPermissions()
const canUseOverlay = supported.includes('overlay') // 仅 Android 为 true
进入功能页
↓
checkPermission(key) ──→ granted → 执行业务
↓ notDetermined / denied
用户点击「申请权限」
↓
requestPermission(key)
↓
系统弹窗 ──→ 拒绝 → getPermissionSettingsGuide + openPermissionSettings
↓ 同意
granted → 执行业务
项目可复用 @/utils/permission-manager.js:
import {
checkPermission,
requestPermission,
requestPermissions,
openPermissionSettings,
getPermissionSettingsGuide,
ensurePermission,
getSupportedPermissions,
} from '@/utils/permission-manager'
| 方法 | 用途 |
|---|---|
checkPermission(key) |
检查状态,返回 { granted, status } |
requestPermission(key) |
申请权限,返回 boolean |
requestPermissions(keys[]) |
批量申请,返回 { allGranted, results } |
openPermissionSettings(key) |
按权限类型跳转系统设置 |
getPermissionSettingsGuide(key, label) |
获取跳转前的引导文案 |
ensurePermission(key, { openSettings }) |
检查 → 申请 → 可选跳转设置 |
import { requestPermission } from '@/uni_modules/m-permission-manager'
requestPermission({
permission: 'camera',
success(res) {
if (res.granted) { /* ... */ }
},
fail(err) {
console.error(err.errCode, err.errMsg)
},
})
用户选择「不再询问」或多次拒绝后,应引导至系统设置:
const granted = await requestPermission('bluetooth')
if (!granted) {
uni.showModal({
title: '蓝牙权限未授予',
content: getPermissionSettingsGuide('bluetooth', '蓝牙'),
confirmText: '去设置',
success: (res) => {
if (res.confirm) openPermissionSettings('bluetooth')
},
})
}
各端跳转行为:
| 平台 | openPermissionSettings 行为 |
|---|---|
| Android 普通权限 | 应用详情 → 权限列表 |
Android overlay |
悬浮窗权限设置页 |
Android writeSettings |
修改系统设置权限页 |
| iOS | 本 App 设置页(需 manifest 声明对应 UsageDescription) |
| Harmony | 系统设置 → 应用详情 |
READ_MEDIA_IMAGES / READ_MEDIA_VIDEOBLUETOOTH_CONNECT / BLUETOOTH_SCANoverlay、writeSettings 需跳转系统设置页,申请结果可能为 notDetermined,返回后需再次 checkPermissionprivacyDescription 中配置对应 NS*UsageDescription,否则无弹窗storage / readStorage 映射到相册权限(PHPhotoLibrary)coarseLocation / location 均映射到定位授权NSBluetoothAlwaysUsageDescription;系统蓝牙开关在「设置 → 蓝牙」,App 授权在 App 设置页或「隐私与安全性 → 蓝牙」module.json5 含 5 项 normal 权限,调试包可直接安装system_basic,需 ACL 签名 + module.full.json5uni.chooseImage(系统 PhotoViewPicker),无需媒体读写权限restricted,申请返回 9020003| errCode | 含义 | 建议提示 |
|---|---|---|
| 9020001 | 当前环境不支持 | 请在 App 端使用 |
| 9020002 | 用户拒绝授权 | 您拒绝了授权,可在设置中重新开启 |
| 9020003 | 权限不支持当前平台 | 当前平台不支持该权限 |
| 9020004 | 打开系统设置失败 | 无法打开系统设置,请手动前往 |
| 9020005 | 权限检查失败 | 权限检查失败,请重试 |
| 9020006 | 权限申请失败 | 权限申请失败,请重试 |
| 市场 | 注意点 |
|---|---|
| App Store | 每个 NS*UsageDescription 文案需与真实功能一致;不要申请未使用的权限 |
| Google Play | 需在 Data safety 中声明权限用途;Android 13+ 媒体权限需按类型声明 |
| 华为 / 鸿蒙 | 说明 ohos.permission.* 用途;system_basic 权限需 ACL 白名单 |
| 国内 Android 市场 | 隐私合规检测会扫描 manifest 权限列表,确保与隐私政策一致 |
manifest.json 权限或鸿蒙 module.json5 后,需重新打包privacyDescription 后需重新打包,必要时删除旧 App 重装以重新触发授权弹窗