Android 选择联系人并返回手机号等信息(适配安卓11+)

从Android11开始,由于隐私政策改变,第三方应用无法直接通过ContactsContract获取电话号码。需在AndroidManifest.xml中添加READ_CONTACTS权限,并使用ActivityResultLauncherAPI请求权限和选择联系人。示例代码展示了如何在Fragment中实现这一功能。
摘要由CSDN通过智能技术生成

从Android 11开始,出于隐私考虑,Google已经限制了第三方应用程序访问电话号码 在 Android 10 中,可以通过查询ContactsContract.CommonDataKinds.Phone.NUMBER来获取电话号码。但是,从 Android 11 开始,该列始终返回空值。

  1. 先在 AndroidManifest.xml 文件中添加 READ_CONTACTS 权限。
<uses-permission android:name="android.permission.READ_CONTACTS" />
  1. 下面请求使用 ActivityResultLauncher API仅适用于 androidx.activityandroidx.fragment 包,如果项目中没有引入这两个库,先在 build.gradle 文件中添加以下依赖项:
dependencies {
    // ...
    implementation "androidx.activity:activity-ktx:1.3.1"
    implementation "androidx.fragment:fragment-ktx:1.3.6"
}
  1. 完整示例代码
class MyFragment : Fragment() {

    private val contactsPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        if (isGranted) {
            selectContactLauncher.launch(null)
        }
    }

    private val selectContactLauncher = registerForActivityResult(ActivityResultContracts.PickContact()) { uri ->
        uri?.let {
            val contactName = getContactName(it)
            val phoneNumber = getContactPhoneNumber(it)
            if (contactName != null && phoneNumber != null) {
                Toast.makeText(requireContext(), "Contact selected: $contactName, phone number: $phoneNumber", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(requireContext(), "Failed to retrieve contact information", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun getContactName(contactUri: Uri): String? {
        val cursor = requireActivity().contentResolver.query(contactUri, null, null, null, null)
        cursor?.use {
            if (it.moveToFirst()) {
                val nameIndex = it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
                return it.getString(nameIndex)
            }
        }
        return null
    }

private fun getContactPhoneNumber(contactUri: Uri?): String? {
    if (contactUri == null) {
        return null
    }
    val projection = arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER)
    val selection = "${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} = ?"
    val selectionArgs = arrayOf(ContentUris.parseId(contactUri).toString())
    val cursor = requireActivity().contentResolver.query(
        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
        projection,
        selection,
        selectionArgs,
        null
    )
    cursor?.use {
        if (it.moveToFirst()) {
            val phoneNumberIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
            return it.getString(phoneNumberIndex)
        }
    }
    return null
}

    private fun requestContactsPermission() {
        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
            selectContactLauncher.launch(null)
        } else {
            contactsPermissionLauncher.launch(Manifest.permission.READ_CONTACTS)
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // ...
        // 当用户单击按钮时请求读取联系人的权限并选择一个联系人
        myButton.setOnClickListener {
            requestContactsPermission()
        }
        // ...
    }
}

多嘴一句 由于use函数实现“try-with-resources”语句,use函数会在代码块完成时自动关闭资源,所以不用手动释放cursor 资源了 :)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值