La policy di Google Play sui permessi dei contatti prevede che, dal 27 gennaio 2027, le app con target Android 17 (livello API 37) o successivo possano richiedere solo READ_CONTACTS se il Contact Picker di Android non può supportare una funzionalità core, e devono giustificarlo con una dichiarazione in Play Console. Per la maggior parte delle app Capacitor che leggono i contatti per invitare un amico, condividere un file o inserire un numero di telefono, la soluzione è passare al Contact Picker e rimuovere il permesso. Questa guida spiega la policy e mostra come farlo con @capgo/capacitor-contacts, e spiega cosa fare se hai davvero bisogno dell'intera rubrica.
Cosa prevede la policy
Google ha annunciato la policy il 15 aprile 2026, nell'ambito di una serie di aggiornamenti sulla privacy. I punti chiave, tratti dalle pagine di assistenza di Play Console:
- Ambito: app che puntano ad Android 17 (API 37) o versioni successive e richiedono
READ_CONTACTS. - Regola: puoi richiedere l'accesso solo
READ_CONTACTSse l'Android Contact Picker non è sufficiente per una funzione core della tua app. - Dichiarazione: le app che mantengono il permesso devono compilare una dichiarazione in Play Console descrivendo quali funzioni ne hanno bisogno e perché il picker non è sufficiente.
- Timeline: Play Console ha iniziato a mostrare prompt alle app che dichiarano
READ_CONTACTSa settembre 2026. La conformità è obbligatoria entro il 27 gennaio 2027. Google menziona una proroga di 30 giorni tramite self-service in Play Console. - Esenzioni: le app private e quelle per l'enterprise device management sono escluse.
- Dati: i dati dei contatti sono personali e sensibili secondo la User Data policy; non puoi pubblicare dati di contatti non pubblici senza l'autorizzazione delle persone interessate.
Casi d'uso che possono mantenere READ_CONTACTS
Google elenca funzionalità core come app di gestione contatti, dialer e app SMS, cronologia chiamate e call screening, CRM, funzioni di accessibilità, assistenti personali, friend matching, backup e restore, e tastiere o autocomplete.
Casi d'uso che dovrebbero passare al picker
Invitare o suggerire qualcuno, condividere file, collaborare o scegliere un contatto per inviare denaro. Se la tua app legge i contatti per questo motivo, la dichiarazione non sarà accettata. Usa il picker.
Cosa cambia su Android 17
Android 17 introduce un nuovo Contact Picker di sistema. Le app ricevono un URI di sessione temporaneo e in sola lettura che espone solo i contatti e i campi selezionati dall'utente, senza alcuna permission. Per le app che puntano ad Android 17, il sistema aggiorna automaticamente il classico Intent.ACTION_PICK contacts intent verso questo nuovo picker. Le app possono anche richiedere campi dati specifici (telefono, email, indirizzo postale) e la selezione multipla tramite una nuova intent action.
Nelle versioni più vecchie di Android, selezionare una riga di dati specifica (ad esempio un numero di telefono) tramite il contact picker ha sempre restituito un URI che l'app può leggere senza READ_CONTACTS. Questo rende possibile un flusso senza permessi su ogni versione di Android.
Perché prima "selezionare un contatto" richiedeva READ_CONTACTS
Molti plugin Capacitor implementano "pick contact" aprendo il picker per l'intero contatto, per poi interrogare la rubrica per ottenere numeri di telefono ed email. Questa seconda query richiede READ_CONTACTS. Di conseguenza, anche le app che richiedevano un solo numero di telefono finivano per dichiarare il permesso, proprio ciò che la policy mira a contrastare.
La soluzione è richiedere al picker il campo specifico di cui hai bisogno, così il URI di risultato contiene già i dati.
Seleziona telefono, email o indirizzo senza READ_CONTACTS
@capgo/capacitor-contacts ha aggiunto un' property opzione nella versione 8.1.0. Quando attivata, Android apre il picker sulla tabella di telefono, email o indirizzo postale e legge la riga selezionata dal URI concesso. Nessun READ_CONTACTS è necessario su qualsiasi versione di Android. Su iOS, il picker di sistema non richiede mai il permesso per i contatti.
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;
}
Con property, il risultato contiene i dati del contatto id, displayName e solo la proprietà selezionata. La selezione multipla viene ignorata; il property picking restituisce sempre un solo valore. Se l'utente annulla, controlla se l'array è vuoto.
Il plugin non dichiara READ_CONTACTS o WRITE_CONTACTS nel proprio manifest, quindi se usi solo il property picking, il tuo manifest unificato rimane pulito.
Quando ti serve ancora READ_CONTACTS
Questi metodi del plugin leggono la rubrica e continuano a richiedere il permesso:
pickContacts()opickContact()senzaproperty, quando vuoi il record completo del contattogetContacts(),getContactById(),countContacts()getGroups(),getGroupById(),getAccounts()
Se la tua app è un CRM, uno strumento di backup o una funzione di friend matching, si tratta di un uso core legittimo. Aggiungi il permesso manualmente e presenta la dichiarazione:
<!-- 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 policy riguarda READ_CONTACTS. Scrivere i contatti con WRITE_CONTACTS (per createContact, updateContactById, deleteContactById) non è oggetto di questa policy, ma aggiungilo solo se usi quei metodi.
Piano di migrazione per un'app Capacitor
-
Verifica il manifest unificato. Genera la release e apri
android/app/build/intermediates/merged_manifest/(o usa la scheda Merged Manifest di Android Studio). Alcuni plugin aggiungonoREAD_CONTACTSsenza che tu te ne accorga. Se un plugin lo aggiunge ma non ti serve, rimuovilo contools: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> -
Elenca ogni punto in cui accedi ai contatti. Per ognuno, decidi: selettore con proprietà o rubrica completa.
-
Sostituisci i flussi di invito e condivisione con
pickContacts({ property }). -
Mantieni il permesso solo per le funzioni core, e prepara il testo della dichiarazione: quale funzionalità, perché il picker non basta, un video se la funzionalità è difficile da trovare.
-
Pubblica una build nativa. Le modifiche al manifest e ai plugin richiedono una nuova release su Play. Se buildi in CI, Build Capgo puoi generare build Android firmate, e il Generatore di keystore per Android ti aiuta se stai configurando la firma per la prima volta.
-
Pubblica le modifiche UI over the air. Una volta attivo il nuovo plugin nativo, i ritocchi a testi e flow del picker possono essere inviati tramite Live updates di Capgo.
Migrazione da un altro plugin contatti
Se usi @capacitor-community/contacts (8.0.0 al momento della stesura), il suo Android pickContact richiede il gruppo di permessi contatti prima di aprire il picker, quindi legge il contatto completo dalla rubrica. Non esiste una modalità property. Anche i nomi dei metodi differiscono (getContact vs getContactById, oggetti projection vs un fields array). Il nostro confronto tra il plugin community contacts e il plugin Capgo mappa ogni chiamata.
Se usi ancora un plugin Cordova contacts all'interno di Capacitor, ora è il momento di sostituirlo. Vedi migrare da Cordova a Capacitor.
Risoluzione problemi
Il picker restituisce un contatto senza numero di telefono. Hai chiamato pickContacts() senza property e l'app non ha READ_CONTACTS. Solo id e displayName (e su Android 17+, i campi autorizzati tramite picker) vengono restituiti. Aggiungi property.
Play Console indica ancora che l'app dichiara READ_CONTACTS. Una libreria lo aggiunge. Controlla il manifest unito e rimuovilo con tools:node="remove". Controlla anche le versioni precedenti in altri track, ogni artifact attivo conta.
Dichiarazione rifiutata. Inviti, referral e condivisione sono elencati come casi per il picker. Ripensa la feature o spiega chiaramente perché l'elenco completo è fondamentale (ad esempio, il friend matching che interroga l'intera rubrica).
iOS richiede il permesso per i contatti. Chiami un metodo che legge la rubrica. Il picker non ne ha mai bisogno. Rimuovi NSContactsUsageDescription se scegli solo uno.
Date chiave
| Data | Cosa succede |
|---|---|
| 15 aprile 2026 | Policy annunciata |
| Settembre 2026 | Play Console invita le app che dichiarano READ_CONTACTS a presentare una dichiarazione |
| 27 gennaio 2027 | Conformità obbligatoria per le app con target Android 17 (API 37) o successivi |
Controlla la pagina di aiuto di Play Console per la policy prima di inviare, Google può aggiornare scadenze e testi.