API 30环境下contentResolver.query查询联系人返回0条数据问题
问题根源
Android 11(API 30)引入了包可见性过滤机制,即使你申请了READ_CONTACTS权限,没有在清单中声明要访问的联系人组件,系统也会拦截你的ContentResolver查询请求,返回空Cursor。你申请的QUERY_ALL_PACKAGES权限完全冗余,该权限仅适用于需要扫描设备所有安装应用的特殊场景,上架应用商店还需要额外提交使用说明,完全不需要用在读取联系人的需求中。
修复步骤
- 修改AndroidManifest配置
在<manifest>节点下(和<application>节点平级)添加如下<queries>声明,无需保留QUERY_ALL_PACKAGES权限:
<queries> <!-- 声明要访问系统联系人Provider --> <provider android:authorities="com.android.contacts" /> </queries>
如果你的联系人选择器用的是ACTION_PICK隐式Intent,也可以用下面的声明:
<queries> <intent> <action android:name="android.intent.action.PICK" /> <data android:mimeType="vnd.android.cursor.dir/contact" /> </intent> </queries>
- 代码优化(非必须,但可规避崩溃)
你当前代码中cursor!!.count的写法有风险,若返回的contactUri为空会直接触发空指针崩溃,可以调整为更安全的判空逻辑:
pickContactCallback = ActivityResultCallback<Uri?> { contactUri: Uri? -> val queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME) contactUri ?: return@ActivityResultCallback // uri为空直接返回 val cursor = requireActivity().contentResolver.query( contactUri, queryFields, null, null, null ) cursor?.use { if (it.count == 0) { return@ActivityResultCallback } it.moveToFirst() val suspect = it.getString(0) Log.d(TAG, "onActivityResult() called - $suspect") crime.suspect = suspect crimeDetailViewModel.saveCrime(crime) suspectButton.text = suspect } }
验证方式
修改完成后卸载模拟器上的旧应用重装,重新授予权限后测试即可正常获取到联系人姓名。
内容的提问来源于stack exchange,提问作者Federico
相关产品推荐
相关产品推荐

