Wenn du eine Capacitor Community Contacts Alternative suchst, ist der vollständigste Drop-in-Replacement: @capgo/capacitor-contacts. Es deckt alles ab, was @capacitor-community/contacts bietet (Lesen, Erstellen, Löschen und Auswählen von Kontakten) und ermöglicht das Aktualisieren eines Kontakts ohne ID-Änderung, Pagination, Gruppen, Accounts, native Kontakt-Screens sowie permission-freies Picking auf Android – entscheidend für die Google Play Contacts Policy 2027. Dieser Guide vergleicht beide und bildet jeden Call ab, damit du die Migration an einem Nachmittag erledigst.
Warum nach einer Alternative suchen?
@capacitor-community/contacts wird gepflegt und hat ein Capacitor 8 Release. Für einfache Read- und Create-Flows ist es eine gute Wahl. Teams wachsen meist aus folgenden Gründen darüber hinaus:
- Keine Update-Methode. Du kannst Kontakte erstellen und löschen, aber nicht bearbeiten. Löschen und Neuerstellen vergibt eine neue ID, was alle gespeicherten Referenzen bricht und Daten verlieren kann, die das Plugin nicht liest.
- Keine Pagination.
getContactsgibt das gesamte Adressbuch in einem Call zurück. Auf einem Gerät mit 5.000 Kontakten und Fotos ist das langsam und speicherintensiv. - Picking benötigt auf Android die Permission. Das Android-
pickContactfordert die Contacts-Permission an, bevor der Picker geöffnet wird, und liest den Kontakt dann aus dem Adressbuch. Unter Google Play Richtlinie zu Kontaktberechtigungen, können Apps, die auf Android 17 abzielen, nurREAD_CONTACTSfür Kernfunktionen. - Keine Gruppen, Accounts oder nativen Screens. Keine Möglichkeit, Gruppen aufzulisten, den Account für neue Kontakte zu wählen oder das System-Formular „Neuer Kontakt“ zu öffnen.
Feature-Vergleich
| Feature | @capacitor-community/contacts 8.0 | @capgo/capacitor-contacts 8.1 |
|---|---|---|
| Einzelne / alle Kontakte lesen | getContact, getContacts |
getContactById, getContacts |
| Feldauswahl | projection Objekt |
fields Array |
| Pagination | Nein | limit, offset |
| Kontakte zählen | Nein | countContacts |
| Erstellen | createContact |
createContact |
| Vor Ort aktualisieren | Nein | updateContactById |
| Löschen | deleteContact |
deleteContactById |
| Einen Kontakt auswählen | pickContact |
pickContact |
| Mehrere auswählen | Nein | pickContacts({ multiple: true }) |
| Telefon/E-Mail/Adresse ohne Berechtigung abrufen | Nein | pickContacts({ property }) |
| Gruppen | Nein | getGroups, getGroupById, createGroup, deleteGroupById |
| Accounts | Nein | getAccounts |
| Native Create / View / Edit Screens | Nein | displayCreateContact, displayContactById, displayUpdateContactById |
| Getrennte Lese- und Schreibberechtigungen | Nein (einzelner Alias) | readContacts, writeContacts |
| iOS Limited Access Status | limited |
limited |
| Einstellungen öffnen | Nein | openSettings |
Installieren
bun add @capgo/capacitor-contacts
bunx cap sync
Das Plugin fügt keine Berechtigungen zum Android Manifest hinzu. Füge nur das hinzu, was du wirklich nutzt:
<!-- 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" />
On iOS, add NSContactsUsageDescription zu Info.plist falls du das Adressbuch liest oder beschreibst. Für die Auswahl (Picking) ist dies nicht nötig.
Migrationsleitfaden, Schritt für Schritt
Berechtigungen
// 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;
}
Ab iOS 18 können Nutzer nur einem Teil der Kontakte Zugriff gewähren. Das Plugin meldet dies als limited. Behandle dies als erteilt und verlasse dich nur auf die freigegebenen Kontakte.
Alle Kontakte lesen
// 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;
Nutze countContacts() zuerst, falls du einen Fortschrittsbalken anzeigen möchtest.
Einen Kontakt lesen
// 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');
Kontakt erstellen
// 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 ist im Capgo Plugin schreibgeschützt. Schreibe givenName und familyName, und das Gerät formatiert den Anzeigenamen.
Kontakt aktualisieren (neu)
await CapacitorContacts.updateContactById({
id,
contact: {
givenName: 'Ada',
familyName: 'King',
jobTitle: 'Analyst',
phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
},
});
Die ID bleibt gleich, sodass alle gespeicherten Referenzen weiterhin funktionieren. Lies den Kontakt zuerst und sende die Felder zurück, die du behalten möchtest, um nichts versehentlich zu löschen.
Wenn der Nutzer selbst editieren soll, öffne den System-Editor:
await CapacitorContacts.displayUpdateContactById({ id });
Kontakt löschen
// Before
await Contacts.deleteContact({ contactId: id });
// After
await CapacitorContacts.deleteContactById({ id });
Kontakt auswählen
// 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;
Wenn du den vollständigen Datensatz aus dem Picker benötigst, rufe pickContact() ohne propertyauf. Bei Android wird der vollständige Kontakt nur zurückgegeben, wenn READ_CONTACTS wurde erteilt.
Field-Mapping
| Community-Payload | Capgo Contact |
|---|---|
contactId |
id |
name.display |
displayName (schreibgeschützt) |
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 (Base64-String) |
Auch die Typen ändern sich: Das Capgo Plugin nutzt Großbuchstaben wie 'MOBILE', 'HOME', 'WORK' für Telefonnummern und E-Mails.
Schrittweise pro Screen migrieren
Die beiden Plugins registrieren sich unter unterschiedlichen nativen Namen (Contacts und CapacitorContacts), sodass sie parallel installiert werden können, während du die Aufrufstellen migrierst. Ein kleiner Adapter hält den Rest deiner App unverändert:
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),
}));
}
Sobald die letzte Aufrufstelle migriert wurde, entferne das Community-Plugin und führe bunx cap sync, und prüfe das zusammengeführte Android Manifest, um sicherzustellen, dass nur die benötigten Berechtigungen verbleiben.
Fehlerbehebung
getContacts gibt auf iOS eine leere Liste zurück. Der Nutzer hat nur begrenzten Zugriff gewährt und keine Kontakte geteilt oder den Zugriff abgelehnt. Prüfe readContacts und biete openSettings().
Erstellter Kontakt wird in einem bestimmten Account auf Android nicht angezeigt. Übergib einen account (aus getAccounts()) in dem Kontakt, den du erstellst.
Fotos machen Listen langsam. Nicht anfragen photo in Listenansichten. Lade sie mit getContactById wenn der User einen Kontakt öffnet.
Play Console Warnungen READ_CONTACTS. Invite- und Share-Flows verschieben nach pickContacts({ property }) und die Permission entfernen, falls sie nicht mehr benötigt wird.
Veröffentlichen
Plugins zu tauschen ist eine Native-Änderung und erfordert einen Store-Build. Capgo Build kann iOS- und Android-Builds in der Cloud erstellen. Danach sind Fixes für deine Kontakt-Screens reines JavaScript und können via Capgo Live Updatesausgeliefert werden. Das vollständige API findest du im Contacts Plugin Docs.