Berita Produk

Pemilih Kontak: Berbagi Kontak yang Mengutamakan Privasi

Waktu baca: 4 menit
Roxanna Aliabadi Walker
Product Manager

Privasi dan kontrol pengguna tetap menjadi inti dari pengalaman Android. Sama seperti pemilih foto yang membuat berbagi media menjadi aman dan mudah diterapkan, kami kini menghadirkan tingkat privasi, kesederhanaan, dan pengalaman pengguna yang sama baiknya untuk pemilihan kontak.

Standar Baru untuk Privasi Kontak

Secara historis, aplikasi yang memerlukan akses ke kontak pengguna tertentu mengandalkan izin READ_CONTACTS yang luas. Meskipun berfungsi, pendekatan ini sering kali memberikan lebih banyak data kepada aplikasi daripada yang diperlukan. Pemilih Kontak Android baru, yang diperkenalkan di Android 17, mengubah dinamika ini dengan menyediakan antarmuka yang standar, aman, dan dapat ditelusuri untuk pemilihan kontak.

Fitur ini memungkinkan pengguna memberikan akses aplikasi hanya ke kontak tertentu yang mereka pilih, yang selaras dengan komitmen Android terhadap transparansi data dan jejak izin yang diminimalkan.

selection.png
picker.png

Cara Kerja

Developer dapat mengintegrasikan Pemilih Kontak menggunakan intent Intent.ACTION_PICK_CONTACTS. API yang diperbarui ini menawarkan beberapa kemampuan yang canggih:

  • Permintaan Data Terperinci: Aplikasi dapat menentukan dengan tepat kolom mana yang mereka butuhkan, seperti nomor telepon atau alamat email, bukan menerima seluruh data kontak.
  • Dukungan Multi-Pemilihan: Pemilih mendukung pemilihan kontak tunggal dan beberapa kontak, sehingga memberikan fleksibilitas yang lebih besar kepada developer untuk fitur seperti undangan grup.
  • Batas Pemilihan: Developer dapat menetapkan batas kustom pada jumlah kontak yang dapat dipilih pengguna dalam satu waktu.
  • Akses Sementara: Setelah pemilihan, sistem akan menampilkan URI Sesi yang memberikan akses baca sementara ke data yang diminta, sehingga memastikan akses tidak berlanjut lebih lama dari yang diperlukan.
  • Akses ke profil lain:  Saat menggunakan intent baru ini, antarmuka akan memungkinkan pengguna memilih konten dari profil pengguna lain seperti profil kerja, profil kloningan, atau ruang pribadi.
  • Performa yang Dioptimalkan: Pemilih Kontak menampilkan satu URI yang memungkinkan kueri hasil kolektif, sehingga tidak perlu mengkueri URI kontak individual secara terpisah seperti yang diperlukan oleh ACTION_PICK. Efisiensi ini lebih lanjut mengurangi overhead sistem dengan menggunakan satu transaksi Binder.

Kompatibilitas Mundur dan Penerapan

Untuk perangkat yang menjalankan Android 17 atau yang lebih tinggi, sistem akan otomatis mengupgrade intent ACTION_PICK lama yang menentukan jenis data kontak ke antarmuka baru yang lebih aman. Namun, untuk memanfaatkan sepenuhnya fitur lanjutan seperti multi-pemilihan, developer sebaiknya memperbarui kode implementasi mereka dan menggunakan ContentResolver untuk mengkueri URI Sesi yang ditampilkan.


Mengintegrasikan pemilih kontakUntuk mengintegrasikan Pemilih Kontak, developer menggunakan intent ACTION_PICK_CONTACTS. Di bawah ini adalah contoh kode yang menunjukkan cara meluncurkan pemilih dan meminta kolom data tertentu, seperti email dan nomor telepon.

  // State to hold the list of selected contacts
var contacts by remember { mutableStateOf<List>(emptyList()) }
// 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
    coroutine.launch {
        contacts = processContactPickerResultUri(resultUri, context)
    }
}
}
// 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 {
putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
putStringArrayListExtra(
EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
requestedFields
)
putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}
// Launch the picker
pickContact.launch(pickContactIntent)

Setelah pengguna melakukan pemilihan, aplikasi akan memproses hasilnya dengan mengkueri URI Sesi yang ditampilkan untuk mengekstrak informasi kontak yang diminta.

  
// Data class representing a parsed Contact with selected details
data class Contact(val id: String, val name: String, val email: String?, val phone: 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._ID,
        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)
    )

    val results = mutableListOf<Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val contactIdIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID)
        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 contactId = cursor.getString(contactIdIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            // Determine if the current row represents an email or a phone number
            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            // Add the parsed contact to our results list
            results.add(Contact(contactId, name, email, phone))
        }
    }

    return@withContext results
}

Lihat dokumentasi lengkapnya di sini.

Praktik Terbaik bagi Developer

Untuk memberikan pengalaman pengguna terbaik dan mempertahankan standar keamanan yang tinggi, sebaiknya lakukan hal berikut:

  • Minimalisasi Data: Hanya minta kolom data tertentu (misalnya, email) yang dibutuhkan aplikasi Anda.
  • Persistensi Langsung: Segera pertahankan data yang dipilih, karena akses URI Sesi bersifat sementara.

Lanjutkan membaca