必须在 manifest.json 的 app-plus.distribute.android.permissions 中以全限定名数组声明权限,如["android.permission.read_contacts"],漏、错或格式不正确将导致 uni.authorize({scope: 'scope.contact'}) 在真机上静默失败;ios 还需配置 nscontactsusagedescription 描述文案,且必须重新云打包生效。

必须在 manifest.json 的 app-plus.distribute.android.permissions 里用全限定名数组声明,漏一个、错一个、格式不对,真机上 uni.authorize({scope: 'scope.contact'}) 就会静默失败,不报错也不弹窗。
Android 权限字段必须写全限定名,不能简写或混用对象
uni-app 打包时不会校验权限字符串是否合法,但 Android 系统在运行时只认标准格式。常见错误包括:
-
"READ_CONTACTS"或"read_contacts"→ 错误,缺前缀 -
{"android.permission.READ_CONTACTS": {}}→ 错误,HBuilderX 只识别数组,对象结构会被忽略 -
"android.permission.GET_ACCOUNTS"单独写 → 不够,READ_CONTACTS才是读取联系人的必要权限(GET_ACCOUNTS是获取账户列表,非必需)
正确写法只有一种:"permissions": ["android.permission.READ_CONTACTS"]。如果还要写入或同步联系人,才加 "android.permission.WRITE_CONTACTS"。
iOS 需额外配 NSContactsUsageDescription 描述文案
Android 只靠 manifest 声明还不够,iOS 还必须在 manifest.json 的 app-plus.distribute.ios.privacyDescription 下配置描述字段,否则首次调用直接 crash:
{
"NSContactsUsageDescription": "我们需要访问您的通讯录,以便您快速选择联系人。"
}
注意:NSContactsUsageDescription 是强制项,文案不能为空,也不能用占位符(如“xxx 功能需要”)。App Store 审核会人工检查该字段是否合理、具体、用户可理解。
别信可视化勾选,改完必须重新云打包才生效
HBuilderX 编辑器右侧面板的“权限勾选”只是快捷生成方式,最终仍转成 permissions 数组。但如果你手动编辑了源码视图里的数组,又没点「发行」→「原生App-云打包」,那改的内容根本不会进 APK:
- 本地运行(
运行到手机或模拟器)不走 manifest 权限校验,容易误以为 OK - 真机安装的 APK 权限以云打包输出为准,和你本地 manifest.json 是否保存成功无关
- 改完后务必清缓存、删旧包、重新云打包,再装新 APK 测试
scope.contact 不等于 READ_CONTACTS,微信小程序要另配
uni-app 的 scope.contact 是跨平台抽象层,但底层实现完全分离:
- App 端:依赖
manifest.json里声明的android.permission.READ_CONTACTS,且运行时调用必须严格匹配字符串 - 微信小程序端:不看 manifest 的 permissions,而是看
mp-weixin.requiredPrivateInfos,必须显式写"getContact"或"chooseContact"(注意不是scope.contact) - 两者配置互不影响,也不能复用;同一份代码在不同平台打包,得分别检查对应配置
最常被忽略的一点:iOS 上即使配了 NSContactsUsageDescription,如果用户首次拒绝后你没在 onShow 里调 uni.getAuthSetting 同步状态,UI 就会卡在“已拒绝”却无提示——这个状态不会自动刷新。











