Saltar al contenido principal

Alternativa a Capacitor Community Contacts

Una alternativa al plugin @capacitor-community/contacts: actualiza contactos, grupos, paginación y selección sin permisos, con una guía de migración completa.

Ilustración de plugins de Capgo para una comparación de plugins de contactos de Capacitor

Si necesitas una alternativa a los contactos de la comunidad de Capacitor, la sustitución más completa es @capgo/capacitor-contacts. Cubre lo que @capacitor-community/contacts permite (leer, crear, eliminar y seleccionar contactos) y añade la capacidad de actualizar un contacto sin cambiar su ID, paginación, grupos, cuentas, pantallas nativas de contactos y selección sin permisos en Android, algo clave para la política de contactos de Google Play de 2027. Esta guía compara ambos y mapea cada llamada para que puedas migrar en una tarde.

Por qué buscar una alternativa

@capacitor-community/contacts se mantiene y tiene una versión 8 de Capacitor. Es una buena opción para flujos sencillos de lectura y creación. Los equipos suelen quedarse cortos con él por estas razones:

  • Sin método de actualización. Puedes crear y eliminar contactos, pero no editarlos. Eliminar y volver a crear le asigna al contacto un nuevo ID, lo que rompe cualquier referencia que hayas guardado y puede provocar la pérdida de datos que el plugin no lee.
  • Sin paginación. getContacts devuelve toda la agenda en una sola llamada. En un dispositivo con 5.000 contactos y fotos, eso es lento y consume mucha memoria.
  • La selección requiere el permiso en Android. Android pickContact solicita el permiso de contactos antes de abrir el selector y luego lee el contacto de la libreta de direcciones. Bajo política de permisos de contactos de Google Play, las apps orientadas a Android 17 solo pueden mantener READ_CONTACTS para funciones clave.
  • Sin grupos, cuentas ni pantallas nativas. No permite listar grupos, elegir la cuenta donde se guarda un nuevo contacto ni abrir el formulario de "nuevo contacto" del sistema.

Comparativa de funciones

Característica @capacitor-community/contacts 8.0 @capgo/capacitor-contacts 8.1
Leer uno / todos los contactos getContact, getContacts getContactById, getContacts
Selección de campos projection objeto fields array
Paginación No limit, offset
Contar contactos No countContacts
Crear createContact createContact
Actualizar in situ No updateContactById
Eliminar deleteContact deleteContactById
Seleccionar un contacto pickContact pickContact
Seleccionar varios No pickContacts({ multiple: true })
Seleccionar un teléfono/email/dirección sin permiso No pickContacts({ property })
Grupos No getGroups, getGroupById, createGroup, deleteGroupById
Cuentas No getAccounts
Pantallas nativas de creación / vista / edición No displayCreateContact, displayContactById, displayUpdateContactById
Estados de permisos de lectura y escritura separados No (alias único) readContacts, writeContacts
Estado de acceso limitado en iOS limited limited
Abrir ajustes No openSettings

Instalar

bun add @capgo/capacitor-contacts
bunx cap sync

El plugin no añade permisos a tu manifiesto de Android. Añade solo lo que uses:

<!-- Needed for getContacts, getContactById, countContacts, groups, accounts -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Needed for createContact, updateContactById, deleteContactById, groups writes -->
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

En iOS, añade NSContactsUsageDescription a Info.plist si lees o escribes en la agenda de contactos. Para seleccionar no hace falta.

Guía de migración, llamada por llamada

Permisos

// Before
import { Contacts } from '@capacitor-community/contacts';
const perm = await Contacts.requestPermissions();
if (perm.contacts !== 'granted') return;

// After
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const status = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (status.readContacts !== 'granted' && status.readContacts !== 'limited') {
  await CapacitorContacts.openSettings();
  return;
}

En iOS 18 y versiones posteriores, los usuarios pueden conceder acceso a un subconjunto de contactos. El plugin lo reporta como limited. Dalo por concedido y espera solo los contactos compartidos.

Leer todos los contactos

// Before: whole address book, projection object
const { contacts } = await Contacts.getContacts({
  projection: { name: true, phones: true, emails: true },
});
const first = contacts[0];
console.log(first.name?.display, first.phones?.[0]?.number);

// After: fields array, paginated
const pageSize = 200;
let offset = 0;
for (;;) {
  const { contacts } = await CapacitorContacts.getContacts({
    fields: ['displayName', 'givenName', 'familyName', 'phoneNumbers', 'emailAddresses'],
    limit: pageSize,
    offset,
  });
  render(contacts);
  if (contacts.length < pageSize) break;
  offset += pageSize;
}

declare function render(list: unknown[]): void;

Usa countContacts() primero si quieres mostrar una barra de progreso.

Leer un contacto

// Before
const { contact } = await Contacts.getContact({
  contactId: id,
  projection: { name: true, phones: true },
});

