アプリ起動時広告

このガイドは、Google Mobile Ads Android SDK を使用してアプリ起動時広告を統合するパブリッシャー様を対象としています。

アプリ起動時広告は、アプリの読み込み画面を収益化したいパブリッシャー様向けの特別な広告フォーマットです。アプリ起動時広告は、ユーザーがアプリをフォアグラウンドに戻したときに表示されるよう、いつでも閉じることができます。

アプリ起動時広告には、小さなブランド領域が自動的に表示されるため、ユーザーは自分のアプリを使用していることを認識できます。アプリ起動時広告の例を以下に示します。

大まかに言うと、重要なステップは次のとおりです。

  1. Application クラスを拡張して、Google Mobile Ads SDK を初期化します。
  2. 表示が必要になる前に広告を読み込むユーティリティ クラスを作成します。
  3. 広告を読み込みます。
  4. ActivityLifecycleCallbacks.を聞き取る
  5. 広告を表示してコールバックを処理します。
  6. フォアグラウンド イベント中に広告を表示する LifecycleObserver インターフェースを実装して登録します。

前提条件

  • Google Mobile Ads SDK 19.4.0 以降。
  • スタートガイドの設定手順に沿って操作します。

必ずテスト広告でテストする

アプリの作成とテストでは、実際の配信中の広告ではなくテスト広告を使用するようにしてください。実際の広告を使用すると、アカウントが停止される可能性があります。

テスト広告を読み込む最も簡単な方法は、アプリ起動時広告向けのテスト専用広告ユニット ID を使用することです。

/6499/example/app-open

すべてのリクエストに対してテスト広告を返すように特別に構成されており、独自のアプリでコーディング、テスト、デバッグを行うときに自由に使用できます。ただし、アプリを公開する前に、必ずご自身の広告ユニット ID に置き換えてください。

Mobile Ads SDK のテスト広告の仕組みについて詳しくは、テスト広告をご覧ください。

Application クラスを拡張する

Application クラスを拡張する新しいクラスを作成し、次のコードを追加して 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();
    new Thread(
            () -> {
              // Initialize the Google Mobile Ads SDK on a background thread.
              MobileAds.initialize(this, initializationStatus -> {});
            })
        .start();
  }
}

Kotlin

/** Application class that initializes, loads and show ads when activities change states. */
class MyApplication : Application() {

  override fun onCreate() {
    super.onCreate()
    val backgroundScope = CoroutineScope(Dispatchers.IO)
    backgroundScope.launch {
      // Initialize the Google Mobile Ads SDK on a background thread.
      MobileAds.initialize(this@MyApplication) {}
    }
  }
}

これにより SDK が初期化され、後でアプリのフォアグラウンド イベントに登録するスケルトンが提供されます。

次に、以下のコードを AndroidManifest.xml に追加します。

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

実際のパッケージ名を必ず参照してください。

ユーティリティ クラスを実装する

広告はすぐに表示される必要があるため、表示前に読み込むことをおすすめします。そうすることで、ユーザーがアプリに入ったらすぐに広告を掲載できるようになります。ユーティリティ クラスを実装して、広告を表示するタイミングに先立って広告リクエストを行います。

MyApplication クラス内に AppOpenAdManager という新しいクラスを作成し、次のように入力します。

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
    }
  }
}

これでユーティリティ クラスを作成したので、それを MyApplication クラスでインスタンス化できます。

Java

public class MyApplication extends Application {

  private AppOpenAdManager appOpenAdManager;

  @Override
  public void onCreate() {
    super.onCreate();
    new Thread(
            () -> {
              // Initialize the Google Mobile Ads SDK on a background thread.
              MobileAds.initialize(this, initializationStatus -> {});
            })
        .start();
    appOpenAdManager = new AppOpenAdManager(this);
  }
}

Kotlin

class MyApplication : Application() {

  private lateinit var appOpenAdManager: AppOpenAdManager

  override fun onCreate() {
    super.onCreate()
    val backgroundScope = CoroutineScope(Dispatchers.IO)
    backgroundScope.launch {
      // Initialize the Google Mobile Ads SDK on a background thread.
      MobileAds.initialize(this@MyApplication) {}
    }
    appOpenAdManager = AppOpenAdManager()
  }
}

広告を読み込む

次のステップでは、loadAd() メソッドに記入します。

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;
          }
        })
  }
  ...
}

AppOpenAdLoadCallback には、AppOpenAd が読み込みを完了したときに呼び出されるメソッドがあります。

現在のアクティビティを追跡する

広告を表示するには、Activity コンテキストが必要です。ユーザーが使用している最新のアクティビティを追跡するには、Application クラスに Application.ActivityLifecycleCallbacks を実装します。

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) {}
}

現在のアクティビティを追跡することで、広告の表示に使用するコンテキストを得ることができます。次に、registerActivityLifecycleCallbacks メソッドを使用してこのインターフェースを登録する必要があります。

Java

