Google AdMob Next Gen SDK: Implementing Inline Adaptive Banners in Jetpack Compose

Mobile advertising in today’s dynamic market is visible everywhere, from your favorite websites to your Android or iOS apps. This is used as a strategy to keep some content free of charge in exchange for in-app ads to the users.
Google dominates the digital advertising market, accounting for the majority of global advertising revenue. Hence, they develop an SDK for developers to integrate and display in-app ads more easily, which is the Google AdMob. It is a mobile advertising platform that helps app developer monetize their apps by displaying in-app ads. In such a manner, developers can earn some revenue from a vast network of advertisers while enabling advertisers to reach their target audience within the mobile apps.
AdMob simplifies this complex process of in-app advertising by providing developers with an AdMob SDK (Software Developer Kit). That enables them to integrate it into their applications, creating designated “ad units” where ads can be displayed. Once integrated, it leverages Google’s immense advertising ecosystem to automatically deliver relevant and high-performing ads to app users. These ads are generated and paid for by advertisers (in most cases are companies), with developers earning revenue for impressions, clicks or other user interactions with the ads.
Besides simply showing ads, AdMob also offers a suite of tools and features to optimize monetization, enhance user experience, and provide valuable insight into ad performance. The goal is to empower developers to focus on building the app while AdMob handles the task of ad serving, targeting the audience, and payment.
With AdMob any app developer can transform their passion into a profitable venture. AdMob provides a robust and accessible solution for generating sustainable income through in-app advertising.
AdMob Next Gen Ads SDK
The current Android AdMob SDK provides such feature and ability. Recently Google introduced a brand new AdMob SDK called AdMob Next Gen Ads which improves ads loading performance and the ability to pre-fetch ads for a smoother ad display experience.
Supported Ad format
This new AdMob SDK offers various ad formats to suit different app experiences, including:
- Banner ads: Small, rectangular ads that appear at the top or bottom of the screen or sometimes in between a list item. Examples: Inline adaptive, Collapsible & Fixed size.
- Interstitial ads: A full-screen ad that appears at natural transition points in an app.
- Native ads: Customizable ad formats that blend seamlessly with the app’s design and content.
- Rewarded ads: Opt-in video ads that users watch in exchange for in-app rewards
Configure your app
To configure your app, add the corresponding dependency and initialize MobileAd by following the steps in the following link. For simplification reasons, we are going to use the dedicated sample AdMob app ID:
ca-app-pub-3940256099942544~3347511713
UMP SDK implementation (Important) Before implementing the Next Gen Ads SDK in your Android app, you must get consent from the user before proceeding. This is important for data collection, especially under regulations like GDPR (General Data Protection Regulation) in the EEA (European Economic Area) and the CCPA (California Consumer Privacy Act). To comply with these regulations, Google introduced the UMP (User Messaging Platform) SDK for developers. For the full guide on how to implement it, read the following article. |
Inline adaptive banner ads (using AdMob Next Gen Ad SDK)
An inline adaptive banner ad provides the ability to dynamically adjust itself to the optimal ad size. This type is widely used in news apps that want to display ads at a specific position in lazy columns. AdMob Next Gen Ads SDK provides an easy way to implement it, and for users that is coming from the current AdMob SDK can easily migrate to the new implementation.
In this article, we want to achieve the following result:
To make the process as simple as possible, we are going to use the test adUnit:
ca-app-pub-3940256099942544/9214589741
Implementation
As previously described, this type is quite dynamic, which introduces new opportunities to improve ad performance.
@Composable
fun InlineAdaptiveStatic(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text("Next Gen Banner ad on static view", style = MaterialTheme.typography.titleSmall, modifier = Modifier.padding(top = 16.dp))
BannerAdView(bannerAdUnit = NextGenAdUnit.BannerAd(""))
}
}
Banner Ad View
Composable
fun BannerAdView(bannerAdUnit: NextGenAdUnit) {
val activity = LocalActivity.current
val isInPreview = LocalInspectionMode.current
if (activity == null) {
BannerAdViewFailedPlaceHolder()
return
}
val initialViewHeight = remember {
mutableStateOf(300.dp)
}
if (initialViewHeight.value == 0.dp)
return
val loadingViewHeight = remember {
mutableStateOf(300.dp)
}
val isLoadingAds = remember { mutableStateOf(true) }
var parent by remember { mutableStateOf<FrameLayout?>(null) }
var banner_Ad_View by remember { mutableStateOf<View?>(null) }
var banner_Ad by remember { mutableStateOf<BannerAd?>(null) }
Box(
modifier = Modifier
.fillMaxWidth()
.animateContentSize()
) {
if (isInPreview) {
BannerAdViewFailedPlaceHolder()
return
}
AndroidView(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(),
update = {
it.requestLayout()
},
factory = { context ->
FrameLayout(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}.also { adLayout ->
if (!isInPreview) {
parent = adLayout
MobileAdsManager.fetchBannerAd(adUnit = bannerAdUnit) { bannerAdView ->
isLoadingAds.value = false
if (bannerAdView == null) {
initialViewHeight.value = 0.dp
} else {
bannerAdView.apply {
banner_Ad = this
initialViewHeight.value = getAdSize().height.dp
// Banner Ad refresh callback
bannerAdRefreshCallback = object : BannerAdRefreshCallback {
override fun onAdRefreshed() {
super.onAdRefreshed()
println("[Banner Ad View] - onAdRefreshed")
}
override fun onAdFailedToRefresh(adError: LoadAdError) {
super.onAdFailedToRefresh(adError)
println("[Banner Ad View] - Ad Failed to refresh, cause: ${adError.message}")
}
}
adEventCallback = object : BannerAdEventCallback {
override fun onAdShowedFullScreenContent() {
super.onAdShowedFullScreenContent()
println("[Banner Ad View] - onAdShowedFullScreenContent")
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
println("[Banner Ad View] - onAdDismissedFullScreenContent")
}
override fun onAdFailedToShowFullScreenContent(
fullScreenContentError: FullScreenContentError
) {
super.onAdFailedToShowFullScreenContent(
fullScreenContentError
)
println("[Banner Ad View] - onAdFailedToShowFullScreenContent")
}
override fun onAdImpression() {
super.onAdImpression()
println("[Banner Ad View] - onAdImpression")
}
override fun onAdClicked() {
super.onAdClicked()
println("[Banner Ad View] - onAdClicked")
}
}
activity?.runOnUiThread {
this.getView(activity).also { bannerAdView ->
println("[Banner Ad View Parent] - Banner ads with unit ID: ${bannerAdUnit.id} - parent: ${bannerAdView.parent}")
try {
if (bannerAdView.parent != null)
(bannerAdView.parent as ViewGroup).removeView(
bannerAdView
)
adLayout.addView(bannerAdView)
banner_Ad_View = bannerAdView
} catch (e: Exception) {
e.printStackTrace()
initialViewHeight.value = 0.dp
println("[Banner Ad View Parent] [Exception] - Error loading banner ads, cause: ${e.message}")
} catch (e: Throwable) {
e.printStackTrace()
initialViewHeight.value = 0.dp
println("[Banner Ad View Parent] [Throwable] - Error loading banner ads, cause: ${e.message}")
}
}
}
}
}
}
}
}
}
)
AdLoadingView(
visible = isLoadingAds.value,
modifier = Modifier
.fillMaxWidth()
.height(loadingViewHeight.value)
)
}
DisposableEffect(Unit) {
onDispose {
if (parent != null && banner_Ad_View != null) {
banner_Ad_View?.let {
(it.parent as? ViewGroup)?.removeView(it)
}
parent?.removeAllViews()
}
banner_Ad?.destroy()
}
}
}
@Composable
private fun BannerAdViewFailedPlaceHolder(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.fillMaxWidth()
.height(400.dp)
.background(color = Color.LightGray)
) {
Text(
"Failed to load banner Ad View", color = Color.Black, modifier = Modifier.align(
Alignment.Center
)
)
}
}
Result

In future articles, we will cover the other types that AdMob offers, including native ads.
See our Github repository for the inline Adaptive and BannerAd view source code.