plus.contacts是uni-app中唯一可批量读取通讯录的原生方案,仅限app-plus平台,需正确配置权限、字段白名单及平台差异化处理。
uni-app 里 plus.contacts 是唯一靠谱的通讯录读取方式
uni-app 官方 api(如 uni.choosecontact)只支持「选择一个联系人」,不能批量读取;真要拉整个通讯录列表,必须走 html5+ 原生能力,也就是 plus.contacts。它不是 vue 插件,也不是 npm 包,而是 hbuilderx 打包 app 时内置的 5+ 引擎提供的对象——这意味着:web 和小程序端完全不可用,只适用于 app-plus 平台。
常见错误现象:Cannot read property 'contacts' of undefined,基本都是因为没在真机或模拟器运行,或者没用 HBuilderX 打包(比如直接用 npm run dev:app 启动调试,plus 对象根本不存在)。
- 必须在
onLoad或用户触发事件中调用,不能在data初始化时就访问plus.contacts - Android 6.0+ 和 iOS 都需提前声明权限,否则
plus.contacts.getAddressBook会静默失败 - iOS 上首次调用会弹系统授权框;Android 需先用
plus.android.requestPermissions主动申请,不能只靠manifest.json声明
manifest.json 权限配置写错一行,整个功能就白搭
权限不是“写了就生效”,不同平台字段位置和格式要求极细。Android 要三组 <uses-permission>,iOS 要 NSContactsUsageDescription 描述文案,漏一不可。
典型踩坑点:"permissions": ["contacts"] 这种写法只对 uni.authorize 有效,但对 plus.contacts 完全无效——后者认的是原生权限字符串,不是 scope。
- Android 配置必须放在
app-plus.distribute.android.permissions下,且每项是完整 XML 字符串:"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>" - iOS 配置必须在
app-plus.distribute.ios.privacyDescription.NSContactsUsageDescription,值为中文字符串,不能为空或占位符 - HBuilderX 编译后记得清缓存再真机测试,旧包可能沿用旧 manifest
plus.contacts.find 的字段参数决定你能拿到什么
很多人调用 addressbook.find 后发现 phoneNumbers 是空数组、displayName 是 undefined,问题往往出在字段白名单没写对。
find 第一个参数是字符串数组,它不是“过滤条件”,而是“我要哪些字段”。不写,就啥都拿不到;写错大小写或嵌套路径,对应字段就为 null。
- 基础必填:
["displayName", "phoneNumbers"]——注意是复数,不是phoneNumber - 想拿邮箱:
"emails";地址:"addresses";头像:"photos" - 手机号具体类型可细化,如
"phoneNumbers.mobile"(但兼容性差,部分机型返回空),稳妥起见还是用"phoneNumbers"然后自己遍历.value - 别传
null或空数组,某些 Android 版本会直接报错退出
Android 和 iOS 获取逻辑不能共用一套代码
表面上看 plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE, ...) 两边都能跑,但实际行为差异极大:Android 默认只读手机本地通讯录,SIM 卡需显式传 ADDRESSBOOK_SIM;而 iOS 根本不支持 SIM 卡读取,且对空联系人(无号码)处理更严格。
常见错误现象:iOS 上 contacts 数组长度远小于 Android,甚至为空——大概率是用户通讯录里有大量无号码联系人,而 find 没做数据清洗。
- 务必在
find成功回调里加过滤:contacts.filter(c => c.phoneNumbers && c.phoneNumbers.length) - Android 可额外尝试
plus.contacts.ADDRESSBOOK_SIM读 SIM 卡,但需单独判断权限和可用性 - iOS 不支持
multiple: false强制单选,find总是返回数组,哪怕只有一个匹配项
plus.runtime.getProperty 查版本、用 plus.android.getNativeObj 做兜底、对空结果主动提示引导重试。事情说清了就结束。










