[HTML payload içeriği buraya]
26.6 C
Jakarta
Wednesday, March 25, 2026

Android Builders Weblog: Contact Picker: Privateness-First Contact Sharing



Posted by Roxanna Aliabadi Walker, Senior Product Supervisor

Privateness and consumer management stay on the coronary heart of the Android expertise. Simply because the picture picker made media sharing safe and straightforward to implement, we at the moment are bringing that very same degree of privateness, simplicity, and nice consumer expertise to contact choice.

A New Commonplace for Contact Privateness

Traditionally, functions requiring entry to a selected consumer’s contacts relied on the broad READ_CONTACTS permission. Whereas purposeful, this strategy usually granted apps extra knowledge than obligatory. The brand new Android Contact Picker, launched in Android 17, adjustments this dynamic by offering a standardized, safe, and searchable interface for contact choice.

This function permits customers to grant apps entry solely to the particular contacts they select, aligning with Android’s dedication to knowledge transparency and minimized permission footprints.

How It Works

Builders can combine the Contact Picker utilizing the Intent.ACTION_PICK_CONTACTS intent. This up to date API provides a number of highly effective capabilities:

  • Granular Information Requests: Apps can specify precisely which fields they want, reminiscent of cellphone numbers or e mail addresses, fairly than receiving the whole contact file.
  • Multi-Choice Help: The picker helps each single and a number of contact alternatives, giving builders extra flexibility for options like group invites.
  • Choice Limits: Builders can set customized limits on the variety of contacts a consumer can choose at one time.
  • Non permanent Entry: Upon choice, the system returns a Session URI that gives non permanent learn entry to the requested knowledge, guaranteeing that entry doesn’t persist longer than obligatory.
  • Entry to different profiles: When utilizing this new intent, the interface will enable customers to pick out contents from different consumer profiles reminiscent of a piece profile, cloned profile or a non-public house.
  • Optimized Efficiency: The Contact Picker returns a single Uri that enables for collective end result querying, eliminating the necessity to question particular person contact Uri individually as required by ACTION_PICK. This effectivity additional reduces system overhead by using a single Binder transaction.

Backward Compatibility and Implementation

For units operating Android 17 or larger, the system routinely upgrades legacy ACTION_PICK intents that specify contact knowledge sorts to the brand new, safer interface. Nevertheless, to take full benefit of superior options like multi-selection, builders are inspired to replace their implementation code and make the most of the ContentResolver to question the returned Session URI.


Combine the contact pickerTo combine the Contact Picker, builders use the 
 ACTION_PICK_CONTACTS intent. Beneath is a code instance demonstrating the right way to launch the picker and request particular knowledge fields, reminiscent of e mail and cellphone numbers.


// State to carry the listing of chosen contacts
var contacts by keep in mind { mutableStateOf<Listing<Contact>>(emptyList()) }

// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
    if (it.resultCode == Exercise.RESULT_OK) {
        val resultUri = it.knowledge?.knowledge ?: return@rememberLauncherForActivityResult

        // Course of the end result URI in a background thread
        coroutine.launch {
            contacts = processContactPickerResultUri(resultUri, context)
        }
    }
}

// Outline the particular contact knowledge fields you want
val requestedFields = arrayListOf(
    E mail.CONTENT_ITEM_TYPE,
    Cellphone.CONTENT_ITEM_TYPE,
)

// Arrange 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)

After the consumer makes a variety, the app processes the end result by querying the returned Session URI to extract the requested contact data.


// Information class representing a parsed Contact with chosen particulars
knowledge class Contact(val id: String, val identify: String, val e mail: String?, val cellphone: String?)

// Helper perform to question the content material resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact particulars reminiscent of identify, e mail, and cellphone quantity
non-public droop enjoyable processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): Listing<Contact> = withContext(Dispatchers.IO) {
    // Outline the columns we need to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Information.MIMETYPE, // Sort of knowledge (e.g., e mail or cellphone)
        ContactsContract.Information.DATA1, // The precise knowledge (Cellphone quantity / E mail string)
    )

    val outcomes = mutableListOf<Contact>()

    // Be aware: The Contact Picker Session Uri would not assist customized choice & selectionArgs.
    context.contentResolver.question(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.Information.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Information.DATA1)

        whereas (cursor.moveToNext()) {
            val contactId = cursor.getString(contactIdIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val identify = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            // Decide if the present row represents an e mail or a cellphone quantity
            val e mail = if (mimeType == E mail.CONTENT_ITEM_TYPE) data1 else null
            val cellphone = if (mimeType == Cellphone.CONTENT_ITEM_TYPE) data1 else null

            // Add the parsed contact to our outcomes listing
            outcomes.add(Contact(contactId, identify, e mail, cellphone))
        }
    }

    return@withContext outcomes
}

Take a look at the total documentation right here.

Greatest Practices for Builders

To supply one of the best consumer expertise and preserve excessive safety requirements, we advocate the next:

  • Information Minimization: Solely request the particular knowledge fields (e.g., e mail) your app wants.
  • Rapid Persistence: Persist chosen knowledge instantly, because the Session URI entry is non permanent.


Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles