Trình chọn danh bạ Android là một giao diện tiêu chuẩn mà người dùng có thể duyệt để chia sẻ danh bạ với ứng dụng của bạn. Trình chọn này có trên các thiết bị chạy Android 17 trở lên và là một giải pháp thay thế giúp bảo vệ quyền riêng tư cho quyền READ_CONTACTS trên diện rộng. Thay vì yêu cầu quyền truy cập vào toàn bộ sổ địa chỉ của người dùng, ứng dụng của bạn sẽ chỉ định các trường dữ liệu mà ứng dụng cần, chẳng hạn như số điện thoại hoặc địa chỉ email, và người dùng sẽ chọn những người liên hệ cụ thể để chia sẻ. Điều này chỉ cấp cho ứng dụng của bạn quyền đọc đối với dữ liệu đã chọn, đảm bảo quyền kiểm soát chi tiết trong khi mang đến trải nghiệm nhất quán cho người dùng với các chức năng tìm kiếm, chuyển đổi hồ sơ và chọn nhiều mục được tích hợp sẵn mà không cần phải tạo hoặc duy trì giao diện người dùng.
Tích hợp Trình chọn người liên hệ
Để tích hợp Trình chọn người liên hệ, hãy dùng ý định Intent.ACTION_PICK_CONTACTS.
Ý định này sẽ khởi chạy trình chọn và trả về các số liên hệ đã chọn cho ứng dụng của bạn.
Không giống như ACTION_PICK cũ, Trình chọn người liên hệ cho phép bạn chỉ định nhiều trường dữ liệu mà ứng dụng của bạn yêu cầu cùng một lúc. Bạn thực hiện việc này bằng cách sử dụng Intent.EXTRA_REQUESTED_DATA_FIELDS, truyền một ArrayList<String> gồm các loại MIME được xác định trong ContactsContract.CommonDataKinds.
Các loại MIME phổ biến bao gồm:
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
Khởi chạy bộ chọn
Sử dụng registerForActivityResult với hợp đồng StartActivityForResult để khởi chạy công cụ chọn. Bạn có thể định cấu hình ý định để cho phép chọn một hoặc nhiều lựa chọn.
Chọn một người liên hệ
Trong ví dụ này, ứng dụng chỉ yêu cầu số điện thoại. Trình chọn sẽ lọc danh sách để chỉ hiện những người liên hệ có số điện thoại và cho phép người dùng chọn một số điện thoại cụ thể.
Kotlin
// Define the specific data fields you need
val requestedFields = arrayListOf(
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
)
// Set up the intent
val pickContactIntent = Intent(Intent.ACTION_PICK_CONTACTS).apply {
type = ContactsContract.Contacts.CONTENT_TYPE
putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS, requestedFields)
}
// Launch the picker
pickContactLauncher.launch(pickContactIntent)
Java
// Define the specific data fields you need
ArrayList<String> requestedFields = new ArrayList<>();
requestedFields.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
// Set up the intent
Intent pickContactIntent = new Intent(Intent.ACTION_PICK_CONTACTS);
pickContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);
pickContactIntent.putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS,
requestedFields);
// Launch the picker
pickContactLauncher.launch(pickContactIntent);
Chọn nhiều người liên hệ
Để bật chế độ chọn nhiều, hãy thêm phần bổ sung Intent.EXTRA_ALLOW_MULTIPLE. Bạn có thể tuỳ ý giới hạn số lượng mục mà người dùng có thể chọn.
Kotlin
val requestedFields = arrayListOf(
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
)
val pickMultipleIntent = Intent(Intent.ACTION_PICK_CONTACTS).apply {
type = ContactsContract.Contacts.CONTENT_TYPE
putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS, requestedFields)
// Enable multi-select
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
// Optional: Set a custom limit (max 50 recommended)
putExtra(Intent.EXTRA_SELECTION_LIMIT, 10)
}
pickMultipleLauncher.launch(pickMultipleIntent)
Xử lý kết quả
Khi người dùng hoàn tất việc chọn, hệ thống sẽ trả về một RESULT_OK và một URI phiên. URI này cấp quyền đọc tạm thời cho dữ liệu đã chọn.
Bạn có thể truy vấn URI này bằng cách sử dụng ContentResolver tiêu chuẩn. Cursor thu được chứa các trường dữ liệu được yêu cầu và tuân theo giản đồ của ContactsContract.Data.
Kotlin
private val pickContactLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// The result data contains the Session URI
val sessionUri = result.data?.data
sessionUri?.let { uri ->
processSelectedContacts(uri)
}
} else {
// User cancelled the picker
}
}
private fun processSelectedContacts(sessionUri: Uri) {
// Define the projection (columns) you want to retrieve
val projection = arrayOf(
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.DATA1 // Generic data column (Phone number, Email, etc.)
)
contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
val dataIdx = cursor.getColumnIndex(ContactsContract.Data.DATA1)
val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
while (cursor.moveToNext()) {
val mimeType = cursor.getString(mimeTypeIdx)
val dataValue = cursor.getString(dataIdx)
val name = cursor.getString(nameIdx)
when (mimeType) {
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
Log.d("ContactPicker", "Picked Phone: $dataValue for $name")
}
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> {
Log.d("ContactPicker", "Picked Email: $dataValue for $name")
}
}
}
}
}
Khả năng tương thích ngược
Đối với các ứng dụng nhắm đến Android 17 trở lên, hệ thống sẽ tự động nâng cấp ý định Intent.ACTION_PICK hiện có để sử dụng giao diện Trình chọn danh bạ mới.
Nếu ứng dụng của bạn đã sử dụng ACTION_PICK, thì bạn không cần thay đổi mã để nhận giao diện người dùng mới. Tuy nhiên, để tận dụng các tính năng mới, chẳng hạn như nhận một Uri để truy vấn dữ liệu liên hệ, chuyển đổi giữa hồ sơ cá nhân và hồ sơ công việc hoặc nhiều yêu cầu về trường dữ liệu, bạn phải cập nhật quá trình triển khai để sử dụng Intent.ACTION_PICK_CONTACTS hoặc các phần bổ sung ý định mới.
Kiểm thử trên các SDK cũ
Bạn có thể kiểm thử hành vi mới của bộ chọn trên các thiết bị chạy Android 17 trở lên ngay cả khi ứng dụng của bạn nhắm đến một phiên bản SDK thấp hơn bằng cách thêm phần bổ sung boolean EXTRA_USE_SYSTEM_CONTACTS_PICKER vào ý định ACTION_PICK.
Các phương pháp hay nhất
- Chỉ yêu cầu những gì bạn cần: Nếu ứng dụng của bạn chỉ cần gửi một tin nhắn SMS, hãy yêu cầu
Phone.CONTENT_ITEM_TYPE. Trình chọn sẽ tự động lọc ra những người liên hệ không có số điện thoại, giúp người dùng có giao diện người dùng gọn gàng hơn. - Duy trì dữ liệu ngay lập tức: URI phiên cấp quyền đọc tạm thời. Nếu cần truy cập thông tin liên hệ này sau (sau khi quy trình ứng dụng của bạn bị huỷ), ứng dụng của bạn phải duy trì dữ liệu liên hệ.
- Không dựa vào Dữ liệu tài khoản: Để bảo vệ quyền riêng tư của người dùng và ngăn chặn việc nhận dạng vân tay, siêu dữ liệu dành riêng cho tài khoản sẽ bị xoá khỏi kết quả.