Skip to main content

Setting up an App Open Ad - Compose

App Open Ads have two possible flows designed to be used together: Cold start and Resuming from background.

Cold start (Splash screen)

The first approach allows you monetise the loading screen of your app. When the user opens the app, the splash screen is displayed. While your app is loading, our SDK will load an Ad. If the ad is loaded in time you can control whether the ad is displayed before the home screen of your app is displayed. The example below is taken from our demo app:
class SplashViewModel(
    private val adManager: CIAppOpenAdManager
) : ViewModel() {
...

    init {
        viewModelScope.launch {
            adManager.state.first { it == AppOpenState.DISMISSED }
            _state.update { SplashState.NavigateToHome }
        }

        viewModelScope.launch {
            val adLoaded = withTimeoutOrNull(AD_LOAD_TIMEOUT_MS) {
                adManager.state.first { event ->
                    event == AppOpenState.LOADED || event == AppOpenState.LOAD_FAILED
                } == AppOpenState.LOADED
            }
            _state.update { 
                if (adLoaded == true) {
                    SplashState.AdReady
                } else {
                    SplashState.NavigateToHome
                }
            }
        }
    }

    fun load(context: Context) {
            val configuration = CIMobileAdsConfiguration.Builder(publisherId = "<PUBLISHER-ID>")
                .enableAppOpen("<PLACEMENT-ID>") // Enable App Open ads
                .setDebugFeature(true)
                .build()

            backgroundScope.launch {
                // Initialise the ContentIgniteMobile SDK on a background thread.
                val status = CIMobileAds.initialise(
                    context = context,
                    configuration = configuration
                )
                when (status) {
                    CIInitialisationStatus.Succeeded -> {
                        println("CIMobileAds Initialised Successfully")
                        // Load the app open ad
                        loadAd(context)
                    }
                    CIInitialisationStatus.Failed -> {
                        println("CIMobileAds Initialisation Failed")
                        _state.update { SplashState.NavigateToHome }
                    }
                }
            }
        }

    private fun loadAd(context: Context) {
        adManager.loadAd(context)
    }

    fun showAd(activity: Activity) {
        adManager.show(activity = activity)
    }
...
}
You will notice that in this example the SDK initialisation is now performed on Splash Screen and to enable App Open Ads you must use enableAppOpen(placementID: String) in the SDK configuration builder. Passing in the placement ID which will be supplied to you by Content Ignite. From the UI we can control when the ad is shown by responding to the state updates:
@Composable
fun SplashScreen(
    viewModel: SplashViewModel,
    onNavigateToHome: () -> Unit
) {
    val activity = LocalActivity.current
    val context = LocalContext.current
    val state by viewModel.state.collectAsStateWithLifecycle()

    // Trigger ad show when ad is ready; navigate when done
    LaunchedEffect(state) {
        viewModel.load(context)
    }

    when (state) {
        is SplashState.AdReady -> {
            activity?.let { viewModel.showAd(activity) }
        }
        is SplashState.NavigateToHome -> onNavigateToHome()
        else -> Unit
    }
...

Resuming from background

For this approach we need to listen to application lifecycle callbacks. The recommended approach is to create a class which inherits Application. Then implement both the DefaultLifecycleObserver and Application.ActivityLifecycleCallbacks interfaces.
class App: Application(), Application.ActivityLifecycleCallbacks, DefaultLifecycleObserver { ... }
Inside the App class implement onCreate() and register the Activity Lifecycle Callbacks:
private lateinit var adManager: CIAppOpenAdManager

override fun onCreate() {
    super<Application>.onCreate()

    adManager = CIAppOpenAdManager

    ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    registerActivityLifecycleCallbacks(this)
}
To keep track of the current Activity, we use the ActivityLifecycleCallbacks:
private var currentActivity: Activity? = null


override fun onActivityStarted(activity: Activity) {
    if (!CIAppOpenAdManager.isShowingAd()) {
        currentActivity = activity
    }
}

override fun onActivityResumed(activity: Activity) { currentActivity = activity }

override fun onActivityPaused(activity: Activity) { currentActivity = null }
Finally we implement onStart() which gets called when the app resumes from the background, and we use the CIAppOpenAdManager to show the ad if one is available and otherwise load the ad for the next opportunity.
override fun onStart(owner: LifecycleOwner) {
    super.onStart(owner)
    currentActivity?.let {
        if (adManager.isAdAvailable()) {
            adManager.show(it)
        } else {
            adManager.loadAd(this@App)
        }
    }
}
Full example code here.