Pemilih Kontak Android adalah antarmuka standar yang dapat dijelajahi bagi pengguna untuk membagikan kontak ke aplikasi Anda. Tersedia di perangkat yang menjalankan Android 17 (level API 37) atau yang lebih tinggi, pemilih ini menawarkan alternatif yang menjaga privasi untuk izin READ_CONTACTS yang luas. Daripada meminta
akses ke seluruh buku alamat pengguna, aplikasi Anda menentukan kolom data yang
dibutuhkan, seperti nomor telepon atau alamat email, dan pengguna memilih kontak
tertentu untuk dibagikan. Hal ini memberi aplikasi Anda akses baca hanya ke data yang dipilih, memastikan kontrol terperinci sekaligus memberikan pengalaman pengguna yang konsisten dengan kemampuan penelusuran bawaan, penggantian profil, dan multi-seleksi tanpa harus membangun atau memelihara UI.
Mengintegrasikan Pemilih Kontak
Untuk mengintegrasikan Pemilih Kontak, gunakan intent Intent.ACTION_PICK_CONTACTS.
Intent ini meluncurkan pemilih dan menampilkan kontak yang dipilih ke aplikasi Anda.
Tidak seperti ACTION_PICK lama, Pemilih Kontak memungkinkan Anda menentukan beberapa
kolom data yang diperlukan aplikasi Anda secara bersamaan. Anda melakukannya menggunakan
Intent.EXTRA_REQUESTED_DATA_FIELDS, dengan meneruskan ArrayList<String> jenis MIME
yang ditentukan dalam ContactsContract.CommonDataKinds.
Jenis MIME umum meliputi:
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
Meluncurkan pemilih
Gunakan registerForActivityResult dengan kontrak StartActivityForResult untuk meluncurkan pemilih. Anda dapat mengonfigurasi maksud untuk mengizinkan satu atau beberapa
pilihan.
// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult
// Process the result URI in a background thread to fetch all selected contacts
coroutine.launch {
contacts = processContactPickerResultUri(resultUri, context)
}
}
}
Mode pilihan
UI Pemilih Kontak menyesuaikan diri sesuai dengan kolom data yang diminta. Bergantung pada persyaratan ini, pengguna dapat memilih seluruh data kontak jika beberapa kolom diperlukan, atau memilih item data tertentu dari dalam informasi kontak.
Memilih satu kontak
Dalam contoh ini, aplikasi hanya meminta nomor telepon. Pemilih akan memfilter daftar untuk hanya menampilkan kontak dengan nomor telepon dan memungkinkan pengguna memilih nomor tertentu.
// Define the specific contact data fields you need
val requestedFields = arrayListOf(
Email.CONTENT_ITEM_TYPE,
Phone.CONTENT_ITEM_TYPE,
)
// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
putStringArrayListExtra(
EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
requestedFields
)
}
// Launch the picker
pickContact.launch(pickContactIntent)
Memilih beberapa kontak
Untuk mengaktifkan multi-pilihan, tambahkan ekstra Intent.EXTRA_ALLOW_MULTIPLE. Anda dapat
secara opsional membatasi jumlah item yang dapat dipilih pengguna.
val requestedFields = arrayListOf(
Email.CONTENT_ITEM_TYPE,
Phone.CONTENT_ITEM_TYPE,
)
// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
// Enable multi-select
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
// Set limit of selectable contacts
putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
// Define the specific contact data fields you need
putStringArrayListExtra(
EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
requestedFields
)
// Enable this option to only filter contacts that have all the requested data fields
putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}
// Launch the picker
pickContact.launch(pickContactIntent)
Menangani hasil
Saat pengguna menyelesaikan pemilihan, sistem akan menampilkan RESULT_OK dan URI Sesi. URI ini memberikan akses baca sementara ke data yang dipilih.
Anda dapat membuat kueri URI ini menggunakan ContentResolver standar. Cursor yang dihasilkan berisi kolom data yang diminta dan mengikuti skema ContactsContract.Data.
// Data class representing a parsed Contact with selected details.
data class Contact(
val lookupKey: String,
val name: String,
val emails: List<String>,
val phones: List<String>
)
// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number.
private suspend fun processContactPickerResultUri(
sessionUri: Uri,
context: Context
): List<Contact> = withContext(Dispatchers.IO) {
// Define the columns we want to retrieve from the ContactPicker ContentProvider
val projection = arrayOf(
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
)
// We use `LOOKUP_KEY` as a unique ID to aggregate all contact info related to a same person
val contactsMap = mutableMapOf<String, Contact>()
// Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
// We query the URI directly to get the results chosen by the user.
context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
// Get the column indices for our requested projection
val lookupKeyIdx = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)
while (cursor.moveToNext()) {
val lookupKey = cursor.getString(lookupKeyIdx)
val mimeType = cursor.getString(mimeTypeIdx)
val name = cursor.getString(nameIdx) ?: ""
val data1 = cursor.getString(data1Idx) ?: ""
val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null
val existingContact = contactsMap[lookupKey]
if (existingContact != null) {
contactsMap[lookupKey] = existingContact.copy(
emails = if (email != null) existingContact.emails + email else existingContact.emails,
phones = if (phone != null) existingContact.phones + phone else existingContact.phones
)
} else {
contactsMap[lookupKey] = Contact(
lookupKey = lookupKey,
name = name,
emails = if (email != null) listOf(email) else emptyList(),
phones = if (phone != null) listOf(phone) else emptyList()
)
}
}
}
return@withContext contactsMap.values.toList()
}
Kompatibilitas Mundur
Untuk aplikasi yang menargetkan Android 17 (level API 37) dan yang lebih tinggi, sistem
akan otomatis mengupgrade intent Intent.ACTION_PICK yang ada untuk menggunakan antarmuka Pemilih Kontak baru.
Jika aplikasi Anda sudah menggunakan ACTION_PICK, Anda tidak perlu mengubah kode untuk
menerima UI baru. Namun, untuk memanfaatkan fitur baru, seperti menerima satu Uri untuk membuat kueri data kontak, beralih antara profil pribadi & kerja atau beberapa permintaan kolom data, Anda harus memperbarui penerapan untuk menggunakan Intent.ACTION_PICK_CONTACTS atau ekstra intent baru.
Menguji di SDK target yang lebih lama
Anda dapat menguji perilaku pemilih baru di perangkat yang menjalankan Android 17 dan yang lebih tinggi, meskipun aplikasi Anda menargetkan versi SDK yang lebih rendah, dengan menambahkan ekstra boolean EXTRA_USE_SYSTEM_CONTACTS_PICKER ke intent ACTION_PICK Anda.
Praktik terbaik
- Minta hanya yang Anda butuhkan: Jika aplikasi Anda hanya perlu mengirim SMS,
minta
Phone.CONTENT_ITEM_TYPE. Pemilih akan otomatis memfilter kontak yang tidak memiliki nomor telepon, sehingga menghasilkan UI yang lebih bersih bagi pengguna. - Mengelola beberapa entri data per kontak: Kontak individual sering kali berisi berbagai alamat email atau nomor telepon. Untuk membantu memastikan hal ini
disajikan dengan jelas dan intuitif bagi pengguna, sebaiknya kelompokkan
hal tersebut menggunakan
ContactsContract.Contacts.LOOKUP_KEY. Selain itu, Anda dapat mengambil label tertentu untuk setiap entri (seperti kantor atau pribadi) untuk menawarkan opsi pemilihan yang lebih terperinci dalam antarmuka aplikasi Anda. - Mempertahankan data secara langsung: URI Sesi memberikan izin baca sementara. Jika Anda perlu mengakses informasi kontak ini nanti (setelah proses aplikasi Anda dihentikan), aplikasi Anda harus mempertahankan data kontak.
- Jangan mengandalkan Data Akun: Untuk melindungi privasi pengguna dan mencegah sidik jari, metadata khusus akun dihapus dari hasil.