Una forma más confiable de agregar y editar contactos en Android
Lectura de 6 min
¿Qué cambiará?
Las apps que se orienten a la próxima versión de Android ya no podrán escribir directamente en los contactos con el permiso WRITE_CONTACTS. En su lugar, puedes usar los intents de contacto estándar (ACTION_INSERT, ACTION_EDIT y ACTION_INSERT_OR_EDIT). Para obtener una implementación de referencia completa, consulta la guía para desarrolladores sobre cómo modificar contactos con intents.
En los dispositivos que ejecuten la próxima versión de Android, estos tres intents de contactos se comportarán de manera coherente y no necesitarán ningún permiso. Si tu app se orienta a la próxima versión de Android o una posterior, y trata de escribir en los contactos directamente, esas operaciones de escritura se rechazarán y generarán una SecurityException o una denegación de permiso. Para el pequeño conjunto de apps que requieren acceso amplio para crear y modificar contactos, se incluye un nuevo permiso especial de acceso a la app, MANAGE_CONTACTS, en Android 17 QPR2 (4º trimestre de 2026). Hoy, Google Play publicará lineamientos actualizados para el acceso a los contactos, incluido MANAGE_CONTACTS.
Por qué hacemos esto
Actualmente, si tu app necesita guardar incluso un solo contacto, es posible que solicites WRITE_CONTACTS. Sin embargo, ese permiso otorga un acceso amplio, lo que permite que una app realice cambios generalizados en los contactos de todo el dispositivo en segundo plano, incluso sin la interacción del usuario. La mayoría de las apps no necesitan un permiso tan amplio.
Si bien existen alternativas, nos comentaron que deben estar más estandarizadas en todo el ecosistema. Anteriormente, los intents de contacto se comportaban de manera diferente de un dispositivo a otro. Algunos editores descartaron los datos que pasaste, como una foto de contacto. En algunos dispositivos, el botón Atrás guardaba el contacto sin que el usuario lo quisiera o la opción "Crear contacto nuevo" era difícil de encontrar. Por lo tanto, pedir permiso era la opción racional. Estamos corrigiendo todos estos problemas en la próxima versión de Android y exigiendo que los dispositivos que la ejecuten sigan los mismos estándares.
Qué usar en su lugar
Cómo agregar o editar un contacto: Usa los intents de contacto
Cuando usas estos intents (ACTION_INSERT, ACTION_EDIT y ACTION_INSERT_OR_EDIT), el sistema se encarga del trabajo pesado y presenta una experiencia de edición de contactos limpia y estandarizada. Se abre un formulario rápido de media hoja para las entradas nuevas o permite que el usuario busque y agregue información fácilmente a un contacto existente. Los usuarios pueden expandir esto sin problemas a un editor de página completa para completar más detalles, todo sin que tu app necesite permisos de escritura directos. Consulta las simulaciones de UX tentativas a continuación:
Figura 1: Crea un contacto nuevo *La UX no es definitiva*
Figura 2: Agrega información a un contacto existente *UX no final*
Nota: Es posible que los diferentes fabricantes de dispositivos modifiquen la experiencia del usuario para que coincida con el estilo de su SO, pero el comportamiento seguirá siendo el mismo.
Puedes optimizar aún más el proceso de creación pasando cargas útiles de datos opcionales, conocidas como extras, junto con tu intent:
EXTRA_ACCOUNTsugiere en qué cuenta se guarda el contacto, lo que resulta útil si tu app sincroniza contactos. Este extra ya existía, pero la compatibilidad variaba según el dispositivo. A partir de la próxima versión de Android, la compatibilidad se estandarizará en todos los dispositivos.EXTRA_PHOTO_URIpasa una foto para precompletar la imagen del contacto. El editor controla el permiso de lectura del URI por ti. Esta es una novedad de la próxima versión de Android y será compatible con todo el ecosistema.
Antes: Escritura directa con
// Requires android.permission.WRITE_CONTACTS fun saveContactDirectly(context: Context, name: String, phone: String, account: Account) { val ops = arrayListOf( ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, account.name) .build(), ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE ) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) .build(), ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .build() ) context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) }
| Después: Se abre el editor de contactos (No se necesita permiso.)
fun saveContactWithEditor( context: Context, name: String, phone: String, account: Account, photoUri: Uri ) { val intent = Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI).apply { putExtra(ContactsContract.Intents.Insert.NAME, name) putExtra(ContactsContract.Intents.Insert.PHONE, phone) // Suggest which account the contact is saved to putExtra(ContactsContract.Intents.Insert.EXTRA_ACCOUNT, account) // New in the upcoming Android release: pre-fill the contact photo putExtra(ContactsContract.Intents.Insert.EXTRA_PHOTO_URI, photoUri) clipData = ClipData.newRawUri("", photoUri) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } context.startActivity(intent) }
|
Antes: Actualizar un contacto existente directamente
// Requires android.permission.WRITE_CONTACTS fun addPhoneDirectly(context: Context, rawContactId: Long, phone: String) { val values = ContentValues().apply { put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } context.contentResolver.insert(ContactsContract.Data.CONTENT_URI, values) } | Después: Permitir que el usuario elija un contacto para actualizar o crear uno nuevo fun addPhoneWithEditor(context: Context, phone: String) { val intent = Intent(Intent.ACTION_INSERT_OR_EDIT).apply { type = ContactsContract.Contacts.CONTENT_ITEM_TYPE putExtra(ContactsContract.Intents.Insert.PHONE, phone) } context.startActivity(intent) } Si ya sabes qué contacto actualizar, usa fun editKnownContact(context: Context, contactUri: Uri, phone: String) { val intent = Intent(Intent.ACTION_EDIT, contactUri).apply { putExtra(ContactsContract.Intents.Insert.PHONE, phone) } context.startActivity(intent) }
|
Cómo elegir un contacto: Usa el Selector de contactos
Si solo necesitas leer los contactos que elige el usuario, usa el Selector de contactos, disponible desde Android 17. No necesita ningún permiso.
Apps de llamadas y mensajería: Usa el Directorio de personas
Algunas apps agregan acciones como "Llamar con…" o "Enviar mensaje con…" a los contactos para que las personas puedan iniciar una llamada o un chat desde la app de Teléfono o Contactos. Si tu app hace esto hoy escribiendo entradas adicionales en los contactos del usuario, migra al Directorio de personas, que llegará en Android QPR2 (4º trimestre de 2026). Es un nuevo directorio del sistema en el que tu app publica cómo las personas pueden comunicarse entre sí en tu app, sin editar los contactos del usuario.
Ejemplos de cómo pueden migrar las apps
Para ver cómo funcionan estas alternativas en la práctica, aquí tienes algunos ejemplos de cómo diferentes tipos de apps pueden abordar el acceso a los contactos:
| Ejemplo de tipo de app (no exclusivo). | Ruta de migración recomendada |
| Apps de redes sociales, pagos P2P y viajes compartidos | Si tu app permite que los usuarios encuentren amigos, dividan una cuenta o compartan el estado de un viaje, no necesitas permisos para acceder a los contactos. Usa el selector de contactos para seleccionar un contacto una sola vez y, luego, inicia ACTION_INSERT con EXTRA_PHOTO_URI cuando un usuario presione "Guardar en Contactos" en un perfil. |
| Apps de escáneres de tarjetas de presentación y de redes de eventos | Si tu app escanea un pase o un código QR y guarda un contacto nuevo, o agrega un número de teléfono laboral a la entrada de un colega existente, usa ACTION_INSERT o ACTION_INSERT_OR_EDIT. El editor estandarizado de media hoja precompleta los campos analizados (nombre, empresa, teléfono, correo electrónico y foto) para que el usuario pueda verificar y guardar con un solo toque sin otorgar permisos en segundo plano. |
| Apps de mensajería y llamadas de VoIP | En lugar de solicitar que WRITE_CONTACTS inserte filas personalizadas de "Llamar con…" o "Enviar mensaje con…" en la libreta de direcciones del usuario, publica metadatos de accesibilidad a través del Directorio de personas y usa ACTION_INSERT cuando los usuarios agreguen un contacto nuevo desde un hilo de chat. |
| Apps de CRM empresarial y sincronización en la nube | Si tu app realiza una sincronización continua y bidireccional de contactos en segundo plano con una cuenta empresarial o de nube, en la que no es posible mostrarle al usuario una IU de intent para cada registro, tu app cumple con los requisitos para declarar MANAGE_CONTACTS . |
Cambios que se deben verificar
- No se admiten los tipos de datos personalizados en el editor. Si pasas filas
Insert.DATAcon tipos de MIME que no sean los estándarContactsContract.CommonDataKinds, el editor ignorará esos tipos de MIME de forma silenciosa. SHOW_OR_CREATE_CONTACTno se controla con el editor del sistema. Las apps de contactos que se incluyen con el dispositivo aún pueden controlarlo. Para obtener un comportamiento coherente en todos los dispositivos, usaACTION_INSERT_OR_EDIT.- Las operaciones de escritura fallan de forma predeterminada. Una vez que te orientes a la próxima versión de Android, cualquier escritura directa sin
MANAGE_CONTACTSgenerará unaSecurityException or permission denial. Realiza pruebas para detectarlo.
¿Necesito MANAGE_CONTACTS?
Probablemente no. Si tu app guarda o edita contactos porque un usuario se lo pidió, los intents anteriores te cubren, sin permiso ni declaración de Play Console.
MANAGE_CONTACTS es para apps cuyo propósito principal es administrar contactos, en las que los intents no son suficientes. Por ejemplo:
| Tu app… | ¿Necesitas MANAGE_CONTACTS? |
| Guarda un contacto de un chat, una tarjeta de presentación o un pedido. | No, usa ACTION_INSERT |
| Agrega un número o un correo electrónico a un contacto existente. | No, usa ACTION_INSERT_OR_EDIT o ACTION_EDIT |
| Permite que los usuarios elijan contactos para invitarlos, compartir contenido con ellos o pagarles. | No, usa el Selector de contactos |
| Agrega acciones de llamada o mensaje a los contactos. | No, usar el Directorio de personas |
| Tiene su propia pantalla de edición de contactos con su marca. | No, una interfaz personalizada por sí sola no cumple con los requisitos. |
| Es un administrador de contactos dedicado o una app de reemplazo del marcador. | Es probable que sí |
| Es una app de protección contra spam y de identificación de llamadas que actualiza de forma masiva las entradas de la libreta de direcciones. | Es probable que sí |
| Sincroniza contactos con una cuenta empresarial o de nube en segundo plano. | Es probable que sí |
| Realiza copias de seguridad y restablecimientos de contactos de forma masiva, o bien transferencias de teléfono de un dispositivo a otro. | Es probable que sí |
| Establece tonos personalizados para contactos individuales. | Es probable que sí |
Cómo funciona:
MANAGE_CONTACTSes un permiso de acceso especial para apps. No es un diálogo de tiempo de ejecución. Los usuarios pueden activarla en Configuración > Acceso especial de apps > Administrar contactos.
// Opens Settings > Apps > Special app access > Manage contacts val intent = Intent(Settings.ACTION_MANAGE_CONTACTS, Uri.fromParts("package", packageName, null)) context.startActivity(intent)
- Abarca la lectura, la adición, la edición y la eliminación de contactos, cuentas y datos del Directorio de personas. Tampoco es necesario que solicites
READ_CONTACTS. - Para publicar en Google Play con
MANAGE_CONTACTS, debes enviar una declaración en Play Console en la que expliques por qué los intents no son suficientes para la funcionalidad principal de tu app.
Pasos de la migración
- Busca las escrituras de contacto. Busca
WRITE_CONTACTS,ContactsContract.RawContacts.CONTENT_URI,ContactsContract.Data.CONTENT_URIyapplyBatch(ContactsContract.AUTHORITY, …)en tu código. - Reemplaza cada escritura controlada por el usuario por un intent:
ACTION_INSERTpara contactos nuevos, yACTION_EDIToACTION_INSERT_OR_EDITpara actualizaciones. - Usa solo tipos de datos estándar en
Insert.DATA. Se movieron las acciones de llamada o mensaje al directorio de personas. - Decide si realmente necesitas
MANAGE_CONTACTScon la tabla anterior. Si es así, planifica tu declaración de Play Console. - Quita
WRITE_CONTACTSde tu manifiesto una vez que ninguna ruta de código lo necesite.
Cronograma
| Cuándo | Qué ocurre |
| 21 de octubre de 2026 | Google Play anuncia la política de MANAGE_CONTACTS |
| 2026 (versión trimestral de la plataforma 2 de Android 17) | El permiso MANAGE_CONTACTS pasa a estar disponible |
| 2027 (próxima versión de Android) | WRITE_CONTACTS ya no otorga acceso de escritura a las apps que se orientan a la próxima versión de Android. Los intents de contacto están estandarizados en todos los dispositivos |
| 2027, no antes de la próxima versión de Android | Play Console solicita a las apps que usan MANAGE_CONTACTS que envíen una declaración |
| 2027, no antes de la próxima versión de Android | Se requiere el cumplimiento de las políticas de Play |
Preguntas frecuentes
- ¿Esto afecta a todas las apps?
- El cambio de baja de
WRITE_CONTACTSsolo se aplica a las apps que se orientan a la próxima versión de Android y posteriores. Las apps orientadas a versiones anteriores conservarán su comportamiento actual. Sin embargo, el nuevo editor de contactos estandarizado estará disponible para todas las apps que se ejecuten en el nuevo SO, independientemente de su SDK de destino.
- El cambio de baja de
- ¿Mi app puede borrar contactos con un intent?
- No. No hay ningún intent para borrar contactos. Los usuarios borran contactos en su app de contactos. Las apps con
MANAGE_CONTACTSpueden borrar contactos directamente.
- No. No hay ningún intent para borrar contactos. Los usuarios borran contactos en su app de contactos. Las apps con
- Ya tengo mi propia pantalla de edición de contactos. ¿Puedo quedármelo?
- Solo si tu app cumple con los requisitos para
MANAGE_CONTACTS. Querer mantener un diseño personalizado no es un motivo válido por sí solo.
- Solo si tu app cumple con los requisitos para
- ¿
MANAGE_CONTACTSreemplaza READ_CONTACTS?MANAGE_CONTACTSincluye acceso de lectura, por lo que no es necesario que solicites ambos, pero muchas apps que no necesitan modificar los contactos califican paraREAD_CONTACTS. Estas apps pueden seguir solicitandoREAD_CONTACTS.
- ¿Qué sucede con mis usuarios que tienen versiones anteriores de Android?
- Los intents de contacto también funcionan en versiones anteriores, administrados por la app de contactos del dispositivo. La mayoría de las apps funcionarán bien en todos los dispositivos que usen estos intents. Si tu app se ve afectada por un problema de coherencia específico que solo se resuelve en las versiones más recientes, puedes mantener el permiso
WRITE_CONTACTSen tu manifiesto con un maxSdkVersion adecuado.
- Los intents de contacto también funcionan en versiones anteriores, administrados por la app de contactos del dispositivo. La mayoría de las apps funcionarán bien en todos los dispositivos que usen estos intents. Si tu app se ve afectada por un problema de coherencia específico que solo se resuelve en las versiones más recientes, puedes mantener el permiso
-
Novedades de productosPrincipales actualizaciones de IA en Android para crear experiencias inteligentes de Google I/O 2026
En Google I/O 2026, presentamos el cambio de Android de un sistema operativo a un sistema de inteligencia. También mostramos cómo puedes crear experiencias inteligentes de forma nativa con el sistema y llevar el poder de la IA de Google a tus apps.
Jingyu Shi • Lectura de 2 min -
Novedades de productosEste año, en Google I/O, iremos más allá de los cambios iterativos y nos dirigiremos hacia un cambio fundamental en la forma en que se crean las apps. Nuestras herramientas más recientes se crearon para la era de los agentes con funciones que aumentan tu productividad como desarrollador de Android Y potencian los agentes de IA que implementas en tu base de código.
Matthew Warner • Lectura de 8 min -
Novedades de productosComo se anunció hoy durante The Android Show, Android está pasando de ser un sistema operativo a un sistema de inteligencia, lo que crea más oportunidades de interacción con tus apps.
Matthew McCullough • Lectura de 4 min
Recibe la información más reciente sobre el desarrollo de Android en tu bandeja de entrada todas las semanas.