Aller au contenu principal
Version: 6.x.x

App Open Ads

Overview

App open ads are full-screen ads designed to appear during app launch moments. They are similar to interstitial ads but are specifically tailored for two key scenarios:

Cold start — When the user opens the app fresh (the app was not previously in memory). A splash or loading screen is typically shown before the ad.

Soft launch — When the user returns to the app from the background. The app is still in memory but was paused.

In both cases, the ad is displayed before the user reaches the main content. Users can dismiss the ad at any time.

Implementation Steps

At a high level, integrating app open ads involves the following:

  1. Build a manager class that preloads an ad so it's ready when needed.
  2. Display the ad when the app comes to the foreground.
  3. React to ad lifecycle and presentation callbacks.

Best Practices

App open ads are a great way to monetize your app's loading screen, but it's important to follow best practices so that your users continue to enjoy using your app:

  • Show ads only during natural waiting moments. App open ads work best when users are already expecting a brief pause, such as during app launch or when returning from the background. Avoid surprising users with ads at unexpected times.
  • Always show a splash or loading screen first. The user should never see actual app content before the ad appears. The expected flow is: splash screen → app open ad → app content.
  • Initialize the SDK before loading ads. Make sure the BlueStack SDK has fully initialized before you attempt to load an app open ad. Loading ads before initialization may result in failed requests.
  • Preload the ad early. Load the ad as soon as possible so there is no delay when it's time to show it. Avoid loading other ad formats in parallel, as this can strain device resources and reduce fill rates.
  • Respect user experience with frequency controls. Avoid showing an ad on every single app open. Consider strategies such as:
    • Showing an ad on every second or third opportunity instead of every time.
    • Requiring a minimum background duration (e.g., 30 seconds or 2 minutes) before showing an ad on soft launch.
    • Skipping soft launch ads for a period after showing a cold start ad.
  • Be mindful of new users. Hold off on showing app open ads until users have opened and used your app a few times. This helps build a positive first impression before introducing ads.
  • Handle ad expiration. Preloaded ads expire after a certain period (typically 4 hours). Always verify that the ad is still valid before attempting to show it, and reload if it has expired.
  • Coordinate your loading screen with the ad. If you have a loading screen running behind the app open ad and it finishes before the user dismisses the ad, dismiss the loading screen in the onAdDismissed callback to ensure a smooth transition to your app content.

Create an App Open Ad

Implement a Manager Class

App open ads should appear immediately when the user opens or returns to your app, so it's important to have the ad loaded and ready before it's needed. The best approach is to create a manager class that takes care of loading ads ahead of time, checking whether a loaded ad is still valid, and displaying it at the right moment.

Create a class called AppOpenAdManager:

import android.app.Activity;
import com.azerion.bluestack.appopen.AppOpenAd;
import com.azerion.bluestack.appopen.AppOpenAdListener;

public class AppOpenAdManager implements AppOpenAdListener {

private static final String TAG = "AppOpenAdManager";

private ActivityContextProvider activityContextProvider;
private AppOpenAd appOpenAd;
private OnShowAdCompleteListener onShowAdCompleteListener;

public boolean isShowingAd = false;

public AppOpenAdManager(ActivityContextProvider activityContextProvider) {
this.activityContextProvider = activityContextProvider;
}

public interface OnShowAdCompleteListener {
void onShowAdComplete();
}

public interface ActivityContextProvider {
Activity getActivity();
}

private void initializeAppOpenAd() {
if (appOpenAd == null) {
appOpenAd = new AppOpenAd("APP_OPEN_PLACEMENT_ID");
appOpenAd.setAppOpenAdListener(this);
}
}
}

Standalone Creation

To create an app open ad directly, instantiate an AppOpenAd with a placement ID.

import com.azerion.bluestack.appopen.AppOpenAd;

public class MainActivity extends AppCompatActivity {

private AppOpenAd appOpenAd;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

appOpenAd = new AppOpenAd("APP_OPEN_PLACEMENT_ID");
}
}

Load an App Open Ad

With AppOpenAdManager

The recommended way to load an app open ad is through the AppOpenAdManager class. Add the loadAd() method to the manager class:

public void loadAd(Activity activity) {
initializeAppOpenAd();
appOpenAd.load(activity);
}

Standalone Loading

App open ads can be loaded by calling the load(activity) method:

appOpenAd.load(activity);
info

Ad load call will preload an ad before you show it so that ads can be shown with zero latency when needed. This preloaded ad will expire after a certain period. If you try to show an expired ad, you will get AdError.AD_EXPIRED error in the onAdFailedToDisplay callback. Once the ad expires, you can call load again using the existing instance to preload a new ad.

Show an Ad

With AppOpenAdManager

Before showing the ad, the manager checks whether an ad is already on screen. Add these methods to the AppOpenAdManager class:

public void showAdIfAvailable(Activity activity) {
showAdIfAvailable(activity, new OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
// Empty because the user will go back to the activity that shows the ad.
}
});
}

public void showAdIfAvailable(Activity activity, OnShowAdCompleteListener onShowAdCompleteListener) {
initializeAppOpenAd();

if (isShowingAd) {
Log.d(TAG, "The app open ad is already showing.");
return;
}

if (appOpenAd == null || !appOpenAd.isReady()) {
onShowAdCompleteListener.onShowAdComplete();
loadAd(activity);
return;
}

this.onShowAdCompleteListener = onShowAdCompleteListener;
isShowingAd = true;
appOpenAd.show(activity);
}

Standalone Showing

To show an app open ad directly, check isReady() on the AppOpenAd instance and call show(activity).

if (appOpenAd != null && appOpenAd.isReady()) {
appOpenAd.show(activity);
}

Show the Ad During App Foregrounding

To display the ad whenever the user returns to your app, implement a lifecycle observer in your Application class. Create a custom Application class that integrates with Android's lifecycle callbacks:

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.azerion.bluestack.MobileAds;

public class MyApplication extends Application
implements Application.ActivityLifecycleCallbacks,
DefaultLifecycleObserver,
AppOpenAdManager.ActivityContextProvider {

private AppOpenAdManager appOpenAdManager;
private Activity currentActivity;

@Override
public void onCreate() {
super.onCreate();
appOpenAdManager = new AppOpenAdManager(this);
registerActivityLifecycleCallbacks(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}

@Override
public void onActivityStarted(Activity activity) {
if (!appOpenAdManager.isShowingAd) {
currentActivity = activity;
}
}

@Override
public void onStart(LifecycleOwner owner) {
if (MobileAds.isInitialized() && currentActivity != null) {
// Don't show app open ad on launcher/splash activities
// as they manage their own app open ad flow
boolean shouldShowAd = !(currentActivity instanceof CustomLauncherActivity) &&
!(currentActivity instanceof SplashScreenActivity);

if (shouldShowAd) {
appOpenAdManager.showAdIfAvailable(currentActivity);
}
}
}

public void loadAd(Activity activity) {
appOpenAdManager.loadAd(activity);
}

public void showAdIfAvailable(Activity activity,
AppOpenAdManager.OnShowAdCompleteListener listener) {
appOpenAdManager.showAdIfAvailable(activity, listener);
}

@Override
public Activity getActivity() {
return currentActivity;
}

// Other ActivityLifecycleCallbacks methods...
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

@Override
public void onActivityResumed(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityStopped(Activity activity) {}

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

@Override
public void onActivityDestroyed(Activity activity) {}
}

Don't forget to register your custom Application class in the AndroidManifest.xml:

<manifest>
<application
android:name=".MyApplication"
... >
...
</application>
</manifest>

Destroying an App Open Ad

When you have finished displaying an app open ad, call destroy() to free resources.

@Override
protected void onDestroy() {
if (appOpenAd != null) {
appOpenAd.destroy();
appOpenAd = null;
}
super.onDestroy();
}

Ad events

You can register an AppOpenAdListener on your AppOpenAd instance to receive notifications about ad lifecycle events. The AppOpenAdListener extends FullScreenAdListener and provides the following callbacks:

Load Events

  • onAdLoaded() — Called when an ad is successfully loaded and ready to display
  • onAdFailedToLoad(Exception exception) — Called when an ad fails to load, with an exception describing the cause

Display Events (from FullScreenAdListener)

  • onAdDisplayed() — Called when the ad successfully displays full-screen content
  • onAdFailedToDisplay(Exception exception) — Called when the ad fails to display, with an exception describing the cause
  • onAdClicked() — Called when a click is recorded for the ad
  • onAdDismissed() — Called when the ad is dismissed and the user returns to the app

Register for app open events

AppOpenAd delivers lifecycle and presentation events through the AppOpenAdListener interface. Use the setAppOpenAdListener() method to register your listener:

appOpenAd.setAppOpenAdListener(this);

App Open ad lifecycle and display events

Implement the AppOpenAdListener interface in your AppOpenAdManager class to handle all ad events:

@Override
public void onAdLoaded() {
Log.i(TAG, "App open ad loaded");
}

@Override
public void onAdFailedToLoad(Exception exception) {
Log.e(TAG, "App open ad failed to load", exception);
}

@Override
public void onAdDisplayed() {
Log.i(TAG, "App open ad displayed");
}

@Override
public void onAdFailedToDisplay(Exception exception) {
Log.e(TAG, "App open ad failed to display", exception);
isShowingAd = false;
if (onShowAdCompleteListener != null) {
onShowAdCompleteListener.onShowAdComplete();
}
Activity activity = activityContextProvider.getActivity();
if (activity != null) {
loadAd(activity);
}
}

@Override
public void onAdClicked() {
Log.i(TAG, "App open ad clicked");
}

@Override
public void onAdDismissed() {
Log.i(TAG, "App open ad dismissed");
isShowingAd = false;
if (onShowAdCompleteListener != null) {
onShowAdCompleteListener.onShowAdComplete();
}
Activity activity = activityContextProvider.getActivity();
if (activity != null) {
loadAd(activity);
}
}

Handling Cold Starts with Loading Screens

The examples above focus on showing app open ads when users return to an app that is already in memory (soft launch). Cold starts — when the app is launched fresh and was not previously in memory — require additional consideration.

During a cold start, there is no previously loaded ad ready to show immediately. The delay between requesting an ad and receiving one can create a situation where the user briefly sees app content before an ad unexpectedly appears. This is a poor user experience and should be avoided.

The recommended approach is to use a loading or splash screen during the app's startup sequence and only show the app open ad while that screen is still visible. Here's an example implementation:

import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import androidx.appcompat.app.AppCompatActivity;
import com.azerion.bluestack.MobileAds;
import com.azerion.bluestack.initialization.InitializationListener;
import com.azerion.bluestack.initialization.SDKInitializationStatus;
import java.util.concurrent.TimeUnit;

public class CustomLauncherActivity extends AppCompatActivity {

private static final String TAG = "CustomLauncherActivity";
// Simulate app loading time (5 seconds)
private static final long COUNTER_TIME_MILLISECONDS = 5000L;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);

initializeCMP();
}

private void initializeCMP() {
// Initialize your Consent Management Platform here
// Once consent is obtained, initialize BlueStack SDK
initializeBlueStackSDK();
}

private void initializeBlueStackSDK() {
MobileAds.setDebugModeEnabled(true);
MobileAds.initialize(this, "YOUR_APP_ID", new InitializationListener() {
@Override
public void onInitialized(SDKInitializationStatus status) {
// Load the app open ad after initialization
((MyApplication) getApplication()).loadAd(CustomLauncherActivity.this);
}
});
createTimer();
}

private void navigateToMainActivity() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}

