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:
- Extend the
Application
class to initialize the Google Mobile Ads SDK. - Create a utility class that loads an ad before you need to display it.
- Load an ad.
- Listen for
ActivityLifecycleCallbacks.
- Show the ad and handle callbacks.
- Implement and register the
LifecycleObserver
interface to show an ad during foregrounding events.
Prerequisites
- Google Mobile Ads SDK 19.4.0 or higher.
- 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:
ca-app-pub-3940256099942544/9257395921
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 that extends the Application
class, and add the following
code to initialize the Google Mobile Ads SDK.
Java
/** Application class that initializes, loads and show ads when activities change states. */
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
}
}
Kotlin
/** Application class that initializes, loads and show ads when activities change states. */
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
MobileAds.initialize(this) {}
}
}
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 AppOpenAdManager
within MyApplication
class and
fill it out as follows:
Java
public class MyApplication extends Application {
...
/** Inner class that loads and shows app open ads. */
private class AppOpenAdManager {
private static final String LOG_TAG = "AppOpenAdManager";
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/9257395921";
private AppOpenAd appOpenAd = null;
private boolean isLoadingAd = false;
private boolean isShowingAd = false;
/** Constructor. */
public AppOpenAdManager() {}
/** Request an ad. */
private void loadAd(Context context) {
// We will implement this below.
}
/** Check if ad exists and can be shown. */
private boolean isAdAvailable() {
return appOpenAd != null;
}
}
}
Kotlin
private const val String LOG_TAG = "AppOpenAdManager"
private const val String AD_UNIT_ID = "ca-app-pub-3940256099942544/9257395921"
public class MyApplication extends Application {
...
/** Inner class that loads and shows app open ads. */
private inner class AppOpenAdManager {
private var appOpenAd: AppOpenAd? = null
private var isLoadingAd = false
var isShowingAd = false
/** Request an ad. */
fun loadAd(context: Context) {
// We will implement this below.
}
/** Check if ad exists and can be shown. */
private fun isAdAvailable(): Boolean {
return appOpenAd != null
}
}
}
Now that you have a utility class, you can instantiate it in your
MyApplication
class:
Java
public class MyApplication extends Application {
private AppOpenAdManager appOpenAdManager;
@Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
appOpenAdManager = new AppOpenAdManager(this);
}
}
Kotlin
class MyApplication : Application() {
private lateinit var appOpenAdManager: AppOpenAdManager
override fun onCreate() {
super.onCreate()
MobileAds.initialize(this) {}
appOpenAdManager = AppOpenAdManager()
}
}
Load an ad
The next step is to fill out the loadAd()
method.
Java
private class AppOpenAdManager {
...
/** Request an ad. */
public void loadAd(Context context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return;
}
isLoadingAd = true;
AdRequest request = new AdRequest.Builder().build();
AppOpenAd.load(
context, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
new AppOpenAdLoadCallback() {
@Override
public void onAdLoaded(AppOpenAd ad) {
// Called when an app open ad has loaded.
Log.d(LOG_TAG, "Ad was loaded.");
appOpenAd = ad;
isLoadingAd = false;
}
@Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
// Called when an app open ad has failed to load.
Log.d(LOG_TAG, loadAdError.getMessage());
isLoadingAd = false;
}
});
}
...
}
Kotlin
private inner class AppOpenAdManager {
...
/** Request an ad. */
fun loadAd(context: Context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return
}
isLoadingAd = true
val request = AdRequest.Builder().build()
AppOpenAd.load(
context, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
object : AppOpenAdLoadCallback() {
override fun onAdLoaded(ad: AppOpenAd) {
// Called when an app open ad has loaded.
Log.d(LOG_TAG, "Ad was loaded.")
appOpenAd = ad
isLoadingAd = false
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
// Called when an app open ad has failed to load.
Log.d(LOG_TAG, loadAdError.message)
isLoadingAd = false;
}
})
}
...
}
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, implement the
Application.ActivityLifecycleCallbacks
in your Application
class.
Java
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private Activity currentActivity;
...
/** ActivityLifecycleCallback methods. */
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
@Override
public void onActivityStarted(Activity activity) {
// Updating the currentActivity only when an ad is not showing.
if (!appOpenAdManager.isShowingAd) {
currentActivity = activity;
}
}
@Override
public void onActivityResumed(Activity 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) {}
}
Kotlin
class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
private var currentActivity: Activity? = null
...
/** ActivityLifecycleCallback methods. */
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {
// Updating the currentActivity only when an ad is not showing.
if (!appOpenAdManager.isShowingAd) {
currentActivity = activity
}
}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
}
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
method.
Java
public class MyApplication extends Application {
...
@Override
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(this);
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
appOpenAdManager = new AppOpenAdManager();
}
}
Kotlin
class MyApplication : Application() {
...
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(this)
MobileAds.initialize(this) {}
appOpenAdManager = AppOpenAdManager()
}
}
registerActivityLifecycleCallbacks
lets you 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
The following code demonstrates when to show and subsequently reload an ad.
Java
public class MyApplication extends Application {
...
/** Interface definition for a callback to be invoked when an app open ad is complete. */
public interface OnShowAdCompleteListener {
void onShowAdComplete();
}
private class AppOpenAdManager {
...
/** Shows the ad if one isn't already showing. */
public void showAdIfAvailable(
@NonNull final Activity activity,
@NonNull OnShowAdCompleteListener onShowAdCompleteListener){
// If the app open ad is already showing, do not show the ad again.
if (isShowingAd) {
Log.d(LOG_TAG, "The app open ad is already showing.");
return;
}
// If the app open ad is not available yet, invoke the callback then load the ad.
if (!isAdAvailable()) {
Log.d(LOG_TAG, "The app open ad is not ready yet.");
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
return;
}
appOpenAd.setFullScreenContentCallback(
new FullScreenContentCallback {
@Override
public void onAdDismissedFullScreenContent() {
// Called when fullscreen content is dismissed.
// Set the reference to null so isAdAvailable() returns false.
Log.d(LOG_TAG, "Ad dismissed fullscreen content.");
appOpenAd = null;
isShowingAd = false;
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
// Called when fullscreen content failed to show.
// Set the reference to null so isAdAvailable() returns false.
Log.d(LOG_TAG, adError.getMessage());
appOpenAd = null;
isShowingAd = false;
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
}
@Override
public void onAdShowedFullScreenContent() {
// Called when fullscreen content is shown.
Log.d(LOG_TAG, "Ad showed fullscreen content.");
}
});
isShowingAd = true;
appOpenAd.show(activity);
}
...
}
}
Kotlin
class MyApplication : Application() {
...
/** Interface definition for a callback to be invoked when an app open ad is complete. */
interface OnShowAdCompleteListener {
fun onShowAdComplete()
}
private inner class AppOpenAdManager {
...
/** Shows the ad if one isn't already showing. */
fun showAdIfAvailable(
activity: Activity,
onShowAdCompleteListener: OnShowAdCompleteListener) {
// If the app open ad is already showing, do not show the ad again.
if (isShowingAd) {
Log.d(LOG_TAG, "The app open ad is already showing.")
return
}
// If the app open ad is not available yet, invoke the callback then load the ad.
if (!isAdAvailable()) {
Log.d(LOG_TAG, "The app open ad is not ready yet.")
onShowAdCompleteListener.onShowAdComplete()
loadAd(activity)
return
}
appOpenAd?.setFullScreenContentCallback(
object : FullScreenContentCallback() {
override fun onAdDismissedFullScreenContent() {
// Called when full screen content is dismissed.
// Set the reference to null so isAdAvailable() returns false.
Log.d(LOG_TAG, "Ad dismissed fullscreen content.")
appOpenAd = null
isShowingAd = false
onShowAdCompleteListener.onShowAdComplete()
loadAd(activity)
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {
// Called when fullscreen content failed to show.
// Set the reference to null so isAdAvailable() returns false.
Log.d(LOG_TAG, adError.message)
appOpenAd = null
isShowingAd = false
onShowAdCompleteListener.onShowAdComplete()
loadAd(activity)
}
override fun onAdShowedFullScreenContent() {
// Called when fullscreen content is shown.
Log.d(LOG_TAG, "Ad showed fullscreen content.")
}
})
isShowingAd = true
appOpenAd?.show(activity)
}
...
}
}
The FullScreenContentCallback
handles 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'
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.gms:play-services-ads:22.5.0'
def lifecycle_version = "2.3.1"
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 Application
class by
implementing the LifecycleObserver
interface.
Java
public class MyApplication extends Application
implements ActivityLifecycleCallbacks, LifecycleObserver { {
...
@Override
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(this);
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
appOpenAdManager = new AppOpenAdManager();
}
/** LifecycleObserver method that shows the app open ad when the app moves to foreground. */
@OnLifecycleEvent(Event.ON_START)
protected void onMoveToForeground() {
// Show the ad (if available) when the app moves to foreground.
appOpenAdManager.showAdIfAvailable(currentActivity);
}
/** Show the ad if one isn't already showing. */
private void showAdIfAvailable(@NonNull final Activity activity) {
showAdIfAvailable(
activity,
new OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
// Empty because the user will go back to the activity that shows the ad.
}
});
}
}
Kotlin
class MyApplication : Application(),
Application.ActivityLifecycleCallbacks, LifecycleObserver {
...
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(this)
MobileAds.initialize(this) {}
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
appOpenAdManager = AppOpenAdManager()
}
/** LifecycleObserver method that shows the app open ad when the app moves to foreground. */
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
// Show the ad (if available) when the app moves to foreground.
currentActivity?.let {
appOpenAdManager.showAdIfAvailable(it)
}
}
/** Show the ad if one isn't already showing. */
fun showAdIfAvailable(activity: Activity) {
showAdIfAvailable(
activity,
object : OnShowAdCompleteListener {
override fun onShowAdComplete() {
// Empty because the user will go back to the activity that shows the ad.
}
})
}
}
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 AppOpenAdManager
that checks how long it has been since your ad reference loaded. Then, use that
method to check if the ad is still valid.
Java
private class AppOpenAdManager {
...
/** Keep track of the time an app open ad is loaded to ensure you don't show an expired ad. */
private long loadTime = 0;
/** Request an ad. */
public void loadAd(Context context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return;
}
isLoadingAd = true;
AdRequest request = new AdRequest.Builder().build();
AppOpenAd.load(
context, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
new AppOpenAdLoadCallback() {
@Override
public void onAdLoaded(AppOpenAd ad) {
// Called when an app open ad has loaded.
Log.d(LOG_TAG, "Ad was loaded.");
appOpenAd = ad;
isLoadingAd = false;
loadTime = (new Date()).getTime();
}
@Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
// Called when an app open ad has failed to load.
Log.d(LOG_TAG, loadAdError.getMessage());
isLoadingAd = false;
}
});
}
...
/** 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));
}
/** Check if ad exists and can be shown. */
public boolean isAdAvailable() {
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
}
}
Kotlin
private inner class AppOpenAdManager {
...
/** Keep track of the time an app open ad is loaded to ensure you don't show an expired ad. */
private var loadTime: Long = 0
/** Request an ad. */
fun loadAd(context: Context) {
// Do not load ad if there is an unused ad or one is already loading.
if (isLoadingAd || isAdAvailable()) {
return
}
isLoadingAd = true
val request = AdRequest.Builder().build()
AppOpenAd.load(
context, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
object : AppOpenAdLoadCallback() {
override fun onAdLoaded(ad: AppOpenAd) {
// Called when an app open ad has loaded.
Log.d(LOG_TAG, "Ad was loaded.")
appOpenAd = ad
isLoadingAd = false
loadTime = Date().time
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
// Called when an app open ad has failed to load.
Log.d(LOG_TAG, loadAdError.message)
isLoadingAd = false;
}
})
}
...
private fun wasLoadTimeLessThanNHoursAgo(numHours: Long): Boolean {
val dateDifference: Long = Date().time - loadTime
val numMilliSecondsPerHour: Long = 3600000
return dateDifference < numMilliSecondsPerHour * numHours
}
private fun isAdAvailable(): Boolean {
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.
Examples on GitHub
Next steps
Explore the following topics: