Using AdMob banner Ads in a Compose Layout

Using AdMob banner Ads in a Compose Layout

This is a real quick post to give you some pointers of how to use Google AdMob banner ads in an Android Jetpack Compose view layout.

Right off the bat I want to say two things:

1- The AdMob team hasn’t got their library up to date (in terms of supporting compose), so it’s always going to be a bit of a hack to use AdMob with compose

2- The below feels like a hack, because we load the advert from within the compose hierarchy, it works! But it’s not the “ideal” solution. However whilst we have this interoperability, it may be the best way.

Admob

Here are the offical docs for implementing an AdMob banner advert in an Android app, the examples show you how to do it programmatically or using an XML layout (remember those? :-)). Quick Start then Implement a Banner Ad.

This is where the compose ‘hack’ differs (and you can probably improve on this), so let’s start here. The docs say to load your Ad in onCreate:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        MobileAds.initialize(this) {}

        mAdView = findViewById(R.id.adView)
        val adRequest = AdRequest.Builder().build()
        mAdView.loadAd(adRequest)
    }

You could also do this with compose, after composition calling loadAd from onCreate. But let’s do it another way:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.blundell.tut.R
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView

@Composable
fun AdvertView(modifier: Modifier = Modifier) {
    val isInEditMode = LocalInspectionMode.current
    if (isInEditMode) {
        Text(
            modifier = modifier
                .fillMaxWidth()
                .background(Color.Red)
                .padding(horizontal = 2.dp, vertical = 6.dp),
            textAlign = TextAlign.Center,
            color = Color.White,
            text = "Advert Here",
        )
    } else {
        AndroidView(
            modifier = modifier.fillMaxWidth(),
            factory = { context ->
                AdView(context).apply {
                    adSize = AdSize.BANNER
                    adUnitId = context.getString(R.string.ad_id_banner)
                    loadAd(AdRequest.Builder().build())
                }
            }
        )
    }
}

@Preview(showBackground = true)
@Composable
fun AdvertPreview() {
    AdvertView()
}

Create a new composable, use the AdMob supplied AdView wrap that in a compose supplied AndroidView and wrap both of those in your own created composable AdvertView.

The compose preview does not like rendering AdView when used like this, and so we validate the AdMob AdView for use in the equivalent of isInEditMode for compose, which is called LocalInspectionMode.current. This allows our preview to render a red banner, instead of the advert in a preview.

The official documentation for AndroidView explains this:

Composes an Android layout resource in the presence of ViewBinding. The binding is obtained from the factory block, which will be called exactly once to obtain the ViewBinding to be composed, and it is also guaranteed to be invoked on the UI thread. Therefore, in addition to creating the ViewBinding, the block can also be used to perform one-off initializations and View constant properties’ setting. The update block can be run multiple times (on the UI thread as well) due to recomposition, and it is the right place to set View properties depending on state. When state changes, the block will be reexecuted to set the new properties. Note the block will also be ran once right after the factory block completes.

https://developer.android.com/reference/kotlin/androidx/compose/ui/viewinterop/package-summary#AndroidView(kotlin.Function1,androidx.compose.ui.Modifier,kotlin.Function1)

This explanation seems to suggest we could use either of the two properties: factory (which we do) or update to load our advert. They both run on the UI thread (same as running loadAd from onCreate.) As a judgement for the reader, you have think if you want the loadAd method to be called on each composition or as a one off when the view is instantiated.

And that’s it! Bear in mind, calling loadAd in this way is not recommended by anyone, but since it’s using the factory of AndroidView it feels ok 🙂 (If you used update, I bet the internal library handles us calling it multiple times anyway). This example is just to get you started with AdMob and compose.

If anyone wants a more full featured example, please reach out to me on Twitter and I can make an example project.

Enjoy!

If you like this post, perhaps you will like: Taming your gradle dependencies: Just BECAUSE!

One thought on “Using AdMob banner Ads in a Compose Layout

  1. Thanks a lot for this! This is the only example on the internet about how to show AdMob ads in Jetpack Compose.

Comments are closed.