Si vous avez besoin d’une alternative communautaire à Capacitor, le remplacement le plus complet est @capgo/capacitor-contacts. Il couvre ce que @capacitor-community/contacts permet de (lire, créer, supprimer et sélectionner des contacts) et ajoute la mise à jour d’un contact sans changer son ID, la pagination, les groupes, les comptes, les écrans de contacts natifs et la sélection sans permission sur Android, ce qui compte pour la politique de Google Play sur les contacts en 2027. Ce guide compare les deux solutions et met en correspondance chaque appel pour vous permettre de migrer en un après-midi.
Pourquoi chercher une alternative
@capacitor-community/contacts est maintenu et a une release Capacitor 8. C’est un bon choix pour des flux simples de lecture et de création. Les équipes finissent généralement par ne plus s’en contenter pour ces raisons :
- Aucune méthode de mise à jour. Vous pouvez créer et supprimer des contacts, mais pas en modifier un. Supprimer puis recréer attribue un nouvel ID au contact, ce qui casse toute référence stockée et peut faire perdre des données que le plugin ne lit pas.
- Pas de pagination.
getContactsrenvoie tout le répertoire en un seul appel. Sur un appareil avec 5 000 contacts et photos, c’est lent et gourmand en mémoire. - La sélection nécessite une permission sur Android. La version Android
pickContactdemande le groupe de permissions contacts avant d’ouvrir le sélecteur, puis lit le contact dans le répertoire. Selon la Politique de Google Play sur les permissions Contacts, les applications ciblant Android 17 ne peuvent conserverREAD_CONTACTSpour les fonctionnalités essentielles. - Aucun groupe, compte ni écran natif. Impossible de lister les groupes, de choisir le compte dans lequel enregistrer un nouveau contact ou d’ouvrir le formulaire système « Nouveau contact ».
Comparatif des fonctionnalités
| Fonctionnalité | @capacitor-community/contacts 8.0 | @capgo/capacitor-contacts 8,1 |
|---|---|---|
| Lire un / tous les contacts | getContact, getContacts |
getContactById, getContacts |
| Sélection des champs | projection objet |
fields tableau |
| Pagination | Non | limit, offset |
| Compter les contacts | Non | countContacts |
| Créer | createContact |
createContact |
| Mise à jour sur place | Non | updateContactById |
| Supprimer | deleteContact |
deleteContactById |
| Sélectionner un contact | pickContact |
pickContact |
| Sélectionner plusieurs | Non | pickContacts({ multiple: true }) |
| Choisir un numéro/e-mail/adresse sans autorisation | Non | pickContacts({ property }) |
| Groupes | Non | getGroups, getGroupById, createGroup, deleteGroupById |
| Comptes | Non | getAccounts |
| Écrans natifs de création / vue / édition | Non | displayCreateContact, displayContactById, displayUpdateContactById |
| Séparer les états de permission de lecture et d'écriture | Non (alias unique) | readContacts, writeContacts |
| État d'accès limité sur iOS | limited |
limited |
| Ouvrir les réglages | Non | openSettings |
Installer
bun add @capgo/capacitor-contacts
bunx cap sync
Le plugin n'ajoute pas de permissions à votre manifest Android. Ajoutez uniquement ce que vous utilisez :
<!-- 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" />
Sur iOS, ajoutez NSContactsUsageDescription vers Info.plist si vous lisez ou écrivez dans le carnet d'adresses. La sélection ne l'exige pas.
Guide de migration, appel par appel
Autorisations
// 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;
}
Sur iOS 18 et versions ultérieures, les utilisateurs peuvent accorder l'accès à un sous-ensemble de contacts. Le plugin le signale comme limited. Considérez-le comme accordé et ne vous attendez qu'aux contacts partagés.
Lire tous les contacts
// 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;
Utiliser countContacts() d'abord si vous souhaitez afficher une barre de progression.
Lire un contact
// 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');
Créer un contact
// 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 est en lecture seule dans le plugin Capgo. Écrivez givenName et familyName, et l'appareil formate le nom d'affichage.
Mettre à jour un contact (nouveau)
await CapacitorContacts.updateContactById({
id,
contact: {
givenName: 'Ada',
familyName: 'King',
jobTitle: 'Analyst',
phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
},
});
L'ID reste le même, donc toute référence que vous avez enregistrée fonctionne toujours. Lisez d'abord le contact et renvoyez les champs que vous voulez conserver, pour ne pas effacer quelque chose par accident.
Si vous préférez laisser l'utilisateur modifier, ouvrez l'éditeur système :
await CapacitorContacts.displayUpdateContactById({ id });
Supprimer un contact
// Before
await Contacts.deleteContact({ contactId: id });
// After
await CapacitorContacts.deleteContactById({ id });
Choisir un contact
// 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 vous avez besoin de la fiche contact complète depuis le sélecteur, appelez pickContact() sans property. Sur Android, cela ne renvoie le contact complet que lorsque READ_CONTACTS est accordée.
Correspondance des champs
| Payload communautaire | Capgo Contact |
|---|---|
contactId |
id |
name.display |
displayName (lecture seule) |
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 (chaîne base64) |
Les valeurs de type changent aussi : le plugin Capgo utilise des chaînes en majuscules, comme 'MOBILE', 'HOME', 'WORK' pour les téléphones et e-mails.
Migrer un écran à la fois
Les deux plugins sont enregistrés sous des noms natifs différents (Contacts et CapacitorContacts), ils peuvent donc être installés ensemble pendant que vous déplacez les appels. Un petit adaptateur permet de laisser le reste de votre application inchangé :
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),
}));
}
Une fois le dernier appel déplacé, supprimez le plugin communautaire, exécutez bunx cap sync, et vérifiez le manifest Android fusionné pour vous assurer que seules les permissions nécessaires restent présentes.
Troubleshooting
getContacts renvoie une liste vide sur iOS. L'utilisateur a accordé un accès limité et n'a partagé aucun contact, ou a refusé l'accès. Vérifiez readContacts et proposez openSettings().
Le contact créé n’apparaît pas dans un compte spécifique sur Android. Passez un account (depuis getAccounts()) dans le contact que vous créez.
Les photos ralentissent les listes. Ne demandez pas photo dans les vues de liste. Chargez-l’avec getContactById lorsque l’utilisateur ouvre un contact.
Play Console signale READ_CONTACTS. Déplacez les flux d’invitation et de partage vers pickContacts({ property }) et supprimez l’autorisation si rien d’autre n’en a besoin.
Déployez
Changer de plugin est une modification native, il faut donc un build store. Build Capgo peut générer des builds iOS et Android dans le cloud. Ensuite, les correctifs de vos écrans de contacts sont en JavaScript et peuvent être déployés via les live updates Capgo. L’API complet est dans Docs du plugin contacts.