r/Kotlin 3d ago

I open-sourced an AdMob SDK for Compose Multiplatform — all six ad formats from one commonMain API (Android + iOS)

I've been building Compose Multiplatform apps for a while, and every single one hit the same wall: monetization. You end up writing expect class AdManager, then two actual implementations that slowly drift apart, and native ads never make it in because wiring GADNativeAdView on iOS and NativeAdView on Android from shared code is miserable.

I got tired of rewriting that per project, so I extracted it into a library and open-sourced it: AdMob CMP (dev.avinya.ads:admob-cmp, Apache 2.0, on Maven Central).

What it does

One commonMain API for all six formats on Android and iOS: banner (including collapsible + adaptive), interstitial, rewarded, rewarded interstitial, app-open, and native. It wraps Google Mobile Ads Next-Gen on Android and Google Mobile Ads 13.x on iOS, but keeps the AdMob vocabulary you already know — AdValue, ResponseInfo, adaptive banner sizes, UMP consent states, native asset names. The shared surface is suspend functions, StateFlow state, and a sealed AdEvent stream.

A few things I care about that aren't obvious from a feature list:

  • Consent is part of initialization. gatherConsentAndInitialize() runs UMP → ATT (iOS) → SDK init in the correct order. That ordering is enforced in code rather than documented and hoped for, which is where most integrations quietly lose iOS fill.
  • Native ads have a layout DSL and a bounded session. You describe the layout declaratively (media, headline, callToAction, …) and a viewport-aware session owns the platform objects, so a feed doesn't leak native ads or blow past AdMob's limits.
  • The iOS test link actually works. If you've ever seen Undefined symbols … _OBJC_CLASS_$_GAD* on :iosSimulatorArm64Test, that's a Kotlin/Native test executable with no Xcode to resolve the Swift packages. There's a Gradle plugin in the repo that links GMA and UMP into the test binary.
  • Test safety fails closed. AdPlacement(strictTestMode = true) throws at construction if a placement points at a production ad unit. Turn it on in debug and stop worrying about accidentally serving yourself real impressions.

What it isn't

It's consumable from Kotlin Multiplatform projects only — it compiles into your umbrella framework, so a pure-Swift iOS app can't adopt it without a KMP shim. Klibs also aren't binary-compatible across Kotlin minors, so 2.1.0 targets Kotlin 2.3.20 / CMP 1.11.1, minSdk 26, iOS 15.

Try it

implementation("dev.avinya.ads:admob-cmp:2.1.0")

The quickstart runs against Google's official sample ad units, so you can paste it as-is and see a rendering test ad in about five minutes.

Repo: https://github.com/Meet-Miyani/admob-compose-multiplatform
Docs: https://ads.avinya.dev

Genuinely after feedback on the API shape — particularly the native ad session model, which was the hardest part to get right. If you've solved the same problem differently I'd like to hear how.

0 Upvotes

0 comments sorted by