从Android 11开始,出于隐私考虑,Google已经限制了第三方应用程序访问电话号码 在 Android 10 中,可以通过查询ContactsContract.CommonDataKinds.Phone.NUMBER来获取电话号码。但是,从 Android 11 开始,该列始终返回空值。
- 先在 AndroidManifest.xml 文件中添加 READ_CONTACTS 权限。
<uses-permission android:name="android.permission.READ_CONTACTS" />
- 下面请求使用
ActivityResultLauncher
API仅适用于androidx.activity
和androidx.fragment
包,如果项目中没有引入这两个库,先在build.gradle
文件中添加以下依赖项:
dependencies {
// ...
implementation "androidx.activity:activity-ktx:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.3.6"
}
- 完整示例代码
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 资源了 :)