O seletor de contatos do Android é uma interface padronizada e navegável para os usuários
compartilharem contatos com seu app. Disponível em dispositivos com
Android 17 ou mais recente, o seletor oferece uma alternativa
que preserva a privacidade à permissão ampla READ_CONTACTS. Em vez de solicitar acesso a toda a agenda de endereços do usuário, seu app especifica os campos de dados necessários, como números de telefone ou endereços de e-mail, e o usuário seleciona contatos específicos para compartilhar. Isso concede ao app acesso de leitura apenas aos dados selecionados, garantindo controle granular e oferecendo uma experiência do usuário consistente com recursos integrados de pesquisa, troca de perfil e seleção múltipla sem precisar criar ou manter a interface.
Integrar o seletor de contatos
Para integrar o seletor de contatos, use a intent Intent.ACTION_PICK_CONTACTS.
Esse intent inicia o seletor e retorna os contatos selecionados para seu app.
Ao contrário do ACTION_PICK legado, o seletor de contatos permite especificar vários
campos de dados que seu app exige ao mesmo tempo. Para isso, use
Intent.EXTRA_REQUESTED_DATA_FIELDS, transmitindo um ArrayList<String> de tipos
MIME definidos em ContactsContract.CommonDataKinds.
Os tipos MIME comuns incluem:
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
Abrir o seletor
Use registerForActivityResult com o contrato StartActivityForResult para
iniciar o seletor. É possível configurar a intenção para permitir seleções únicas ou múltiplas.
Selecionar um único contato
Neste exemplo, o app solicita apenas números de telefone. O seletor vai filtrar a lista para mostrar apenas os contatos com números de telefone e permitir que o usuário selecione um número específico.
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);
Selecionar vários contatos
Para ativar a seleção múltipla, adicione o extra Intent.EXTRA_ALLOW_MULTIPLE. Você pode limitar o número de itens que um usuário pode selecionar.
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)
Processar os resultados
Quando o usuário conclui a seleção, o sistema retorna um RESULT_OK e um URI de sessão. Esse URI concede acesso de leitura temporário aos dados selecionados.
É possível consultar esse URI usando um ContentResolver padrão. O Cursor resultante contém os campos de dados solicitados e segue o esquema de 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")
}
}
}
}
}
Compatibilidade com versões anteriores
Para apps direcionados ao Android 17 e versões mais recentes, o sistema
atualiza automaticamente a intent Intent.ACTION_PICK atual para usar a nova
interface do seletor de contatos.
Se o app já usa ACTION_PICK, não é necessário mudar o código para
receber a nova interface. No entanto, para aproveitar novos recursos, como
receber um único Uri para consultar dados de contato, alternar entre perfis pessoais e
de trabalho ou vários pedidos de campo de dados, atualize sua
implementação para usar Intent.ACTION_PICK_CONTACTS ou os novos extras de intent.
Teste em SDKs mais antigos
Você pode testar o novo comportamento do seletor em dispositivos com Android 17 e
versões mais recentes, mesmo que o app segmente uma versão anterior do SDK, adicionando o
extra booleano EXTRA_USE_SYSTEM_CONTACTS_PICKER à intent ACTION_PICK.
Práticas recomendadas
- Solicite apenas o necessário: se o app só precisar enviar um SMS,
solicite
Phone.CONTENT_ITEM_TYPE. O seletor vai filtrar automaticamente os contatos sem números de telefone, resultando em uma interface mais limpa para o usuário. - Persistir dados imediatamente: o URI da sessão concede permissão temporária de leitura. Se você precisar acessar essas informações de contato mais tarde (depois que o processo do app for encerrado), o app precisará manter os dados de contato.
- Não confie nos dados da conta: para proteger a privacidade do usuário e evitar impressões digitais, os metadados específicos da conta são removidos dos resultados.