La politique des permissions Contacts de Google Play signifie qu’à partir du 27 janvier 2027, les applications ciblant Android 17 (niveau API 37) ou supérieur ne pourront demander READ_CONTACTS si le sélecteur de contacts Android ne peut pas prendre en charge une fonctionnalité essentielle, et doivent le justifier par une déclaration dans la Play Console. Pour la plupart des applications Capacitor qui lisent les contacts pour inviter un ami, partager un fichier ou remplir un numéro de téléphone, la solution est de passer au sélecteur de contacts et de supprimer l’autorisation. Ce guide explique la politique et montre comment faire avec @capgo/capacitor-contacts, et explique quoi faire si vous avez vraiment besoin de tout le carnet d'adresses.
Ce que dit la politique
Google a annoncé cette politique le 15 avril 2026, dans le cadre d'une série de mises à jour sur la confidentialité. Les points clés, tirés des pages d'aide de la Play Console :
- Périmètre : les applications qui ciblent Android 17 (API 37) ou supérieur et demandent
READ_CONTACTS. - Règle : vous ne pouvez demander que
READ_CONTACTSsi l'Android Contact Picker ne suffit pas pour une fonctionnalité clé de votre application. - Déclaration : les applications qui conservent la permission doivent remplir une déclaration dans la Play Console décrivant les fonctionnalités concernées et pourquoi le picker ne suffit pas.
- Calendrier : La Play Console a commencé à demander aux applications qui déclarent
READ_CONTACTSen septembre 2026. La conformité est obligatoire le 27 janvier 2027. Google mentionne une extension de 30 jours en libre-service dans Play Console. - Exemptions : les applications privées et les applications de gestion d’appareils d’entreprise sont hors périmètre.
- Données : les données de contacts sont personnelles et sensibles au regard de la politique User Data, et vous ne pouvez pas publier de données de contacts non publiques sans l'autorisation des personnes concernées.
Cas d’usage pouvant conserver READ_CONTACTS
Google cite des fonctionnalités essentielles comme les applications de gestion de contacts, les composeurs et applications SMS, l'historique et le filtrage d'appels, les CRM, les fonctionnalités d'accessibilité, les assistants personnels, l'association d'amis, la sauvegarde et la restauration, ainsi que les claviers ou l'auto-complétion.
Cas d’usage devant passer au picker
Inviter ou recommander quelqu'un, partager des fichiers, collaborer, ou choisir un contact pour envoyer de l'argent. Si c'est la raison pour laquelle votre application lit les contacts, la déclaration ne sera pas acceptée. Utilisez le sélecteur.
Ce qui change sur Android 17
Android 17 intègre un nouveau sélecteur de contacts système. Les applications obtiennent un URI de session temporaire, en lecture seule, qui n'expose que les contacts et champs sélectionnés par l'utilisateur, sans aucune permission. Pour les applications ciblant Android 17, le système met automatiquement à niveau l'intention classique Intent.ACTION_PICK de contacts vers ce nouveau sélecteur. Les applications peuvent également demander des champs de données spécifiques (téléphone, e-mail, adresse postale) et la sélection multiple via une nouvelle action d'intention.
Sur les versions Android antérieures, la sélection d'une ligne de données spécifique (par exemple un numéro de téléphone) via le sélecteur de contacts a toujours renvoyé un URI que l'application peut lire sans READ_CONTACTS. C'est ce qui rend possible un flux sans permission sur toutes les versions d'Android.
Pourquoi « choisir un contact » exigeait READ_CONTACTS
De nombreux plugins Capacitor implémentent la sélection d’un contact en ouvrant le sélecteur pour un contact entier, puis en interrogeant le répertoire pour récupérer ses numéros de téléphone et e-mails. Cette seconde requête nécessite READ_CONTACTS. Ainsi, même les applications qui ne demandaient qu’un seul numéro de téléphone finissaient par déclarer l’autorisation, ce qui est précisément ce que la politique vise.
La solution consiste à demander au sélecteur le champ spécifique dont vous avez besoin, afin que l’URI de résultat contienne déjà les données.
Choisir un téléphone, un e-mail ou une adresse sans READ_CONTACTS
@capgo/capacitor-contacts a ajouté une property option dans la version 8.1.0. Une fois activée, Android ouvre le sélecteur sur la table des téléphones, e-mails ou adresses postales et lit la ligne sélectionnée depuis l’URI accordée. Aucune READ_CONTACTS est nécessaire sur toutes les versions d'Android. Sur iOS, le sélecteur système n'a jamais besoin de la permission contacts.
bun add @capgo/capacitor-contacts
bunx cap sync
import { CapacitorContacts, ContactProperty } from '@capgo/capacitor-contacts';
export async function pickPhoneNumber(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.PhoneNumber,
});
const picked = contacts[0];
return picked?.phoneNumbers?.[0]?.value;
}
export async function pickEmail(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.EmailAddress,
});
return contacts[0]?.emailAddresses?.[0]?.value;
}
Avec property, le résultat contient le contact id, displayName et uniquement la propriété sélectionnée. La sélection multiple est ignorée, le choix de propriété renvoie toujours une seule valeur. Si l'utilisateur annule, vérifiez s'il s'agit d'un tableau vide.
Le plugin ne déclare pas READ_CONTACTS ou WRITE_CONTACTS dans son propre manifest, donc si vous n'utilisez que le choix de propriété, votre manifest fusionné reste propre.
Quand vous avez encore besoin de READ_CONTACTS
Ces méthodes du plugin lisent le carnet d'adresses et continuent d'exiger la permission :
pickContacts()oupickContact()sansproperty, quand vous voulez la fiche contact complètegetContacts(),getContactById(),countContacts()getGroups(),getGroupById(),getAccounts()
Si votre application est un CRM, un outil de sauvegarde ou propose une fonctionnalité de mise en relation, il s’agit d’un usage central légitime. Ajoutez la permission vous-même et déposez la déclaration :
<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const perm = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (perm.readContacts === 'granted' || perm.readContacts === 'limited') {
const { contacts } = await CapacitorContacts.getContacts({
fields: ['displayName', 'phoneNumbers'],
limit: 200,
offset: 0,
});
console.log(contacts.length);
}
La politique cible READ_CONTACTS. L’écriture de contacts via WRITE_CONTACTS (pour createContact, updateContactById, deleteContactById) n’est pas visée par cette politique, mais n’ajoutez cette permission que si vous utilisez ces méthodes.
Plan de migration pour une application Capacitor
-
Auditez le manifeste fusionné. Compilez votre release et ouvrez
android/app/build/intermediates/merged_manifest/(ou utilisez l’onglet Merged Manifest d’Android Studio). Certains plugins ajoutentREAD_CONTACTSsans que vous vous en rendiez compte. Si un plugin l’ajoute et que vous n’en avez pas besoin, supprimez-l’avectools:node="remove":<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.READ_CONTACTS" tools:node="remove" /> </manifest> -
Listez chaque endroit où vous accédez aux contacts. Pour chacun, décidez : picker avec une propriété, ou carnet d’adresses complet.
-
Remplacez les flux d’invitation et de partage par
pickContacts({ property }). -
Keep the permission only for core features, et préparez le texte de déclaration : quelle fonctionnalité, pourquoi le picker ne suffit pas, une vidéo si la fonctionnalité est difficile à trouver.
-
Publiez un build natif. Les modifications du manifeste et des plugins nécessitent une nouvelle release Play. Si vous compilez en CI, Build Capgo peut générer des builds Android signés, et le générateur de keystore Android en ligne est utile si vous configurez la signature pour la première fois.
-
Déployez les changements d’interface en OTA. Une fois le nouveau plugin natif en ligne, les ajustements de libellés et de parcours autour du sélecteur peuvent être diffusés via les live updates Capgo.
Migration depuis un autre plugin de contacts
Si vous utilisez @capacitor-community/contacts (8.0.0 au moment de la rédaction), son Android pickContact demande le groupe de permissions contacts avant d'ouvrir le sélecteur, puis lit le contact complet depuis le carnet d'adresses. Il n'y a pas de mode propriété. Les noms de méthodes diffèrent également (getContact vs getContactById, des objets de projection vs un fields tableau). Notre comparaison entre le plugin contacts de la communauté et le plugin Capgo mappe chaque appel.
Si vous utilisez toujours un plugin de contacts Cordova dans Capacitor, c'est le moment idéal pour le remplacer. Voir migrer de Cordova vers Capacitor.
Troubleshooting
Le sélecteur renvoie un contact sans numéro de téléphone. Vous avez appelé pickContacts() sans property et l’app n’a pas de READ_CONTACTS. Seuls les id et displayName (et sur Android 17+, les champs accordés par le sélecteur) réapparaissent. Ajoutez property.
La Play Console indique toujours que l’app déclare READ_CONTACTS. Une bibliothèque l’ajoute. Vérifiez le manifest fusionné et supprimez-l’avec tools:node="remove". Vérifiez aussi les anciennes releases dans d’autres canaux : chaque artefact actif compte.
Déclaration refusée. Les invitations, les parrainages et le partage sont cités comme cas d’usage du picker. Repensez la fonctionnalité ou expliquez clairement pourquoi la liste complète est indispensable (par exemple, la mise en relation d’amis qui s’appuie sur tout le carnet d’adresses).
iOS asks for contacts permission. Vous appelez une méthode qui lit le carnet d’adresses. Le picker n’en a jamais besoin. Supprimez NSContactsUsageDescription si vous utilisez uniquement le picker.
Dates clés
| Date | Ce qui se passe |
|---|---|
| 15 avril 2026 | Politique annoncée |
| septembre 2026 | La Play Console invite les applications déclarant READ_CONTACTS à déposer une déclaration |
| 27 janvier 2027 | Conformité obligatoire pour les applications ciblant Android 17 (API 37) ou version ultérieure |
Consultez la page d’aide de la Play Console pour connaître la politique avant de publier : Google peut modifier les délais et la formulation.