private void createTimer() {
new CountDownTimer(COUNTER_TIME_MILLISECONDS, 1000) {
@Override
public void onTick(long millisUntilFinished) {
Log.d(TAG, "App is done loading in: " +
(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) + 1));
}

@Override
public void onFinish() {
// Show the app open ad when the splash screen is ready to dismiss
((MyApplication) getApplication()).showAdIfAvailable(
CustomLauncherActivity.this,
new AppOpenAdManager.OnShowAdCompleteListener() {
@Override
public void onShowAdComplete() {
navigateToMainActivity();
}
}
);
}
}.start();
}
}

Follow these guidelines:

  • Keep the loading screen visible until the ad is ready. Do not dismiss it or transition to app content before the ad has been shown.
  • Show the ad from the loading screen only. If your app finishes loading and has already moved the user to the main content, do not show the ad — the moment has passed.
  • Dismiss the loading screen in onShowAdComplete. Wait for the callback before transitioning to app content. This ensures a smooth flow from splash screen → ad → app content with no flicker or content flash in between.

Consider Ad Expiration

A preloaded ad can become stale if too much time passes between loading and displaying. The BlueStack SDK handles ad expiration internally. If you attempt to show an expired ad, you will receive an AdError.AD_EXPIRED error in the onAdFailedToDisplay() callback.

When this occurs, the best practice is to:

  1. Clean up the expired ad reference
  2. Immediately load a fresh ad for the next opportunity

The AppOpenAdManager implementation above automatically handles this by reloading an ad in the onAdFailedToDisplay() callback.

Control Ad Frequency

To maintain a positive user experience, avoid showing an app open ad on every single foreground event. Consider implementing frequency controls such as:

  • Skip opportunities — Show an ad on every second or third app open instead of every time.
  • Minimum background duration — Only show an ad if the user was away from the app for a certain amount of time (e.g., 30 seconds, 2 minutes, or 15 minutes).
  • Cooldown after cold start — If you showed an ad during a cold start, skip soft launch ads for a set period afterward.
  • Frequency caps — Limit the total number of app open ads shown per session or per day. Where possible, tailor caps based on user cohorts or engagement levels.