Claude-skill-registry android-admob

AdMob integration patterns for monetization - banner ads, interstitials, rewarded ads. Use when setting up ads, implementing different ad formats, or testing with test ad units.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/android-admob" ~/.claude/skills/majiayu000-claude-skill-registry-android-admob && rm -rf "$T"
manifest: skills/data/android-admob/SKILL.md
source content

Android AdMob Skill

AdMob integration patterns: banner ads, interstitials, rewarded ads.

When to Use

  • Setting up AdMob SDK
  • Implementing banner ads
  • Adding interstitial ads
  • Integrating rewarded ads
  • Testing with test ad units

Setup

Dependencies

[libraries]
play-services-ads = { module = "com.google.android.gms:play-services-ads", version = "24.3.0" }

Initialization

// In Application class
MobileAds.initialize(this) { initializationStatus ->
    Timber.d("AdMob initialized: $initializationStatus")
}

AndroidManifest.xml

<meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY"/>

Banner Ads

@Composable
fun BannerAd(modifier: Modifier = Modifier) {
    AndroidView(
        modifier = modifier.fillMaxWidth(),
        factory = { context ->
            AdView(context).apply {
                setAdSize(AdSize.BANNER)
                adUnitId = if (BuildConfig.DEBUG) {
                    "ca-app-pub-3940256099942544/6300978111" // Test ID
                } else {
                    BuildConfig.ADMOB_BANNER_ID
                }
                loadAd(AdRequest.Builder().build())
            }
        }
    )
}

// Adaptive banner (recommended)
@Composable
fun AdaptiveBannerAd(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    val windowMetrics = remember {
        WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context as Activity)
    }
    val adWidth = (windowMetrics.bounds.width() / context.resources.displayMetrics.density).toInt()

    AndroidView(
        modifier = modifier.fillMaxWidth(),
        factory = { ctx ->
            AdView(ctx).apply {
                setAdSize(AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(ctx, adWidth))
                adUnitId = BuildConfig.ADMOB_BANNER_ID
                loadAd(AdRequest.Builder().build())
            }
        }
    )
}

Interstitial Ads

class InterstitialAdManager(private val context: Context) {
    private var interstitialAd: InterstitialAd? = null

    fun loadAd() {
        val adRequest = AdRequest.Builder().build()
        val adUnitId = if (BuildConfig.DEBUG) {
            "ca-app-pub-3940256099942544/1033173712"
        } else {
            BuildConfig.ADMOB_INTERSTITIAL_ID
        }

        InterstitialAd.load(context, adUnitId, adRequest) { ad, error ->
            if (error != null) {
                Timber.e("Interstitial failed to load: ${error.message}")
                return@load
            }
            interstitialAd = ad
        }
    }

    fun showAd(activity: Activity, onDismissed: () -> Unit) {
        interstitialAd?.apply {
            fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdDismissedFullScreenContent() {
                    interstitialAd = null
                    onDismissed()
                    loadAd() // Preload next
                }
                override fun onAdFailedToShowFullScreenContent(error: AdError) {
                    interstitialAd = null
                    onDismissed()
                }
            }
            show(activity)
        } ?: onDismissed()
    }

    fun isLoaded(): Boolean = interstitialAd != null
}

Rewarded Ads

class RewardedAdManager(private val context: Context) {
    private var rewardedAd: RewardedAd? = null

    fun loadAd() {
        val adRequest = AdRequest.Builder().build()
        val adUnitId = if (BuildConfig.DEBUG) {
            "ca-app-pub-3940256099942544/5224354917"
        } else {
            BuildConfig.ADMOB_REWARDED_ID
        }

        RewardedAd.load(context, adUnitId, adRequest) { ad, error ->
            if (error != null) {
                Timber.e("Rewarded ad failed to load: ${error.message}")
                return@load
            }
            rewardedAd = ad
        }
    }

    fun showAd(activity: Activity, onRewarded: (RewardItem) -> Unit, onDismissed: () -> Unit) {
        rewardedAd?.apply {
            fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdDismissedFullScreenContent() {
                    rewardedAd = null
                    onDismissed()
                    loadAd() // Preload next
                }
            }
            show(activity) { reward ->
                onRewarded(reward)
            }
        } ?: onDismissed()
    }

    fun isLoaded(): Boolean = rewardedAd != null
}

Test Ad Units (Use in Debug)

TypeTest ID
App Openca-app-pub-3940256099942544/9257395921
Bannerca-app-pub-3940256099942544/6300978111
Interstitialca-app-pub-3940256099942544/1033173712
Interstitial Videoca-app-pub-3940256099942544/8691691433
Rewardedca-app-pub-3940256099942544/5224354917
Rewarded Interstitialca-app-pub-3940256099942544/5354046379
Nativeca-app-pub-3940256099942544/2247696110

Version Compatibility

Play Services AdsMin SDKTarget SDK
24.x2135
23.x2134
22.x1933

Error Handling

// Ad load error handling
InterstitialAd.load(context, adUnitId, adRequest) { ad, error ->
    if (error != null) {
        when (error.code) {
            AdRequest.ERROR_CODE_NETWORK_ERROR ->
                Timber.w("Network unavailable for ads")
            AdRequest.ERROR_CODE_NO_FILL ->
                Timber.d("No ad inventory available")
            AdRequest.ERROR_CODE_INTERNAL_ERROR ->
                Timber.e("AdMob internal error")
            else -> Timber.w("Ad error: ${error.message}")
        }
        return@load
    }
    interstitialAd = ad
}

// Show ad with fallback
fun showAdOrContinue(activity: Activity, onComplete: () -> Unit) {
    if (interstitialAd != null) {
        interstitialAd?.show(activity)
    } else {
        Timber.d("Ad not ready, continuing without ad")
        onComplete()
    }
}

Troubleshooting

IssueSolution
No fillNormal - try again later, use mediation
Test ads onlyCheck ad unit ID, device registration
Clicks not countingVerify no overlapping views
Policy violationReview ad placement, content

Security Checklist

  • Test IDs in BuildConfig.DEBUG
  • Production IDs in BuildConfig.RELEASE
  • No hardcoded ad unit IDs
  • Consent management (GDPR/CCPA)
  • App-ads.txt configured

Best Practices

  • Always use test IDs in debug builds
  • Preload ads before showing
  • Handle ad not available gracefully
  • Don't show ads too frequently
  • Follow AdMob policies strictly
  • Implement proper error handling
  • Consider user experience first

AdMob Policies Checklist

  • No accidental clicks (proper spacing)
  • No incentivizing clicks
  • No misleading ad placement
  • Proper ad labeling
  • No pop-ups or full-screen ads without user action
  • Content policy compliance

References

Use this skill for ethical, effective monetization.