Banners nativos
AdView / GADBannerView reales colocados sobre el borde del WebView — jamás renderizados en el DOM. Conscientes de safe areas: status bar, navigation bar y home indicator.
Banners nativos fuera del WebView, intersticiales, rewarded, flujo de consentimiento Google UMP y App Tracking Transparency de iOS — todo detrás de una única API de TypeScript fuertemente tipada con errores y eventos estructurados.
npm add tauri-plugin-ad2mob
cargo add tauri-plugin-ad2mobMi App
Tauri v2 · Android / iOS
Banner nativo de AdMob
AdView / GADBannerView · adaptive
Banner nativo sobre el WebView — nunca dentro del DOM
Introducción
Tauri v2.AdView / GADBannerView reales colocados sobre el borde del WebView — jamás renderizados en el DOM. Conscientes de safe areas: status bar, navigation bar y home indicator.
Máquinas de estado explícitas load → ready → show → closed con consultas is*Ready() y destroy explícito. La recompensa llega del callback real del SDK, nunca sintetizada.
Flujo de consentimiento Google UMP y ATT de iOS integrados. Las peticiones de anuncios se rechazan con CONSENT_REQUIRED mientras el estado UMP sea «required».
AdMobError con códigos estables, mapa de eventos tipado y tipos que reflejan uno a uno los modelos de Rust. TypeScript estricto de punta a punta.
Cada callback del SDK se reenvía como evento namespaced admob://* con payload tipado. AdMob.on() elige automáticamente el canal correcto en móvil y escritorio.
El crate compila para Windows, macOS y Linux; toda operación móvil devuelve un UNSUPPORTED_PLATFORM controlado. Tu build de escritorio no cambia.
Introducción
App ID de cada plataforma. Todo lo demás (SDKs nativos, keep-rules de R8, SPM de iOS) se resuelve automáticamente.npm add tauri-plugin-ad2mob
# también disponible en: pnpm · bun · yarn
cargo add tauri-plugin-ad2mobPeer dependency
@tauri-apps/api ^2.0.0, que ya tendrás instalado en cualquier proyecto Tauri v2.fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_ad2mob::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}Opcionalmente puedes inicializar en el arranque con configuración inline — equivalente a la sección plugins > admob de tauri.conf.json:
.plugin(tauri_plugin_ad2mob::init_with_config(serde_json::json!({
"isTesting": true,
"initializeOnStartup": true,
}))){
"permissions": [
"ad2mob:default"
]
}¿Por qué un único permiso?
ad2mob:default habilita todos los comandos, incluidos los listeners de eventos que usa AdMob.on(). Los anuncios no son una superficie sensible: el plugin nunca expone sistema de archivos, red ni capacidades del dispositivo al WebView.Añade el meta-data del App ID dentro de <application> en gen/android/app/src/main/AndroidManifest.xml (crea el proyecto Android con tauri android init). El plugin valida el App ID en runtime y falla con INVALID_CONFIGURATION si falta.
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY" />Desarrollo
ca-app-pub-3940256099942544~3347511713 mientras desarrollas. Los SDK de Google Mobile Ads (24.x) y UMP (3.x) se enlazan automáticamente desde el módulo Gradle del plugin.⚠️ iOS — en desarrollo activo
Añade estas claves al Info.plist (vía gen/apple o Xcode). Los frameworks GoogleMobileAds 13.x y UMP 3.x se resuelven con Swift Package Manager desde ios/Package.swift al generar el proyecto Xcode.
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY</string>
<key>NSUserTrackingUsageDescription</key>
<string>Your data will be used to show you more relevant ads.</string>Desarrollo
ca-app-pub-3940256099942544~1458002511. Para publicar en el App Store recuerda además declarar ATT y los identificadores de publicidad en tus respuestas de App Privacy, y añadir los SKAdNetworkItems de Google.Introducción
import { AdMob } from "tauri-plugin-ad2mob"
// 1. Detecta soporte e inicializa (idempotente)
if (await AdMob.isSupported()) {
await AdMob.initialize({ isTesting: true })
}
// 2. Configura tus Ad Unit IDs de producción
await AdMob.configure({
adUnitIds: {
banner: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
interstitial: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
rewarded: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
},
})
// 3. Suscríbete a eventos ANTES de operar
await AdMob.on("admob://rewarded-earned", ({ payload }) => {
console.log("Recompensa:", payload.amount, payload.type)
})
// 4. Muestra un banner nativo
await AdMob.showBanner({ position: "bottom", size: "adaptive" })Si prefieres no llamar a initialize() en tu código, activa initializeOnStartup en la configuración del plugin: el SDK se inicializa solo cuando la app arranca, con el mismo AdMobConfig.
{
"plugins": {
"admob": {
"isTesting": true,
"debug": true,
"initializeOnStartup": true
}
}
}initialize() es idempotente
AdMob.configure() para cambiar los Ad Unit IDs.Privacidad
required, toda petición de anuncios se rechaza con CONSENT_REQUIRED — los anuncios nunca se piden sin consentimiento.const { status } = await AdMob.requestConsent()
// status: "unknown" | "required" | "notRequired" | "obtained"
const current = await AdMob.getConsentStatus()| Estado | Significado | ¿Se pueden pedir anuncios? |
|---|---|---|
| unknown | Aún no se ha consultado el estado UMP. | No — CONSENT_REQUIRED |
| required | El usuario debe completar el formulario de consentimiento. | No — CONSENT_REQUIRED |
| notRequired | No se requiere consentimiento para esta ubicación/configuración. | Sí |
| obtained | El usuario completó el formulario de consentimiento. | Sí |
No persistas el consentimiento tú mismo
automaticallyRequestConsent: true (por defecto) el flujo ya se ejecuta durante initialize(); solo llama requestConsent() manualmente si lo desactivaste o quieres ofrecer un botón de «opciones de privacidad».Privacidad
requestTrackingAuthorization: true en initialize() para mostrar el prompt justo después del arranque.const status = await AdMob.requestTrackingAuthorization()
// iOS: "notDetermined" | "restricted" | "denied" | "authorized"
// Android y escritorio: "notAvailable" — seguro de llamar sin condiciones
const known = await AdMob.getTrackingAuthorizationStatus()Requisito de Info.plist
NSUserTrackingUsageDescription en el Info.plist (ver Instalación → iOS). Además solo se muestra una vez por instalación; reinstala o restablece los ajustes de privacidad del simulador para verlo de nuevo.Anuncios
Mutex y las cargas obsoletas nunca corrompen el estado.await AdMob.loadInterstitial() // resuelve cuando el anuncio está cargado
if (await AdMob.isInterstitialReady()) {
await AdMob.showInterstitial() // resuelve cuando el usuario lo cierra
}
await AdMob.destroyInterstitial() // libera el anuncio cargado, si lo hayLos anuncios se consumen
show consume el anuncio. Recarga después de cada evento *-closed. Si llamas show sin carga previa, la promesa rechaza con AD_NOT_READY; fallos del SDK llegan como LOAD_FAILED / SHOW_FAILED con el detalle en el evento *-failed.Anuncios
OnUserEarnedRewardListener en Kotlin, GADRewardedAdDelegate en Swift). Cerrar el anuncio sin completarlo emite admob://rewarded-closed — pero jamás una recompensa.const unlisten = await AdMob.on("admob://rewarded-earned", ({ payload }) => {
// payload: { adUnitId?, amount, type } — callback REAL del SDK
grantReward(payload.amount, payload.type)
})
await AdMob.loadRewarded()
if (await AdMob.isRewardedReady()) {
await AdMob.showRewarded() // resuelve cuando el usuario lo cierra
}
// cuando ya no lo necesites:
// unlisten()Nunca otorgues recompensas desde rewarded-closed
admob://rewarded-earned, que proviene del listener nativo del SDK mientras el usuario está viendo el anuncio. Confiar en el evento de cierre permitiría cobrar premios sin ver el anuncio.Referencia
AdMob.on(evento, handler) antes de inicializar para no perderte ninguno. El campo stage distingue fallos de carga ("load") de fallos de muestra ("show") — los eventos de banner lo omiten.| Evento | Tipo de payload | Campos |
|---|---|---|
admob://initialized | InitializedEvent | platform, testing |
admob://consent-changed | ConsentChangedEvent | status |
admob://tracking-authorization-changed | TrackingAuthorizationChangedEvent | status |
Referencia
AdMob, agrupados por área. Todos son seguros de llamar sin condiciones: en escritorio, las operaciones de anuncios rechazan con UNSUPPORTED_PLATFORM mientras el núcleo (initialize, configure, getStatus, destroy y consultas de estado) sigue funcionando.AdMob.initialize(options?: AdMobConfig)→ Promise<InitializationResult>Inicializa el SDK de Google Mobile Ads. Es idempotente: llamarlo de nuevo es un no-op seguro que devuelve el estado actual. Con isTesting: true los Ad Unit IDs que falten se resuelven automáticamente a los oficiales de Google.
| Parámetro | Tipo | Descripción |
|---|---|---|
| options.appId | string | App ID genérico para ambas plataformas. |
| options.androidAppId | string | App ID para Android (prioridad sobre appId). |
| options.iosAppId | string | App ID para iOS (prioridad sobre appId). |
| options.isTesting | boolean | Modo desarrollo: resuelve test IDs oficiales. |
| options.initializeOnStartup | boolean | Inicializa al arrancar desde tauri.conf.json. |
| options.requestTrackingAuthorization | boolean | Solo iOS: pide ATT tras inicializar. |
| options.automaticallyRequestConsent | boolean | Ejecuta el flujo UMP durante la inicialización. Por defecto true. |
| options.debug | boolean | Logs detallados del plugin. Sin datos personales. |
INVALID_CONFIGURATIONNATIVE_ERRORconst result = await AdMob.initialize({
appId: "ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY",
isTesting: true,
})
// { initialized: true, platform: "android", testing: true }AdMob.configure(options: ConfigureOptions)→ Promise<void>Configura los Ad Unit IDs a nivel de aplicación (se fusionan sobre los valores previos). Orden de resolución de cualquier ID: argumento explícito → configure() → test IDs de Google si isTesting → error INVALID_CONFIGURATION.
| Parámetro | Tipo | Descripción |
|---|---|---|
| options.adUnitIds.banner | string | Ad Unit ID para banners. |
| options.adUnitIds.interstitial | string | Ad Unit ID para intersticiales. |
| options.adUnitIds.rewarded | string | Ad Unit ID para rewarded. |
INVALID_ARGUMENTawait AdMob.configure({
adUnitIds: {
banner: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
interstitial: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
rewarded: "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY",
},
})AdMob.isSupported()→ Promise<boolean>Devuelve true en Android e iOS, false en Windows, macOS y Linux. Úsalo para omitir la lógica de anuncios en escritorio.
if (!(await AdMob.isSupported())) return
// solo llega aquí en móvilAdMob.getStatus()→ Promise<AdMobStatus>Instantánea del estado completo del plugin: inicialización, plataforma, modo test, consentimiento, ATT y disponibilidad de cada formato.
const status = await AdMob.getStatus()
// { initialized, platform, testing, consentStatus, trackingStatus,
// interstitialReady, rewardedReady, bannerVisible }AdMob.destroy()→ Promise<void>Limpieza global: libera el banner, el intersticial y el rewarded, elimina los recursos nativos y resetea el estado para poder volver a inicializar.
await AdMob.destroy() // libera todos los recursos de anunciosAdMob.requestConsent()→ Promise<ConsentResult>Ejecuta el flujo de Google UMP: actualiza la información de consentimiento y muestra el formulario solo si es necesario. Mientras el estado sea required, las peticiones de anuncios rechazan con CONSENT_REQUIRED.
UNSUPPORTED_PLATFORMNATIVE_ERRORconst { status } = await AdMob.requestConsent()
if (status === "obtained") {
// consentimiento listo, los anuncios pueden pedirse
}AdMob.getConsentStatus()→ Promise<ConsentStatus>Último estado UMP conocido: unknown, required, notRequired u obtained.
const status = await AdMob.getConsentStatus()AdMob.requestTrackingAuthorization()→ Promise<TrackingAuthorizationStatus>Muestra el prompt de ATT de iOS. En Android y escritorio resuelve "notAvailable" sin lanzar error, así que es seguro llamarlo sin condiciones. Nunca se solicita de forma automática salvo que lo actives en initialize().
const status = await AdMob.requestTrackingAuthorization()
if (status === "authorized") {
// el usuario permite el rastreo: mejor eCPM
}AdMob.getTrackingAuthorizationStatus()→ Promise<TrackingAuthorizationStatus>Último estado ATT conocido, sin mostrar ningún prompt.
const status = await AdMob.getTrackingAuthorizationStatus()AdMob.loadInterstitial(options?: LoadAdOptions)→ Promise<void>Carga un intersticial; la promesa resuelve cuando el anuncio está listo para mostrarse. Puede tardar segundos en conexiones lentas.
| Parámetro | Tipo | Descripción |
|---|---|---|
| options.adUnitId | string | Ad Unit ID opcional; si se omite se usa el configurado o el de test. |
NOT_INITIALIZEDINVALID_CONFIGURATIONINVALID_ARGUMENTLOAD_FAILEDCONSENT_REQUIREDUNSUPPORTED_PLATFORMawait AdMob.loadInterstitial()AdMob.showInterstitial()→ Promise<void>Muestra un intersticial previamente cargado. La promesa resuelve cuando el usuario lo cierra. Rechaza con AD_NOT_READY si no hay nada cargado.
AD_NOT_READYSHOW_FAILEDNOT_INITIALIZEDCONSENT_REQUIREDUNSUPPORTED_PLATFORMif (await AdMob.isInterstitialReady()) {
await AdMob.showInterstitial()
}AdMob.isInterstitialReady()→ Promise<boolean>true cuando hay un intersticial cargado y listo para mostrar.
const ready = await AdMob.isInterstitialReady()AdMob.destroyInterstitial()→ Promise<void>Destruye el intersticial cargado, si lo hay.
await AdMob.destroyInterstitial()AdMob.loadRewarded(options?: LoadAdOptions)→ Promise<void>Carga un anuncio rewarded; resuelve cuando está listo para mostrarse.
| Parámetro | Tipo | Descripción |
|---|---|---|
| options.adUnitId | string | Ad Unit ID opcional; si se omite se usa el configurado o el de test. |
NOT_INITIALIZEDINVALID_CONFIGURATIONINVALID_ARGUMENTLOAD_FAILEDCONSENT_REQUIREDUNSUPPORTED_PLATFORMawait AdMob.loadRewarded()AdMob.showRewarded()→ Promise<void>Muestra el rewarded cargado. Resuelve cuando el usuario lo cierra; la recompensa llega por el evento admob://rewarded-earned desde el callback real del SDK.
AD_NOT_READYSHOW_FAILEDNOT_INITIALIZEDCONSENT_REQUIREDUNSUPPORTED_PLATFORMif (await AdMob.isRewardedReady()) {
await AdMob.showRewarded()
}AdMob.isRewardedReady()→ Promise<boolean>true cuando hay un rewarded cargado y listo para mostrar.
const ready = await AdMob.isRewardedReady()AdMob.destroyRewarded()→ Promise<void>Destruye el rewarded cargado, si lo hay.
await AdMob.destroyRewarded()AdMob.on(E extends AdMobEventName>(event: E, handler: (payload: AdMobEventMap[E]) => void)→ Promise<Unlisten>Suscribe un handler a un evento del plugin y devuelve una función unlisten awaitable. El mapa de eventos es totalmente tipado: el payload se infiere del nombre del evento. En móvil usa el canal de eventos del plugin; en escritorio, el sistema global.
| Parámetro | Tipo | Descripción |
|---|---|---|
| eventrequerido | AdMobEventName | Nombre del evento, p. ej. "admob://rewarded-earned". |
| handlerrequerido | (payload) => void | Callback tipado según AdMobEventMap. |
const unlisten = await AdMob.on("admob://rewarded-earned", ({ payload }) => {
console.log("+" + payload.amount, payload.type)
})
// para desuscribirse:
// await unlisten()Referencia
src/models.rs) y forma parte de la API estable del plugin. Estos son los principales; el resto se exporta desde tauri-plugin-ad2mob.// Configuración — misma forma que "plugins > ad2mob" en tauri.conf.json
export interface AdMobConfig {
appId?: string // App ID genérico
androidAppId?: string // prioridad sobre appId en Android
iosAppId?: string // prioridad sobre appId en iOS
isTesting?: boolean // resuelve los test IDs oficiales de Google
initializeOnStartup?: boolean
requestTrackingAuthorization?: boolean // solo iOS, tras initialize
automaticallyRequestConsent?: boolean // por defecto: true
debug?: boolean // logs detallados; sin datos personales
}
export interface AdUnitIds {
banner?: string
interstitial?: string
rewarded?: string
}
export interface ShowBannerOptions {
adUnitId?: string
position?: BannerPosition // "top" | "bottom"
size?: BannerSize
}
export interface LoadAdOptions {
adUnitId?: string // si se omite: configure() → test IDs
}
// Instantánea de estado que devuelve getStatus()
export interface AdMobStatus {
initialized: boolean
platform: AdMobPlatform
testing: boolean
consentStatus: ConsentStatus
trackingStatus: TrackingAuthorizationStatus
interstitialReady: boolean
rewardedReady: boolean
bannerVisible: boolean
}
// Recompensa real entregada por el SDK en admob://rewarded-earned
export interface Reward {
amount: number
type: string
}
// Cada método rechaza con un AdMobError (subclase de Error) con "code" estable
export class AdMobError extends Error {
readonly code: AdMobErrorCode
}
export function isAdMobError(error: unknown): error is AdMobError| Unión de literales | Valores |
|---|---|
BannerPosition | "top" | "bottom" |
BannerSize | "banner" | "largeBanner" | "mediumRectangle" | "fullBanner" | "leaderboard" | "adaptive" |
ConsentStatus | "unknown" | "required" | "notRequired" | "obtained" |
TrackingAuthorizationStatus | "notDetermined" | "restricted" | "denied" | "authorized" | "notAvailable" |
AdMobPlatform | "android" | "ios" | "windows" | "macos" | "linux" |
AdMobErrorCode | NOT_INITIALIZED · AD_NOT_READY · LOAD_FAILED · SHOW_FAILED · INVALID_CONFIGURATION · INVALID_ARGUMENT · CONSENT_REQUIRED · UNSUPPORTED_PLATFORM · NATIVE_ERROR |
Referencia
AdMobError — una subclase de Error — con un campo code estable y compartido con el enum de errores de Rust. Usa isAdMobError() como type guard.import { AdMob, isAdMobError } from "tauri-plugin-ad2mob"
try {
await AdMob.showInterstitial()
} catch (error) {
if (isAdMobError(error) && error.code === "AD_NOT_READY") {
await AdMob.loadInterstitial()
}
}| Código | Cuándo ocurre | Qué hacer |
|---|---|---|
NOT_INITIALIZED | Operación de anuncios antes de initialize(). | Inicializa el plugin al arrancar la app. |
INVALID_CONFIGURATION | Falta o es inválido el App ID, un Ad Unit ID o la configuración de plataforma. | Revisa el manifest / Info.plist y configure(). |
INVALID_ARGUMENT | Argumentos malformados. | Revisa tipos y valores de las opciones. |
AD_NOT_READY | show*() sin anuncio cargado. | Carga primero y recarga tras cada cierre. |
LOAD_FAILED | El SDK no pudo cargar el anuncio. | Mira el evento *-failed y reintenta con backoff. |
SHOW_FAILED | El SDK no pudo presentar el anuncio. | Mira el evento *-failed (stage: show) y reintenta. |
CONSENT_REQUIRED | El estado UMP es required. | Ejecuta requestConsent() y completa el formulario. |
UNSUPPORTED_PLATFORM | API de móvil usada en escritorio. | Filtra con isSupported() si quieres omitir en silencio. |
NATIVE_ERROR | Cualquier otro error reportado por la capa nativa. | Inspecciona message y los eventos asociados. |
Producción
isTesting: true, los Ad Unit IDs que falten se resuelven a los oficiales de Google. Estos son los IDs explícitos si prefieres fijarlos a mano (App IDs de test: Android ~3347511713, iOS ~1458002511).| Formato | Android | iOS |
|---|---|---|
| Banner | ca-app-pub-3940256099942544/6300978111 | ca-app-pub-3940256099942544/2934735716 |
| Intersticial | ca-app-pub-3940256099942544/1033173712 | ca-app-pub-3940256099942544/441146891 |
| Rewarded | ca-app-pub-3940256099942544/5224354917 | ca-app-pub-3940256099942544/1717083536 |
Emuladores y simuladores
Nunca hagas clic en tus propios anuncios
Dispositivos de prueba con anuncios reales
testDeviceIds via MobileAds.setRequestConfiguration) para recibir anuncios de prueba con tus Ad Unit IDs reales.Producción
| API | Comportamiento en Windows / macOS / Linux |
|---|---|
initialize() | No-op correcto: el estado se registra y se emite admob://initialized. |
configure(), getStatus(), isSupported() y consultas de estado | Funcionan con normalidad. |
requestTrackingAuthorization() | Resuelve notAvailable sin lanzar error. |
requestConsent() y toda operación de anuncios | Rechazan con UNSUPPORTED_PLATFORM. |
destroy() | No-op correcto. |
Patrón recomendado
if (await AdMob.isSupported()) {
await AdMob.initialize({ isTesting: true })
}Producción
Producción