App Open Ads

This guide is intended for publishers integrating app open ads using the Google Mobile Ads Android SDK.

App open ads are a special ad format intended for publishers wishing to monetize their app load screens. App open ads can be closed at any time, and are designed to be shown when your users bring your app to the foreground.

App open ads automatically show a small branding area so users know they're in your app. Here is an example of what an app open ad looks like:

At a high level these are the important steps:

  1. Extend the Application class to initialize the GMA SDK.
  2. Create a utility class that loads an ad before you need to display it.
  3. Load an ad.
  4. Listen for ActivityLifecycleCallbacks.
  5. Show the ad and handle callbacks.
  6. Implement and register the LifecycleObserver interface to show an ad during foregrounding events.

Prerequisites

Follow the setup instructions in the Get Started guide.

Always test with test ads

When building and testing your apps, make sure you use test ads rather than live, production ads. Failure to do so can lead to suspension of your account.

The easiest way to load test ads is to use our dedicated test ad unit ID for app open ads:

/6499/example/app_open_new

It's been specially configured to return test ads for every request, and you're free to use it in your own apps while coding, testing, and debugging. Just make sure you replace it with your own ad unit ID before publishing your app.

For more information about how the Mobile Ads SDK's test ads work, see Test Ads.

Extend the Application class

Create a new class called MyApplication and add the following code:

package com.google.android.gms.example.appopendemo;

import android.app.Application;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;

/** The Application class that manages AppOpenManager. */
public class MyApplication extends Application {

  @Override
  public void onCreate() {
    super.onCreate();
    MobileAds.initialize(
        this,
        new OnInitializationCompleteListener() {
          @Override
          public void onInitializationComplete(InitializationStatus initializationStatus) {}
        });
  }
}

This will initialize the SDK and provide the skeleton where you'll later register for app foregrounding events.

Next, add the following code to your AndroidManifest.xml:

<application
    android:name="com.google.android.gms.example.appopendemo.MyApplication" ...>
...
</application>

Be sure to reference your actual package name.

Implement your utility class

Your ad should show quickly, so it's best to load your ad before you need to display it. That way, you'll have an ad ready to go as soon as your user enters into your app. Implement a utility class to make ad requests ahead of when you need to show the ad.

Create a new class called AppOpenManager and fill it out as follows:

import static androidx.lifecycle.Lifecycle.Event.ON_START;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.appopen.AppOpenAd;
import java.util.Date;

/** Prefetches App Open Ads. */
public class AppOpenManager {
  private static final String LOG_TAG = "AppOpenManager";
  private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/3419835294";
  private AppOpenAd appOpenAd = null;

  private AppOpenAd.AppOpenAdLoadCallback loadCallback;

  private final MyApplication myApplication;

  /** Constructor */
  public AppOpenManager(MyApplication myApplication) {
    this.myApplication = myApplication;
  }

  /** Request an ad */
  public void fetchAd() {
    // We will implement this below.
  }

  /** Creates and returns ad request. */
  private AdRequest getAdRequest() {
    return new AdRequest.Builder().build();
  }

  /** Utility method that checks if ad exists and can be shown. */
  public boolean isAdAvailable() {
    return appOpenAd != null;
  }
}

This class shell manages an instance variable to keep track of a loaded ad, the ad unit ID, and the AppOpenAdLoadCallback.

Now that you have a utility class, you can instantiate it in your MyApplication class:

/** The Application class that manages AppOpenManager. */
public class MyApplication extends Application {

  private static AppOpenManager appOpenManager;

  @Override
  public void onCreate() {
    super.onCreate();
    MobileAds.initialize(
        this,
        new OnInitializationCompleteListener() {
          @Override
          public void onInitializationComplete(InitializationStatus initializationStatus) {}
        });

    appOpenManager = new AppOpenManager(this);

  }
}

Load an ad

The next step is to fill out the fetchAd() method. Add the following to your AppOpenManager class:

/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager {
  ...
  /** Request an ad */
  public void fetchAd() {
    // Have unused ad, no need to fetch another.
    if (isAdAvailable()) {
      return;
    }

    loadCallback =
        new AppOpenAd.AppOpenAdLoadCallback() {
          /**
           * Called when an app open ad has loaded.
           *
           * @param ad the loaded app open ad.
           */
          @Override
          public void onAppOpenAdLoaded(AppOpenAd ad) {
            AppOpenManager.this.appOpenAd = ad;
          }

          /**
           * Called when an app open ad has failed to load.
           *
           * @param loadAdError the error.
           */
          @Override
          public void onAppOpenAdFailedToLoad(LoadAdError loadAdError) {
            // Handle the error.
          }

        };
    AdRequest request = getAdRequest();
    AppOpenAd.load(
        myApplication, AD_UNIT_ID, request,
        AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback);
  }
  ...
}

The AppOpenAdLoadCallback has methods that get called when the AppOpenAd finishes loading.

Keep track of current activity

In order to show the ad, you'll need an Activity context. To keep track of the most current Activity being used by your user, make your AppOpenManager class implement the Application.ActivityLifecycleCallbacks interface:

...
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements Application.ActivityLifecycleCallbacks {

  private Activity currentActivity;

  ...

  /** ActivityLifecycleCallback methods */
  @Override
  public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

  @Override
  public void onActivityStarted(Activity activity) {
    currentActivity = activity;
  }

  @Override
  public void onActivityResumed(Activity activity) {
    currentActivity = activity;
  }

  @Override
  public void onActivityStopped(Activity activity) {}

  @Override
  public void onActivityPaused(Activity activity) {}

  @Override
  public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {}

  @Override
  public void onActivityDestroyed(Activity activity) {
    currentActivity = null;
  }
}

By keeping track of the current activity, you have a context to use to show the ad. You now need to register this interface using the registerActivityLifecycleCallbacks Application method in your AppOpenManager constructor.

/** Constructor */
public AppOpenManager(MyApplication myApplication) {
  this.myApplication = myApplication;
  this.myApplication.registerActivityLifecycleCallbacks(this);
}

registerActivityLifecycleCallbacks allows you to listen for all Activity events. By listening for when activities are started and destroyed, you can keep track of a reference to the current Activity, which you then will use in presenting your app open ad.

Show the ad and handle fullscreen callback events

Add the following method to your AppOpenManager class:

/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements Application.ActivityLifecycleCallbacks {
  ...
  private static boolean isShowingAd = false;

  /** Shows the ad if one isn't already showing. */
  public void showAdIfAvailable() {
    // Only show ad if there is not already an app open ad currently showing
    // and an ad is available.
    if (!isShowingAd && isAdAvailable()) {
      Log.d(LOG_TAG, "Will show ad.");

      FullScreenContentCallback fullScreenContentCallback =
          new FullScreenContentCallback() {
            @Override
            public void onAdDismissedFullScreenContent() {
              // Set the reference to null so isAdAvailable() returns false.
              AppOpenManager.this.appOpenAd = null;
              isShowingAd = false;
              fetchAd();
            }

            @Override
            public void onAdFailedToShowFullScreenContent(AdError adError) {}

            @Override
            public void onAdShowedFullScreenContent() {
              isShowingAd = true;
            }
          };

      appOpenAd.show(currentActivity, fullScreenContentCallback);

    } else {
      Log.d(LOG_TAG, "Can not show ad.");
      fetchAd();
    }
  }
  ...
}

This method shows the ad, passing in a FullScreenContentCallback anonymous class to handle events such as when the ad is presented, fails to present, or when it is dismissed. If a user returns to your app after having left it by clicking on an app open ad, it makes sure they're not presented with another app open ad.

Listen for app foregrounding events

Add the libraries to your gradle file

In order to be notified of app foregrounding events, you need to register a LifecycleObserver. First, edit your application-level build.gradle file to include the LifecycleObserver libraries:

apply plugin: 'com.android.application'

android {
   compileSdkVersion 28
   buildToolsVersion "29.0.0"
   defaultConfig {
       applicationId "com.google.android.gms.example.appopendemo"
       minSdkVersion 18
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"
       testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
   }
   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }
}

