← back to Boomer Calculator
components/Ads.tsx
84 lines
'use client'
import { useEffect } from 'react'
import { Capacitor } from '@capacitor/core'
/**
* Platform-split monetization.
*
* • WEB (boomercalc.com / vercel) → Google AdSense Auto-ads (legit on the web).
* • NATIVE iOS app (Capacitor) → Google AdMob banner (Apple-compliant; AdSense
* web tags are NOT permitted inside apps).
*
* Capacitor wraps the SAME static `out/` for both, so the decision is made at
* runtime via Capacitor.isNativePlatform() — never inject AdSense into the app,
* never initialize AdMob on the web.
*
* The AdMob IDs below are the REAL ids for "Boomer Calc" (AdMob console,
* pub-5278231299883833, created 2026-08-07). The app id also lives in
* ios/App/App/Info.plist (GADApplicationIdentifier).
*/
const ADSENSE_CLIENT = 'ca-pub-5278231299883833'
// Real AdMob ids for Boomer Calc (iOS).
const ADMOB = {
iosAppId: 'ca-app-pub-5278231299883833~7368317108',
iosBanner: 'ca-app-pub-5278231299883833/7591678383',
}
function isNative(): boolean {
try {
return Capacitor.isNativePlatform()
} catch {
return false
}
}
export default function Ads() {
useEffect(() => {
if (isNative()) {
// ---- NATIVE: AdMob ----
// Dynamic import so the web bundle never pulls the native-only plugin.
;(async () => {
try {
const mod = await import('@capacitor-community/admob')
const { AdMob, BannerAdPosition, BannerAdSize } = mod
// App Tracking Transparency is its own call in v7; personalization
// degrades gracefully if the user denies.
try {
await AdMob.requestTrackingAuthorization()
} catch {
/* ATT unavailable (<iOS14) or already answered — ignore */
}
await AdMob.initialize({
initializeForTesting: false,
})
await AdMob.showBanner({
adId: ADMOB.iosBanner,
adSize: BannerAdSize.ADAPTIVE_BANNER,
position: BannerAdPosition.BOTTOM_CENTER,
isTesting: false, // real ad unit; AdMob limits serving until the app is approved
})
} catch (e) {
// Never let an ad failure break the (joke) calculator.
// eslint-disable-next-line no-console
console.warn('[Ads] AdMob init skipped:', e)
}
})()
} else {
// ---- WEB: AdSense Auto-ads ----
if (typeof document === 'undefined') return
if (document.querySelector('script[data-boomer-adsense]')) return
const s = document.createElement('script')
s.async = true
s.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ADSENSE_CLIENT}`
s.crossOrigin = 'anonymous'
s.setAttribute('data-boomer-adsense', '1')
document.head.appendChild(s)
}
}, [])
return null
}