Saltar al contenido principal

Alternativa al plugin Capacitor Community Contacts

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

Alternativa al plugin Capacitor Community Contacts

Si buscas una alternativa a Capacitor community contacts, el reemplazo más completo es @capgo/capacitor-contacts. Cubre lo que @capacitor-community/contacts permite (leer, crear, eliminar y seleccionar contactos) y permite actualizar un contacto sin cambiar su ID, con 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 Capacitor 8. Es una buena opción para flujos simples de lectura y creación. Los equipos suelen superarlo por estas razones:

  • Sin método de actualización. Puedes crear y eliminar contactos, pero no editarlos. Eliminar y recrear le asigna al contacto un nuevo ID, lo que rompe cualquier referencia guardada y puede causar 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, esto es lento y consume mucha memoria.
  • La selección requiere permisos en Android. El 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 principales.
  • Sin grupos, cuentas ni pantallas nativas. No permite listar grupos, elegir la cuenta para guardar un contacto o abrir el formulario nativo de "nuevo contacto".

Comparativa de funciones

Característica @capacitor-community/contacts 8.0 @capgo/capacitor-contacts 8.1
Leer un contacto / todos 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 })
Obtener 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 al Android manifest. 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 vas a leer o escribir en la agenda. Para seleccionar no es necesario.

Guía de migración, paso a paso

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 dar acceso a un subconjunto de contactos. El plugin lo reporta como limited. Trátalo como concedido y solo espera 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 dará formato al nombre.

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. Primero lee el contacto 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 está concedido.

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 en base64)

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

Migra una pantalla a la vez

Los dos plugins se registran con nombres nativos distintos (Contacts y CapacitorContacts), para que puedan instalarse juntos mientras migras los puntos de llamada. 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 se mueva el último punto de llamada, elimina el plugin de la comunidad y ejecuta bunx cap sync, y revisa el Android manifest fusionado para confirmar que solo se mantienen los permisos que necesitas.

Solución de problemas

getContacts devuelve una lista vacía en iOS. El usuario concedió 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 (de getAccounts()) en el contacto que crees.

Las fotos ralentizan las listas. No solicites photo en las vistas de lista. Cárgalo con getContactById cuando el usuario abra un contacto.

Play Console marca READ_CONTACTS. Mueve los flujos de invitación y compartir a pickContacts({ property }) y elimina el permiso si nada más lo requiere.

Lánzalo

Cambiar plugins es un cambio nativo, así que requiere un build de la tienda. Build con Capgo puede generar builds de iOS y Android en la nube. Después, los arreglos en tus pantallas de contactos son JavaScript y pueden salir con Live Updates de Capgo. El API completo está en el docs del plugin contacts.

Live Updates para apps de Capacitor

Si hay un bug en la capa web, publica el fix con 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 proceso de revisión normal.

Lo último de nuestro blog

Capgo te da los mejores insights para crear una app móvil realmente profesional.