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
Requires Android API 24+ and a completed MobileAds.initialize() before the first ad request.
Each release builds against the current stable Kotlin, AGP and Next-Gen SDK; if you are pinned to
an older toolchain, check the releases
for a version that matches.
Make sure both Google Maven and Maven Central are configured:
repositories {
google()
mavenCentral()
}
def version = '0.5.3'
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> {
override fun onAdLoaded(ad: BannerAd) {
// Banner loaded. This callback runs on the main thread.
}
override fun onAdFailedToLoad(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:
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 |
| 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.