Per gestire il consenso GDPR di AdMob in un'app Capacitor, usa l'User Messaging Platform (UMP) di Google SDK: richiedi le informazioni sul consenso ad ogni avvio, mostra il modulo di consenso se necessario e inizializza gli annunci solo quando canRequestAds è true. Ti serve anche un punto di accesso alle opzioni privacy per permettere agli utenti di cambiare scelta e, su iOS, il flusso UMP deve precedere il prompt di App Tracking Transparency. Questa guida mostra l'intero flusso con due setup: un plugin che incapsula UMP in JavaScript, e @capgo/capacitor-admob con un piccolo bridge nativo per il consenso.
Cosa fa l'UMP e perché AdMob lo richiede
Da gennaio 2024, Google richiede agli editori che mostrano annunci agli utenti nello SEE, nel Regno Unito e in Svizzera di utilizzare una piattaforma di gestione del consenso (CMP) certificata da Google e integrata con l'IAB Transparency and Consent Framework (TCF). L'UMP SDK è la CMP certificata di Google, gratuita e integrata nella console AdMob.
L'UMP fa tre cose per te:
- Rileva se l'utente si trova in una regione in cui è richiesto il consenso.
- Mostra il messaggio di consenso configurato in AdMob, nella lingua dell'utente.
- Salva le scelte dell'utente come TC string sul dispositivo (lo standard
IABTCF_chiavi inUserDefaultssu iOS eSharedPreferencessu Android), che il Google Mobile Ads SDK e i partner di mediazione leggono quando richiedono annunci.
Puoi usare l'UMP anche per le normative sulla privacy degli stati USA, che AdMob chiama messaggi "US states", sempre dalla stessa console.
Passaggio 1: crea i messaggi in AdMob
Nella console di AdMob, vai su Privacy e messaggistica:
- Crea un Regolamenti europei messaggio (GDPR). Scegli a quali app applicarlo, le lingue e l'elenco dei partner pubblicitari.
- Opzionalmente, crea un Stati USA messaggio.
- Su iOS, crea un messaggio esplicativo IDFA se intendi richiedere l'App Tracking Transparency. UMP lo mostrerà prima del prompt ATT di sistema.
- Pubblica i messaggi. Un messaggio non pubblicato non verrà mai mostrato.
Se il modulo non appare più nella tua app, la prima cosa da controllare è se il messaggio è non pubblicato o non assegnato.
Passaggio 2: decidi l'ordine delle operazioni
L'ordine ideale per la maggior parte delle app:
- L'app si avvia.
- Richiedi l'aggiornamento delle info sul consenso con UMP (a ogni avvio).
- Se necessario, carica e mostra il modulo di consenso.
- Se
canRequestAdsè true, avvia il Mobile Ads SDK e carica gli annunci. - Mostra una voce “Impostazioni privacy” nella schermata settings quando UMP indica che le opzioni privacy sono richieste.
Google permette anche di avviare il Mobile Ads SDK in parallelo alla richiesta di consenso quando canRequestAds era già true in una sessione precedente. Questo riduce i tempi per il primo annuncio per gli utenti ricorrenti.
Opzione A: un plugin che incapsula UMP in JavaScript
@capacitor-community/admob (la versione 8 supporta Capacitor 8) espone i metodi UMP direttamente: requestConsentInfo, showConsentForm, showPrivacyOptionsForm e resetConsentInfo.
bun add @capacitor-community/admob
bunx cap sync
import {
AdMob,
AdmobConsentStatus,
AdmobConsentDebugGeography,
} from '@capacitor-community/admob';
export async function initAdsWithConsent(isDebug: boolean) {
await AdMob.initialize();
let info = await AdMob.requestConsentInfo(
isDebug
? {
debugGeography: AdmobConsentDebugGeography.EEA,
testDeviceIdentifiers: ['YOUR_TEST_DEVICE_ID'],
}
: undefined,
);
if (info.isConsentFormAvailable && info.status === AdmobConsentStatus.REQUIRED) {
info = await AdMob.showConsentForm();
}
// The enum value is the string 'REQUIRED'
const showPrivacyEntry = String(info.privacyOptionsRequirementStatus) === 'REQUIRED';
return { canRequestAds: info.canRequestAds, showPrivacyEntry };
}
export async function openPrivacyOptions() {
await AdMob.showPrivacyOptionsForm();
}
Questo plugin è l'unica eccezione all'ordine sopra indicato: il suo README richiede AdMob.initialize() prima requestConsentInfo(), e su iOS il modulo di consenso non può essere mostrato finché initialize() has run. initialize() avvia SDK ma non richiede annunci, quindi la regola fondamentale è non caricare mai un annuncio finché canRequestAds è vera. Se hai bisogno che SDK rimanga fermo finché l'utente non ha risposto, usa l'Opzione B, dove il consenso viene gestito prima AdMob.start().
Controlla canRequestAds di ogni caricamento di annunci, non solo all'avvio, poiché l'utente può revocare il consenso dal modulo delle opzioni sulla privacy.
Opzione B: @capgo/capacitor-admob con un bridge UMP nativo
@capgo/capacitor-admob ti offre AdMob.start(), la configurazione della richiesta, banner, interstitial, rewarded e rewarded interstitial, oltre all'autorizzazione al tracciamento su iOS. Non include UMP, quindi devi aggiungere un piccolo plugin locale per gestire il flusso di consenso prima di chiamare AdMob.start().
bun add @capgo/capacitor-admob
bunx cap sync
Aggiungi il SDK UMP
- iOS: aggiungi il
GoogleUserMessagingPlatformpackage tramite Swift Package Manager (Capacitor 8 usa SPM di default), o il pod CocoaPods con lo stesso nome se il tuo progetto usa ancora CocoaPods. - Android: in
android/app/build.gradle:
dependencies {
implementation "com.google.android.ump:user-messaging-platform:<latest version>"
}
Usa l'ultima release dal repository Maven di Google.
plugin di consenso iOS
Crea ios/App/App/ConsentPlugin.swift:
import Capacitor
import UserMessagingPlatform
@objc(ConsentPlugin)
public class ConsentPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "ConsentPlugin"
public let jsName = "Consent"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "gather", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "showPrivacyOptions", returnType: CAPPluginReturnPromise),
]
@objc func gather(_ call: CAPPluginCall) {
let parameters = RequestParameters()
DispatchQueue.main.async {
ConsentInformation.shared.requestConsentInfoUpdate(with: parameters) { error in
if let error = error {
call.reject(error.localizedDescription)
return
}
guard let vc = self.bridge?.viewController else {
call.reject("No view controller")
return
}
ConsentForm.loadAndPresentIfRequired(from: vc) { formError in
if let formError = formError {
call.reject(formError.localizedDescription)
return
}
call.resolve(self.state())
}
}
}
}
@objc func showPrivacyOptions(_ call: CAPPluginCall) {
DispatchQueue.main.async {
guard let vc = self.bridge?.viewController else {
call.reject("No view controller")
return
}
ConsentForm.presentPrivacyOptionsForm(from: vc) { formError in
if let formError = formError {
call.reject(formError.localizedDescription)
return
}
call.resolve(self.state())
}
}
}
private func state() -> [String: Any] {
return [
"canRequestAds": ConsentInformation.shared.canRequestAds,
"privacyOptionsRequired":
ConsentInformation.shared.privacyOptionsRequirementStatus == .required,
]
}
}
Registralo da una CAPBridgeViewController subclass e imposta quella classe sul view controller in Main.storyboard:
import Capacitor
class MainViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
bridge?.registerPluginInstance(ConsentPlugin())
}
}
Plugin per il consenso Android
Crea android/app/src/main/java/com/example/app/ConsentPlugin.java (usa il tuo package name):
package com.example.app;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.google.android.ump.ConsentInformation;
import com.google.android.ump.ConsentRequestParameters;
import com.google.android.ump.UserMessagingPlatform;
@CapacitorPlugin(name = "Consent")
public class ConsentPlugin extends Plugin {
@PluginMethod
public void gather(PluginCall call) {
ConsentInformation info = UserMessagingPlatform.getConsentInformation(getContext());
ConsentRequestParameters params = new ConsentRequestParameters.Builder().build();
getActivity().runOnUiThread(() ->
info.requestConsentInfoUpdate(
getActivity(),
params,
() -> UserMessagingPlatform.loadAndShowConsentFormIfRequired(getActivity(), formError -> {
if (formError != null) {
call.reject(formError.getMessage());
return;
}
call.resolve(state(info));
}),
requestError -> call.reject(requestError.getMessage())
)
);
}
@PluginMethod
public void showPrivacyOptions(PluginCall call) {
getActivity().runOnUiThread(() ->
UserMessagingPlatform.showPrivacyOptionsForm(getActivity(), formError -> {
if (formError != null) {
call.reject(formError.getMessage());
return;
}
call.resolve(state(UserMessagingPlatform.getConsentInformation(getContext())));
})
);
}
private JSObject state(ConsentInformation info) {
JSObject ret = new JSObject();
ret.put("canRequestAds", info.canRequestAds());
ret.put(
"privacyOptionsRequired",
info.getPrivacyOptionsRequirementStatus() ==
ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED
);
return ret;
}
}
Registralo in MainActivity.java prima super.onCreate:
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
registerPlugin(ConsentPlugin.class);
super.onCreate(savedInstanceState);
}
}
Chiamalo da TypeScript
import { registerPlugin } from '@capacitor/core';
import { AdMob, BannerAd } from '@capgo/capacitor-admob';
interface ConsentState {
canRequestAds: boolean;
privacyOptionsRequired: boolean;
}
interface ConsentPlugin {
gather(): Promise<ConsentState>;
showPrivacyOptions(): Promise<ConsentState>;
}
const Consent = registerPlugin<ConsentPlugin>('Consent');
export async function startAds() {
let state: ConsentState;
try {
state = await Consent.gather();
} catch (err) {
console.warn('Consent flow failed', err);
return { showPrivacyEntry: false };
}
if (state.canRequestAds) {
await AdMob.start();
const banner = new BannerAd({
adUnitId: 'ca-app-pub-3940256099942544/2934735716', // Google test banner (iOS)
position: 'bottom',
});
await banner.show();
}
return { showPrivacyEntry: state.privacyOptionsRequired };
}
export const openPrivacyOptions = () => Consent.showPrivacyOptions();
Native code changes need a new store build. After that, consent copy in your settings screen and ad placement logic can be shipped with live updates di Capgo.
Passaggio 3: aggiungi l'entry point per le opzioni privacy
Quando UMP segnala che sono necessarie le opzioni privacy, Google richiede un modo visibile per riaprire le scelte di consenso. Aggiungi una riga "Impostazioni privacy" alla tua pagina delle impostazioni e nascondila quando non è richiesta:
const { showPrivacyEntry } = await startAds();
document.querySelector('#privacy-row')?.toggleAttribute('hidden', !showPrivacyEntry);
document.querySelector('#privacy-row')?.addEventListener('click', () => openPrivacyOptions());
Dopo che l'utente ha modificato le scelte, leggi canRequestAds di nuovo prima della prossima richiesta di ad.
Passaggio 4: App Tracking Transparency su iOS
L'ATT è distinta dal GDPR. L'ATT controlla l'accesso all'IDFA su iOS, mentre il consenso GDPR determina se e come i dati personali possono essere trattati. Solitamente, per un utente UE su iOS, servono entrambi.
- Aggiungi
NSUserTrackingUsageDescriptionaInfo.plist. - Lascia che UMP mostri il messaggio esplicativo dell'IDFA e attivi l'ATT, se hai configurato tale messaggio in AdMob. Altrimenti, richiedi l'ATT manualmente dopo il flusso di consenso.
Con @capgo/capacitor-admob puoi leggere e richiedere lo stato ATT direttamente:
import { AdMob, TrackingAuthorizationStatus } from '@capgo/capacitor-admob';
const { status } = await AdMob.trackingAuthorizationStatus();
if (status === TrackingAuthorizationStatus.notDetermined) {
await AdMob.requestTrackingAuthorization();
}
Capgo ha anche una versione standalone plugin App Tracking Transparency se ti serve l'ATT per altri SDK. Ricorda di dichiarare il tracking nel tuo privacy manifest e nelle etichette sulla privacy dell'App Store; consulta la nostra guida al privacy manifest.
Passaggio 5: testa con debug geography
UMP mostra il modulo GDPR solo agli utenti situati in SEE, Regno Unito o Svizzera. Per testare altrove:
- Avvia l'app e cerca nel log la riga UMP con l'ID hash del tuo dispositivo.
- Aggiungilo come dispositivo di test e imposta la geografia di debug su SEE. Con il plugin della community, passa
debugGeographyetestDeviceIdentifiersarequestConsentInfo. In un bridge nativo, impostaDebugSettingssu iOS eConsentDebugSettingssu Android solo nelle build di debug. - Resetta il consenso tra un'esecuzione e l'altra (
resetConsentInfo()nel plugin della community,ConsentInformation.reset()nativamente) per far riapparire il modulo.
Non includere mai impostazioni di debug nelle build di release. Gestiscile tramite una build flag.
Passaggio 6: gestisci gli errori senza bloccare l'app
Le richieste di consenso possono fallire: assenza di rete, App ID errato o messaggio non pubblicato. Gestisci l'errore come "nessuna pubblicità per ora", non come un crash:
- Se
requestConsentInfoUpdatefallisce macanRequestAdsera vero in una sessione precedente, puoi comunque richiedere gli annunci. - Se il modulo non si carica, logga l'errore e riprova al prossimo avvio.
- Non mostrare mai annunci mentre il modulo di consenso è a schermo.
Risoluzione problemi
Il modulo non viene mai mostrato. Messaggio non pubblicato, non assegnato a questo app ID o ti trovi fuori dallo SEE senza debug geography. Controlla l'app ID di AdMob in Info.plist e AndroidManifest.xml corrisponde alla console.
Il modulo appare ad ogni avvio. L'utente lo ha chiuso senza scegliere, oppure chiami reset in produzione code.
canRequestAds false per gli utenti USA. Hai pubblicato un messaggio per gli stati USA e l'utente ha negato la vendita o la condivisione. Mostra solo annunci limitati tramite SDK, non bypassarlo.
I partner di mediazione non ricevono il consenso. Assicurati che ogni adapter del partner sia aggiornato e presente nella lista dei partner pubblicitari del tuo messaggio GDPR.
Il prompt iOS ATT non appare mai. NSUserTrackingUsageDescription manca, o l'utente ha disattivato “Consenti alle app di richiedere il tracciamento” nelle Impostazioni.
Compliance oltre il modulo
UMP gestisce la parte pubblicitaria. La tua app necessita comunque di una privacy policy che elenchi AdMob, le regole di retention dei dati e un modo per gestire le richieste sui dati. La nostra checklist per la compliance GDPR copre tutto il resto dell'app.