uni.getContact 和 uni.chooseContact 不支持 App 端,必须用 plus.contacts;需真机运行、HBuilderX 打包、onLoad 后判断 plus.contacts 是否就绪;iOS/Android 权限与字段差异大,manifest 需配置对应权限;应按需读取字段、异步处理、节流 UI,并通过 uni.getAuthSetting 校验后再调 uni.openSetting。

在 uni-app 中,uni.getContact 和 uni.chooseContact 都不能用于 App 端(iOS/Android)获取通讯录列表——这不是你代码写错了,是这两个 API 根本不支持 App 平台。真机上会静默失败、返回空数组或直接不回调。
App 端唯一可行路径:用 plus.contacts(仅限 app-plus)
这是 HBuilderX 打包时内置的 5+ 引擎能力,不是 npm 包,也不是 Vue 插件,web 和小程序完全不可用。常见错误 Cannot read property 'contacts' of undefined 多半因为:
• 没在真机或模拟器运行(H5 环境无此对象)
• 没用 HBuilderX 正式打包(npm run dev:app 调试可能不生效)
• 在 data 初始化阶段就访问 plus.contacts,此时 plus 还未就绪
• 忘了在 onLoad 或用户点击事件中调用
正确调用前必须加判断:
if (!plus || !plus.contacts) {
uni.showToast({ title: '原生环境未就绪', icon: 'none' });
return;
}
iOS 和 Android 权限与字段差异极大,不能一套代码通吃
两者不仅权限申请方式不同,返回字段结构也完全不一致:
- iOS 必须先调
plus.ios.requestAuthorization(plus.ios.AUTHORIZATION_CONTACTS);Android 用plus.android.requestPermissions(['android.permission.READ_CONTACTS']) - iOS 的
displayName是字符串,Android 可能是数组;phoneNumbers在 iOS 是CNPhoneNumber对象,需用.value.stringValue提取,在 Android 是字符串数组,常含空格或分隔符,得用正则清洗 - manifest.json 必须显式配置:
• iOS:ios → permissions → NSContactsUsageDescription(缺它真机直接 crash)
• Android:android → permissions → android.permission.READ_CONTACTS(Android 12+ 厂商如小米、华为会校验该声明是否存在,哪怕你不真读)
全量读取性能敏感,别在主线程遍历几百个联系人
尤其 Android 上用 ContentResolver 查询 ContactsContract.Contacts,或 iOS 上同步执行 enumerateContactsWithFetchRequestErrorUsingBlock,都极易卡 UI。实际项目中建议:
- 只请求必要字段:
['displayName', 'phoneNumbers'],禁用头像、地址、邮箱等冗余字段 - Android 端务必把游标遍历切到
AsyncTask或Executors.newSingleThreadExecutor() - iOS 真机上加
loading状态 + 节流,避免白屏卡顿 - 返回数据里
phoneNumbers是数组,别直接取[0]—— 用户可能有多个号码,且部分系统(如某些安卓定制 ROM)会把号码存在value字段而非number
用户拒绝权限后,uni.openSetting 不是立刻就能调的
这是最容易踩的坑:授权失败后立刻调 uni.openSetting,iOS 静默失败,Android 可能闪退。系统必须先“记录下拒绝”这个状态,而只有 uni.getAuthSetting 能确认。
正确链路是:
- 先调
uni.authorize({ scope: 'scope.contact' }) - 失败后立即调
uni.getAuthSetting() - 检查返回的
authSetting['scope.contact'] === false - 此时再调
uni.openSetting(),才真正有效
跳转后用户手动开启权限,但 App UI 不会自动更新 —— 你得在 onShow 里再次 uni.getAuthSetting 同步状态,否则按钮还灰着。


















