You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API 30环境下contentResolver.query查询联系人返回0条数据问题

问题根源

Android 11(API 30)引入了包可见性过滤机制,即使你申请了READ_CONTACTS权限,没有在清单中声明要访问的联系人组件,系统也会拦截你的ContentResolver查询请求,返回空Cursor。你申请的QUERY_ALL_PACKAGES权限完全冗余,该权限仅适用于需要扫描设备所有安装应用的特殊场景,上架应用商店还需要额外提交使用说明,完全不需要用在读取联系人的需求中。

修复步骤

  1. 修改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>
  1. 代码优化(非必须,但可规避崩溃)
    你当前代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 11:06:03