アプリ起動時広告

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

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

アプリ起動時広告は、小さなブランディング領域を使って自動的に表示されるため、ユーザーはアプリが起動中であることがわかります。以下は、アプリ起動時広告の表示例です。

以下は、重要な手順の概要です。

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

前提条件

常にテスト広告でテストする

アプリの開発とテストでは必ずテスト広告を使用し、配信中の実際の広告は使用しないでください。実際の広告でテストすると、アカウントが停止される場合があります。

下記のアプリ起動時広告向けのテスト専用広告ユニット ID を使うと、テスト広告を簡単に読み込むことができます。

ca-app-pub-3940256099942544/3419835294

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

Mobile Ads SDK のテスト広告の仕組みについて詳しくは、テスト広告でご確認いただけます。

Application クラスを拡張する

MyApplication という名前の新しいクラスを作成し、以下のコードを追加します。

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

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

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

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

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

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

広告は高速で表示されるので、広告を表示するタイミングの前に広告を読み込むことをおすすめします。そうすれば、アプリがフォアグランドに移動するとすぐに広告が表示されるようになります。ユーティリティ クラスを実装して、広告を表示する必要があるタイミングに先立って広告リクエストが行われるようにします。

AppOpenManager という名前の新しいクラスを作成し、以下のように入力します。

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

このクラスシェルにより、読み込まれた広告、広告ユニット ID、AppOpenAdLoadCallback をトラッキングするためのインスタンス変数が管理されます。

作成したユーティリティ クラスを MyApplication クラスで以下のようにインスタンス化できます。

/** 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);

  }
}

広告を読み込む

次の手順は fetchAd() メソッドの入力です。以下を AppOpenManager クラスに追加します。

/** 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 onAdLoaded(AppOpenAd ad) {
            AppOpenManager.this.appOpenAd = ad;
          }

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

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

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

現在のアクティビティをトラッキングする

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

...
/** 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;
  }
}

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

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

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

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

以下のメソッドを AppOpenManager クラスに追加します。

/** 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.setFullScreenContentCallback(fullScreenContentCallback);
      appOpenAd.show(currentActivity);

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

このメソッドにより広告が表示され、FullScreenContentCallback 匿名クラスを渡して、広告の表示、表示の失敗、表示拒否などのイベントが処理されます。これにより、ユーザーがアプリ起動時広告をクリックしてからアプリに戻った場合に、別のアプリ起動時広告がユーザーに表示されることがなくなります。

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

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

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

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

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

LifecycleObserver インターフェースを実装すると、AppOpenManager クラスのフォアグラウンド イベントをリッスンできます。以下を追加して、クラスを編集します。

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

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

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

期限切れの広告を表示しないようにするには、メソッドを AppOpenManager に追加して、広告参照の読み込みからの経過時間と、広告の有効性を確認できるようにします。AppOpenManager メソッドを以下のように変更します。

/** 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);
  }
}

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

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

コールド スタートの例として、ユーザーが初めてアプリを開くときを挙げることができます。 コールド スタートでは、直ちに表示することのできる読み込み済みのアプリ起動時広告がありません。広告をリクエストしてから広告が返されるまでに時間差があるため、ユーザーが少しだけアプリを使用したところで突然コンテキストから外れた広告が表示されることになってしまいます。ユーザー エクスペリエンスの低下につながるこのような事態は、避ける必要があります。

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

ベスト プラクティス

アプリ起動時広告では、アプリの初回起動時やアプリの切り替え時にアプリの読み込み画面が収益化されますが、ユーザーがアプリをスムーズに使用できるよう、以下のベスト プラクティスを念頭に置いてください。

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

GitHub の例