// After
const { contact } = await CapacitorContacts.getContactById({
  id,
  fields: ['displayName', 'phoneNumbers'],
});
if (!contact) console.log('Not found');

Crear un contacto

// Before
const { contactId } = await Contacts.createContact({
  contact: {
    name: { given: 'Ada', family: 'Lovelace' },
    phones: [{ type: PhoneType.Mobile, number: '+44 20 7946 0000' }],
    emails: [{ type: EmailType.Work, address: 'ada@example.com' }],
  },
});

// After
const { id } = await CapacitorContacts.createContact({
  contact: {
    givenName: 'Ada',
    familyName: 'Lovelace',
    phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
    emailAddresses: [{ type: 'WORK', value: 'ada@example.com' }],
  },
});

displayName es de solo lectura en el plugin Capgo. Escribe givenName y familyName, y el dispositivo formatea el nombre visible.

Actualizar un contacto (nuevo)

await CapacitorContacts.updateContactById({
  id,
  contact: {
    givenName: 'Ada',
    familyName: 'King',
    jobTitle: 'Analyst',
    phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
  },
});

El ID se mantiene, así que cualquier referencia guardada seguirá funcionando. Lee el contacto primero y devuelve los campos que quieras conservar para no borrar nada por accidente.

Si prefieres que el usuario lo edite, abre el editor del sistema:

await CapacitorContacts.displayUpdateContactById({ id });

Eliminar un contacto

// Before
await Contacts.deleteContact({ contactId: id });

// After
await CapacitorContacts.deleteContactById({ id });

Seleccionar un contacto

// Before: requests the contacts permission on Android first
const { contact } = await Contacts.pickContact({
  projection: { name: true, phones: true },
});

// After: one phone number, no permission on Android or iOS
import { ContactProperty } from '@capgo/capacitor-contacts';

const { contacts } = await CapacitorContacts.pickContacts({
  property: ContactProperty.PhoneNumber,
});
const phone = contacts[0]?.phoneNumbers?.[0]?.value;

Si necesitas el registro completo del contacto desde el picker, llama a pickContact() sin property. En Android, eso devuelve el contacto completo solo cuando READ_CONTACTS se concede.

Mapeo de campos

Payload de la comunidad Capgo Contact
contactId id
name.display displayName (solo lectura)
name.given / middle / family givenName / middleName / familyName
name.prefix / suffix namePrefix / nameSuffix
organization.company organizationName
organization.jobTitle jobTitle
birthday { day, month, year } birthday { day, month, year }
note note
phones[].number phoneNumbers[].value
emails[].address emailAddresses[].value
urls[] (strings) urlAddresses[].value
postalAddresses[].region / postcode postalAddresses[].state / postalCode
image.base64String photo (string base64)

Los valores de Type también cambian: el plugin Capgo usa strings en mayúsculas como 'MOBILE', 'HOME', 'WORK' para teléfonos y correos electrónicos.

Migra una pantalla a la vez

Los dos plugins se registran con nombres nativos diferentes (Contacts y CapacitorContacts), para que puedan instalarse juntos mientras migras las llamadas. Un pequeño adaptador mantiene el resto de tu app sin cambios:

import { CapacitorContacts } from '@capgo/capacitor-contacts';

export interface AppContact {
  id: string;
  name: string;
  phones: string[];
}

export async function listContacts(limit = 200, offset = 0): Promise<AppContact[]> {
  const { contacts } = await CapacitorContacts.getContacts({
    fields: ['displayName', 'phoneNumbers'],
    limit,
    offset,
  });
  return contacts.map((c) => ({
    id: c.id ?? '',
    name: c.displayName ?? '',
    phones: (c.phoneNumbers ?? []).map((p) => p.value),
  }));
}

Cuando hayas migrado la última llamada, elimina el plugin de la comunidad y ejecuta bunx cap sync, y revisa el Android manifest combinado para confirmar que solo queden los permisos necesarios.

Solución de problemas

getContacts devuelve una lista vacía en iOS. El usuario otorgó acceso limitado y no compartió contactos, o denegó el acceso. Revisa readContacts y ofrece openSettings().

El contacto creado no aparece en una cuenta específica en Android. Pasa un account (desde getAccounts()) en el contacto que crees.

Las fotos ralentizan las listas. No solicites photo en vistas de lista. Carga con getContactById cuando el usuario abre un contacto.

Avisos de Play Console READ_CONTACTS. Mover los flujos de invitación y compartir a pickContacts({ property }) y eliminar el permiso si nada más lo necesita.

Lánzalo

Cambiar plugins es un cambio nativo, por lo que requiere un build para la tienda. Build de Capgo puede generar builds de iOS y Android en la nube. Después, las correcciones a tus pantallas de contactos son JavaScript y pueden publicarse con actualizaciones Live Update de Capgo. El API completo está en la documentación del plugin de contactos.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.