public class MyApplication extends Application {
  ...
  @Override
  public void onCreate() {
    super.onCreate();
    this.registerActivityLifecycleCallbacks(this);
    new Thread(
            () -> {
              // Initialize the Google Mobile Ads SDK on a background thread.
              MobileAds.initialize(this, initializationStatus -> {});
            })
        .start();
    appOpenAdManager = new AppOpenAdManager();
  }
}

Kotlin

class MyApplication : Application() {
  ...
  override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(this)
    val backgroundScope = CoroutineScope(Dispatchers.IO)
    backgroundScope.launch {
      // Initialize the Google Mobile Ads SDK on a background thread.
      MobileAds.initialize(this@MyApplication) {}
    }
    appOpenAdManager = AppOpenAdManager()
  }
}

registerActivityLifecycleCallbacks を使用すると、すべての Activity イベントをリッスンできます。アクティビティが開始および破棄されるタイミングをリッスンすることで、現在の Activity への参照をトラッキングできます。この参照は、アプリ起動時広告を表示するときに使用します。

広告を表示して全画面表示のコールバック イベントを処理する

次のコードは、広告が表示されるタイミングと、その後に広告を再読み込みするタイミングを示しています。

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)
    }
    ...
  }
}

FullScreenContentCallback は、広告が表示されたとき、表示されなかったとき、広告が閉じられたときなどのイベントを処理します。アプリ起動時広告をクリックしてアプリを離れたユーザーがアプリに戻ってきた場合、別のアプリ起動時広告は表示されなくなります。

アプリのフォアグラウンド イベントをリッスンする

Gradle ファイルにライブラリを追加する

アプリのフォアグラウンド イベントについて通知を受け取るには、LifecycleObserver を登録する必要があります。まず、アプリケーション レベルの build.gradle ファイルを編集して、LifecycleObserver ライブラリを含めます。

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:23.1.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"
}

LifecycleObserver インターフェースを実装する

LifecycleObserver インターフェースを実装すると、Application クラスでフォアグラウンド イベントをリッスンできます。

Java

public class MyApplication extends Application
    implements ActivityLifecycleCallbacks, LifecycleObserver { {
  ...
  @Override
  public void onCreate() {
    super.onCreate();
    this.registerActivityLifecycleCallbacks(this);
    new Thread(
            () -> {
              // Initialize the Google Mobile Ads SDK on a background thread.
              MobileAds.initialize(this, initializationStatus -> {});
            })
        .start();
    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)
    val backgroundScope = CoroutineScope(Dispatchers.IO)
    backgroundScope.launch {
      // Initialize the Google Mobile Ads SDK on a background thread.
      MobileAds.initialize(this@MyApplication) {}
    }
    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.
          }
        })
  }
}

LifecycleObserver を登録すると、アプリ起動イベントとフォアグラウンド イベントに対してアラートが通知され、適切なタイミングで広告を表示できるようになります。

広告の有効期限に関する考察

期限切れの広告を表示しないようにするには、広告参照が読み込まれてからの経過時間を確認するメソッドを AppOpenAdManager に追加します。次に、このメソッドを使用して、広告がまだ有効かどうかを確認します。

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)
  }
}

コールド スタートと読み込み画面

ここまでのドキュメントでは、アプリがメモリで一時停止しているときにアプリがフォアグラウンドで表示される場合にのみ、アプリ起動時広告を表示することを前提としています。「コールド スタート」は、アプリが起動されたものの、以前にメモリ内で一時停止されていない場合に発生します。

コールド スタートの例として、ユーザーが初めてアプリを起動したときが挙げられます。コールド スタートでは、以前に読み込まれたアプリ起動時広告をすぐに表示することはできません。広告をリクエストしてから広告が返されるまでに時間差があるため、ユーザーがアプリを一時的に使用しても、コンテキストにそぐわない広告で驚くような状況にならない場合があります。この方法は、ユーザー エクスペリエンスが低下するため避ける必要があります。

コールド スタートでアプリ起動時広告を使用する場合のおすすめの方法は、読み込み画面を使用してゲームまたはアプリアセットを読み込み、読み込み画面からのみ広告を表示することです。アプリの読み込みが完了し、ユーザーをアプリのメイン コンテンツに誘導した場合は、広告を表示しないでください。

ベスト プラクティス

アプリ起動時広告は、アプリの初回起動時や切り替え時にアプリの読み込み画面を収益化するのに役立ちますが、ユーザーがアプリを楽しく利用できるように、ベスト プラクティスを常に念頭に置くことが重要です。以下を行うことをおすすめします。

  • ユーザーがアプリを数回使用した後に、アプリ起動時広告を初めて表示する。
  • ユーザーが本来ならアプリの読み込みを待っている間にアプリ起動時広告を表示する。
  • アプリ起動時広告の下に読み込み画面があり、広告が閉じられる前に読み込み画面の読み込みが完了した場合は、onAdDismissedFullScreenContent() メソッドで読み込み画面を閉じることをおすすめします。

GitHub の例

次のステップ

次のトピックをご覧ください。