Integrating AdMob with Jetpack Compose

AdMob is Google’s advertising platform that allows developers to monetize their apps by displaying ads. Integrating AdMob into a Jetpack Compose application involves setting up AdMob in your project, handling lifecycle events correctly, and displaying the ads within your Compose UI. This blog post will guide you through the process step-by-step, complete with code examples.

What is AdMob?

AdMob is a mobile advertising platform that enables app developers to earn revenue by displaying targeted ads. It supports various ad formats, including banner ads, interstitial ads, rewarded ads, and native ads. Integrating AdMob effectively can significantly boost your app’s revenue stream.

Why Integrate AdMob with Jetpack Compose?

  • Monetization: Earn revenue from your app users.
  • Seamless Integration: Display ads smoothly within your Compose UI.
  • Targeted Advertising: Serve relevant ads to users, improving engagement and revenue.

Prerequisites

  • Android Studio installed
  • Basic knowledge of Jetpack Compose
  • An AdMob account and Ad Unit IDs

Step 1: Set up AdMob in Your Android Project

First, you need to set up the AdMob SDK in your Android project.

Add Google Maven Repository

Ensure you have Google’s Maven repository configured in your settings.gradle file:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter() // Add this if you're still using jCenter
    }
}

Add AdMob SDK Dependency

Add the AdMob SDK dependency to your build.gradle file (Module: app):

dependencies {
    implementation("com.google.android.gms:play-services-ads:23.0.0")
}

Make sure to sync your project after adding the dependency.

Initialize the Mobile Ads SDK

Initialize the Mobile Ads SDK in your Application class or MainActivity.

Create a custom Application class:


import android.app.Application
import com.google.android.gms.ads.MobileAds

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        MobileAds.initialize(this) { }
    }
}

Update your AndroidManifest.xml file to use your custom Application class:


<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.MyApp">
    <!-- Other activity declarations -->
</application>

Step 2: Displaying Banner Ads in Jetpack Compose

Banner ads are rectangular ads that appear at the top, bottom, or in the middle of the screen. To display a banner ad in Jetpack Compose, you need to use an AndroidView.

Create a Composable Function for Banner Ads


import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView

@Composable
fun BannerAd(adUnitId: String, modifier: Modifier = Modifier) {
    AndroidView(
        factory = { context ->
            AdView(context).apply {
                setAdSize(AdSize.BANNER)
                adUnitId = adUnitId
                loadAd(AdRequest.Builder().build())
            }
        },
        modifier = modifier
    )
}

Use the Composable in Your UI

In your composable UI, use the BannerAd composable function:


import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MainScreen() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // Your app content here
        
        BannerAd(
            adUnitId = "YOUR_BANNER_AD_UNIT_ID", // Replace with your actual ad unit ID
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MainScreen()
}

Replace "YOUR_BANNER_AD_UNIT_ID" with your actual AdMob banner ad unit ID.

Step 3: Displaying Interstitial Ads in Jetpack Compose

Interstitial ads are full-screen ads that cover the entire app interface. These are typically displayed at natural transition points in the app flow.

Load the Interstitial Ad

First, load the interstitial ad. You can do this when the app starts or when the user navigates to a specific screen.


import android.content.Context
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.Composable
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.InterstitialAd

@Composable
fun rememberInterstitialAd(adUnitId: String, context: Context): InterstitialAd {
    val interstitialAd = remember {
        InterstitialAd(context).apply {
            adUnitId = adUnitId
            loadAd(AdRequest.Builder().build())
        }
    }
    return interstitialAd
}

Show the Interstitial Ad

Display the interstitial ad when needed (e.g., after completing a level or task).


import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

@Composable
fun ShowInterstitialAd(adUnitId: String, context: Context) {
    val interstitialAd = rememberInterstitialAd(adUnitId, context)
    val adDisplayed = remember { mutableStateOf(false) }

    Button(onClick = {
        if (interstitialAd.isLoaded) {
            interstitialAd.show()
            adDisplayed.value = true
        } else {
            // Handle the case where the ad is not loaded
        }
    }) {
        Text("Show Interstitial Ad")
    }
}

Integrating the Ad into your UI


import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MainScreen() {
    val context = LocalContext.current

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // Your app content here
        
        ShowInterstitialAd(adUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID", context = context)
        
        BannerAd(
            adUnitId = "YOUR_BANNER_AD_UNIT_ID", // Replace with your actual ad unit ID
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MainScreen()
}

Replace "YOUR_INTERSTITIAL_AD_UNIT_ID" with your actual AdMob interstitial ad unit ID.

Step 4: Handling Lifecycle Events

To avoid memory leaks and ensure proper ad behavior, you need to handle the lifecycle events of the AdView.

Create a LifecycleObserver

Implement a LifecycleObserver to manage the AdView‘s lifecycle.


import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.google.android.gms.ads.AdView

class AdLifecycleObserver(private val adView: AdView) : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        super.onResume(owner)
        adView.resume()
    }

    override fun onPause(owner: LifecycleOwner) {
        super.onPause(owner)
        adView.pause()
    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        adView.destroy()
    }
}

Attach the LifecycleObserver to the AdView

Attach the LifecycleObserver to the AdView using remember and LocalLifecycleOwner.


import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView

@Composable
fun BannerAd(adUnitId: String, modifier: Modifier = Modifier) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val adView = remember {
        AdView(context).apply {
            setAdSize(AdSize.BANNER)
            this.adUnitId = adUnitId
            loadAd(AdRequest.Builder().build())
        }
    }

    DisposableEffect(lifecycleOwner, adView) {
        val observer = AdLifecycleObserver(adView)
        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }

    AndroidView(
        factory = {
            adView
        },
        modifier = modifier
    )
}

Best Practices for AdMob Integration

  • User Experience: Don’t disrupt user experience with excessive or intrusive ads.
  • Ad Placement: Place ads strategically to maximize visibility and engagement.
  • Testing: Test your ad integration thoroughly to ensure proper functionality and ad delivery.
  • Policy Compliance: Adhere to AdMob’s policies to avoid account suspension.

Conclusion

Integrating AdMob with Jetpack Compose allows you to monetize your Android apps effectively. By following the steps outlined in this blog post, you can set up AdMob, display banner and interstitial ads, and handle lifecycle events correctly. Remember to prioritize user experience and adhere to AdMob’s policies for long-term success.