A lifecycle-aware banner wrapper for the
GMA Next-Gen SDK. It creates and
releases AdView, tracks load state, and forwards banner callbacks on the main thread.
Important
The 0.5.x release line uses GMA Next-Gen SDK 1.3.1 and requires Android API 24+,
compileSdk 35+, Kotlin 1.9+ for Kotlin apps, and completed SDK initialization before the first
ad request.
Make sure both Google Maven and Maven Central are configured:
repositories {
google()
mavenCentral()
}
def version ='0.5.2'dependencies {
// Views
implementation "com.lazygeniouz:acv:$version"// Compose; includes the view library transitively
implementation "com.lazygeniouz:acv-compose:$version"
}Choose the dependency for your UI toolkit; an app does not need to declare both.
The Next-Gen SDK is exposed transitively; don't add play-services-ads.
Apps using AdMob mediation must exclude the legacy SDK modules that adapters otherwise pull in:
configurations.configureEach {
exclude group: 'com.google.android.gms', module: 'play-services-ads'
exclude group: 'com.google.android.gms', module: 'play-services-ads-lite'
}Other mediation platforms are not currently compatible with Next-Gen.
Add the container to your layout:
<com.lazygeniouz.acv.AdContainerView
xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/adContainerView"android:layout_width="match_parent"android:layout_height="wrap_content"app:acv_adSize="LARGE_ADAPTIVE"app:acv_adUnitId="@string/banner_ad_unit_id" />Initialize Next-Gen in a background coroutine, then load the banner:
val adContainerView = findViewById<AdContainerView>(R.id.adContainerView)
adContainerView.setAdLoadCallback(object:AdLoadCallback<BannerAd> {
overridefunonAdLoaded(ad:BannerAd) {
// Banner loaded. This callback runs on the main thread.
}
overridefunonAdFailedToLoad(adError:LoadAdError) {
// Handle the load failure.
}
})
val config =InitializationConfig.Builder(ADMOB_APP_ID).build()
CoroutineScope(Dispatchers.IO).launch {
MobileAds.initialize(applicationContext, config)
withContext(Dispatchers.Main) {
adContainerView.loadAdView()
}
}With mediation, wait for the SDK initialization callback before loading so adapters are ready.
Next-Gen receives the app ID through InitializationConfig, not the legacy
com.google.android.gms.ads.APPLICATION_ID manifest entry. Apps using UMP must still keep that
manifest entry for UMP.
The legacy OPTIMIZE_INITIALIZATION and OPTIMIZE_AD_LOADING manifest flags are not part of the
Next-Gen setup. Initialize Next-Gen in a background coroutine instead.
The Compose artifact is a thin AndroidView wrapper around AdContainerView. It measures large
adaptive banners from the available Compose width and destroys the underlying view when it leaves
composition. It is built against Compose UI 1.10.6 to retain Kotlin 1.9 consumer compatibility:
val state = rememberAdContainerState()
AdaptiveAdContainer(
adUnitId =BANNER_AD_UNIT_ID,
state = state,
modifier =Modifier.fillMaxWidth()
)
TextButton(onClick = state::reload) {
Text("Reload")
}Use AdContainer when supplying a fixed size or customized BannerAdRequest. Remember customized
requests that should remain stable across recomposition; a different request instance reloads the
banner. AdContainerState.loadState reports idle, loading, loaded, and failed states. State-aware
overloads also accept AdLoadCallback<BannerAd>, BannerAdEventCallback, and
BannerAdRefreshCallback. reload() calls loadAdView() on the existing container; Compose does not
recreate it. Loading and failed states describe the latest request; a previous banner may remain
visible. Initialize Next-Gen before placing either composable in composition; Compose handles cleanup
when it leaves.
| XML attribute | Default | Description |
|---|---|---|
acv_adUnitId | Google test unit | Banner ad unit ID; test default matches the selected size |
acv_adSize | LARGE_ADAPTIVE | Large adaptive or fixed banner size |
acv_autoLoad | false | Loads during ON_CREATE; SDK initialization must already be complete |
SMART_BANNER has no Next-Gen equivalent. For source compatibility, the legacy
ADAPTIVE and SMART_BANNER XML values both resolve to LARGE_ADAPTIVE; use
LARGE_ADAPTIVE in new layouts.
The fixed XML options are BANNER, LARGE_BANNER, MEDIUM_RECTANGLE, FULL_BANNER, and
LEADERBOARD. WIDE_SKYSCRAPER was removed because Next-Gen does not support it as a standard
banner size.
You can also supply the ad unit and size directly:
adContainerView.loadAdView(adUnitId, adSize)For targeting or request extras, pass a customized BannerAdRequest:
val request =BannerAdRequest.Builder(adUnitId, adSize)
.addKeyword("games")
.build()
adContainerView.loadAdView(request)Both overloads accept parentHasListView and showOnCondition options. Setting
parentHasListView=true disables detach cleanup for recycled list items, so the caller must invoke
destroyAd() when its lifecycle ends.
Next-Gen separates banner callbacks by purpose:
setAdLoadCallback()— initial load success or failuresetAdEventCallback()— click, impression, paid, app, and full-screen eventssetAdRefreshCallback()— automatic refresh success or failure
AdContainerView delivers callbacks registered through these methods on the main thread. Pass null
to clear a callback.
getAdView()returns the current Next-GenAdView.isLoading(),isAdLoaded(), andisVisible()expose banner state.getAdSize()andgetAdUnitId()expose the active request configuration.removeAd()anddestroyAd()release the current banner. Detached views are cleaned up automatically unlessparentHasListView=true.
| 0.4.x | 0.5.x |
|---|---|
play-services-ads | ads-mobile-sdk:1.3.1 |
| Minimum API 21 | Minimum API 24 |
| Manifest app ID | InitializationConfig.Builder(appId) |
AdRequest | BannerAdRequest with ad unit ID and size |
AdListener | Load, event, and refresh callbacks |
| Smart/standard adaptive banner | Large anchored adaptive banner |
WIDE_SKYSCRAPER | Removed; no standard Next-Gen equivalent |
pauseAd() / resumeAd() | Removed; Next-Gen has no equivalent |
See Google's SDK migration guide and banner migration guide for more detail.