dependencies {
   implementation 'androidx.appcompat:appcompat:1.0.2'
   implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

   implementation 'com.google.android.gms:play-services-ads:19.4.0'

   def lifecycle_version = "2.0.0"
   implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
   implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
   annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
}

Implement the LifecycleObserver interface

You can listen for foregrounding events in your AppOpenManager class by implementing the LifecycleObserver interface. Edit your class by adding the following:

package com.google.android.gms.example.appopendemo;

import static androidx.lifecycle.Lifecycle.Event.ON_START;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.appopen.AppOpenAd;
import java.util.Date;

/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements LifecycleObserver, Application.ActivityLifecycleCallbacks {
  ...
  /** Constructor */
  public AppOpenManager(MyApplication myApplication) {
    this.myApplication = myApplication;
    this.myApplication.registerActivityLifecycleCallbacks(this);
    ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
  }

  /** LifecycleObserver methods */
  @OnLifecycleEvent(ON_START)
  public void onStart() {
    showAdIfAvailable();
    Log.d(LOG_TAG, "onStart");
  }
  ...
}

By registering your LifecycleObserver, your app will be alerted to app launch and foregrounding events and be able to show the ad at the appropriate times.

Consider ad expiration

To ensure you don't show an expired ad, add a method to the AppOpenManager that checks how long it has been since your ad reference loaded. Then, use that method to check if the ad is still valid. Update your AppOpenManager method like so:

/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements LifecycleObserver, Application.ActivityLifecycleCallbacks {
  ...
  private long loadTime = 0;

  /** Request an ad */
  public void fetchAd() {
    // Have unused ad, no need to fetch another.
    if (isAdAvailable()) {
      return;
    }

    loadCallback =
        new AppOpenAd.AppOpenAdLoadCallback() {
          /**
           * Called when an app open ad has loaded.
           *
           * @param ad the loaded app open ad.
           */
          @Override
          public void onAppOpenAdLoaded(AppOpenAd ad) {
            AppOpenManager.this.appOpenAd = ad;
            AppOpenManager.this.loadTime = (new Date()).getTime();
          }

          /**
           * Called when an app open ad has failed to load.
           *
           * @param loadAdError the error.
           */
          @Override
          public void onAppOpenAdFailedToLoad(LoadAdError loadAdError) {
            // Handle the error.
          }

        };
    AdRequest request = getAdRequest();
    AppOpenAd.load(
        myApplication, AD_UNIT_ID, request, AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback);
  }
  ...

  /** Utility method to check if ad was loaded more than n hours ago. */
  private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
    long dateDifference = (new Date()).getTime() - this.loadTime;
    long numMilliSecondsPerHour = 3600000;
    return (dateDifference < (numMilliSecondsPerHour * numHours));
  }

  /** Utility method that checks if ad exists and can be shown. */
  public boolean isAdAvailable() {
    return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
  }
}

Cold starts and loading screens

The documentation thus far assumes that you only show app open ads when users foreground your app when it is suspended in memory. "Cold starts" occur when your app is launched but was not previously suspended in memory.

An example of a cold start is when a user opens your app for the first time. With cold starts, you won't have a previously loaded app open ad that's ready to be shown right away. The delay between when you request an ad and receive an ad back can create a situation where users are able to briefly use your app before being surprised by an out of context ad. This should be avoided because it is a bad user experience.

The preferred way to use app open ads on cold starts is to use a loading screen to load your game or app assets, and to only show the ad from the loading screen. If your app has completed loading and has sent the user to the main content of your app, do not show the ad.

Best practices

App open ads help you monetize your app's loading screen, when the app first launches and during app switches, but it's important to keep best practices in mind so that your users enjoy using your app. It's best to:

  • Show your first app open ad after your users have used your app a few times.
  • Show app open ads during times when your users would otherwise be waiting for your app to load.
  • If you have a loading screen under the app open ad, and your loading screen completes loading before the ad is dismissed, you may want to dismiss your loading screen in the onAdDismissedFullScreenContent() method.