El selector de contactos de Android es una interfaz estandarizada y navegable para que los usuarios
compartan contactos con tu app. Disponible en dispositivos que ejecutan
Android 17 o versiones posteriores, el selector ofrece una alternativa que preserva la privacidad
al permiso amplio READ_CONTACTS. En lugar de solicitar
acceso a toda la libreta de direcciones del usuario, tu app especifica los campos de datos que
necesita, como números de teléfono o direcciones de correo electrónico, y el usuario selecciona contactos
específicos para compartir. Esto le otorga a tu app acceso de lectura solo a los datos seleccionados,
lo que garantiza un control detallado y, al mismo tiempo, proporciona una experiencia del usuario coherente con
capacidades integradas de búsqueda, cambio de perfil y selección múltiple sin
tener que compilar ni mantener la IU.
Integra el selector de contactos
Para integrar el selector de contactos, usa el intent Intent.ACTION_PICK_CONTACTS.
Este intent inicia el selector y muestra los contactos seleccionados en tu app.
A diferencia del ACTION_PICK heredado, el selector de contactos te permite especificar varios
campos de datos que requiere tu app al mismo tiempo. Para ello, usa
Intent.EXTRA_REQUESTED_DATA_FIELDS, pasando un ArrayList<String> de tipos MIME
definidos en ContactsContract.CommonDataKinds.
Entre los tipos MIME comunes, se incluyen los siguientes:
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
Inicia el selector
Usa registerForActivityResult con el contrato StartActivityForResult para
iniciar el selector. Puedes configurar el intent para permitir selecciones únicas o múltiples
selecciones.
Selecciona un solo contacto
En este ejemplo, la app solo solicita números de teléfono. El selector filtrará la lista para mostrar solo los contactos con números de teléfono y permitirá que el usuario seleccione un 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);
Selecciona varios contactos
Para habilitar la selección múltiple, agrega el extra Intent.EXTRA_ALLOW_MULTIPLE. De manera opcional, puedes limitar la cantidad de elementos que puede seleccionar un usuario.
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)
Controla los resultados
Cuando el usuario completa la selección, el sistema muestra un RESULT_OK y un
URI de sesión. Este URI otorga acceso de lectura temporal a los datos seleccionados.
Puedes consultar este URI con un ContentResolver estándar. El resultante
Cursor contiene los campos de datos solicitados y sigue el 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")
}
}
}
}
}
Retrocompatibilidad
En el caso de las apps orientadas a Android 17 y versiones posteriores, el sistema
actualiza automáticamente el intent Intent.ACTION_PICK existente para usar la nueva
interfaz del selector de contactos.
Si tu app ya usa ACTION_PICK, no es necesario que cambies el código para
recibir la nueva IU. Sin embargo, para aprovechar las funciones nuevas, como
recibir un solo Uri para consultar datos de contacto, cambiar entre perfiles personales y
laborales o varias solicitudes de campos de datos, debes actualizar tu
implementación para usar Intent.ACTION_PICK_CONTACTS o los nuevos extras de intent.
Pruebas en SDKs anteriores
Puedes probar el nuevo comportamiento del selector en dispositivos que ejecutan Android 17 y
versiones posteriores, incluso si tu app está orientada a una versión inferior del SDK, agregando el extra booleano
EXTRA_USE_SYSTEM_CONTACTS_PICKER a tu ACTION_PICK intent.
Prácticas recomendadas
- Solicita solo lo que necesitas: Si tu app solo necesita enviar un SMS,
solicita
Phone.CONTENT_ITEM_TYPE. El selector filtrará automáticamente los contactos que no tengan números de teléfono, lo que generará una IU más limpia para el usuario. - Conserva los datos de inmediato: El URI de sesión otorga permiso de lectura temporal Si necesitas acceder a esta información de contacto más adelante (después de que se finalice el proceso de tu app), tu app debe conservar los datos de contacto.
- No dependas de los datos de la cuenta: Para proteger la privacidad del usuario y evitar la huella digital, se quitan los metadatos específicos de la cuenta de los resultados.