動画リワード アダプタの実装

このガイドは、AdMob メディエーション プラットフォームで第三者広告ネットワークの動画リワード広告を表示することに関心をお持ちの方を対象としています。

AdMob でサポートされている広告ネットワークとカスタム イベント

AdMob メディエーション プラットフォームで直接サポートされている広告ネットワークでは、標準のメディエーション アダプタを実装できます。AdMob で直接サポートされていない広告ネットワークでも、カスタム イベント アダプタを実装して、動画リワードをリクエスト、表示できます。標準のメディエーション アダプタとカスタム イベント アダプタの違いは下記のとおりです。

サーバー パラメータの定義

AdMob メディエーション プラットフォームで使われる広告ネットワークでは、パブリッシャーを識別するための ID が必要となります。こうした ID はサーバー パラメータとして表され、メディエーションで使用する第三者広告ネットワークを AdMob 管理画面で設定する際に定義されます。

カスタム イベント アダプタを構築する場合は、以下のカスタム イベントの作成に関する手順を参考にしてください。アダプタを構築すると、広告ネットワークと対応するサーバー パラメータが、AdMob で広告ネットワーク オンボーディング プロセスの一部として設定されます。

カスタム イベントの作成

カスタム イベントを定義するには、まず AdMob 管理画面でそのカスタム イベントを作成する必要があります。カスタム イベントを作成する手順については、カスタム イベントの追加をご覧ください。定義したら、そのカスタム イベントで、MediationRewardedVideoAdAdapter を実装しているアプリ内のクラスをポイントして、動画リワードを配信します。カスタム イベントでは、動画リワード アダプタに渡すサーバー パラメータも登録します。

カスタム イベントの設定サンプルのスクリーンショットを次に示します。

このスクリーンショットで指定されているエントリは次のとおりです。

クラス名
カスタム イベントを実装するクラスの完全修飾名です。
ラベル
イベントに固有の名前です。
パラメータ
カスタム イベントに渡されるオプションの引数です。

メディエーション アダプタの実装

このセクションでは、アダプタの実装に必要となる手順を示します。Google では、実際のアダプタコードの形式を示すため、サンプル広告ネットワーク SDK を作成しています。この SDK に対応したアダプタを構築することにします。

アダプタの初期化

アプリの最初の動画リワード広告リクエストで、Google Mobile Ads SDK がアダプタの initialize() メソッドを呼び出します。

このメソッドを実装して第三者広告ネットワークを初期化する作業は、アダプタ側で行います。初期化を完了するには、このメソッドで提供される serverParameters のバンドルが必要となる可能性があります。メディエーション アダプタとカスタム イベント アダプタのどちらを作成するかによって、これらのパラメータにアクセスする方法は多少異なります。

メディエーション アダプタの場合、サーバー パラメータのキーはあらかじめ設定されており、サーバー パラメータは個別に取得できます。カスタム イベントの場合は、MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD キーを経由して 1 つのパラメータにアクセスできます。

メディエーション アダプタ

String parameter1 = serverParameters.getString("SERVER_PARAMETER_KEY1");
String parameter2 = serverParameters.getString("SERVER_PARAMETER_KEY2");

カスタム イベント

String parameter = serverParameters.getString(MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD);

アダプタでは、MediationRewardedVideoAdListener インスタンスへの参照を保持して、広告イベントが Google Mobile Ads SDK に転送されるようにする必要があります。初期化に成功した場合は、アダプタで MediationRewardedVideoAdListener.onInitializationSucceeded() を呼び出します。

初期化に失敗した場合は、MediationRewardedVideoAdListener.onInitializationFailed() を呼び出してください。初期化が失敗した場合には、動画リワード広告のリクエストがあるたびに、Google Mobile Ads SDK がアダプタを初期化する試みを繰り返します。以下に initialize() メソッドの実装サンプルを示します。

@Override
public void initialize(Context context,
    MediationAdRequest mediationAdRequest,
    String unused,
    MediationRewardedVideoAdListener listener,
    Bundle serverParameters,
    Bundle mediationExtras) {

    // In this method you should initialize your SDK.

    // The sample SDK requires activity context to initialize, so check
    // that the context provided by the app is an activity context before
    // initializing.
    if (!(context instanceof Activity)) {
        // Context not an Activity context, log the reason for failure and
        // fail the initialization.
        Log.d(TAG, "Sample SDK requires an Activity context to initialize");
        listener.onInitializationFailed(
            SampleAdapter.this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        return;
    }

    // Get the Ad Unit ID for the Sample SDK from serverParameters bundle.
    String adUnit = serverParameters.getString(
        MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD);

    if (TextUtils.isEmpty(adUnit)) {
        listener.onAdFailedToLoad(this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        return;
    }

    // Create a rewarded video event forwarder to forward the events from
    // the Sample SDK to the Google Mobile Ads SDK.
    mRewardedVideoEventForwarder =
        new SampleMediationRewardedVideoEventForwarder(listener, SampleAdapter.this);

    // Initialize the Sample SDK.
    SampleRewardedVideo.initialize((Activity) context, adUnit, mRewardedVideoEventForwarder);
}
public class SampleMediationRewardedVideoEventForwarder extends SampleRewardedVideoAdListener {
    ...
    @Override
    public void onRewardedVideoInitialized() {
        super.onRewardedVideoInitialized();
        mIsInitialized = true;
        mMediationRewardedVideoAdListener.onInitializationSucceeded(mSampleAdapter);
    }

    @Override
    public void onRewardedVideoInitializationFailed(SampleErrorCode error) {
        super.onRewardedVideoInitializationFailed(error);
        mIsInitialized = false;
        mMediationRewardedVideoAdListener.onInitializationFailed(
            mSampleAdapter, getAdMobErrorCode(error));
    }
}

初期化状態を返す

アダプタの isInitialized() メソッドでは、MediationRewardedVideoAdListener.onInitializationSucceeded() の最初の呼び出しが行われるまで false を返す必要があります。最初の呼び出しでは、次に示すようにこのメソッドで常に true を返す必要があります。

@Override
public boolean isInitialized() {
    return mRewardedVideoEventForwarder != null && mRewardedVideoEventForwarder.isInitialized();
}

動画リワードを読み込む

アダプタで MediationRewardedVideoAdListener.onInitializationSucceeded() メソッドを呼び出すと、Google Mobile Ads SDK でアダプタの loadAd() メソッドを呼び出せるようになります。表示する動画リワードがある場合は、このメソッドで動画リワードをリクエストして MediationRewardedVideoAdListener.onAdLoaded() を呼び出す必要があります。表示できる動画がない場合は、MediationRewardedVideoAdListener.onAdFailedToLoad() を呼び出します。

動画リワードに関しては、多くの広告ネットワークが広告リクエストという概念のない API を採用しています。その場合には、広告ネットワークの初期化が完了したら、現在のユーザーに適した広告枠と表示可能な広告があるかどうかを確認します。この条件が満たされていれば、ユーザーに広告を表示できます。そうした広告ネットワークでの loadAd() の実装サンプルを以下に示します。

@Override
public void loadAd(MediationAdRequest mediationAdRequest,
    Bundle serverParameters,
    Bundle mediationExtras) {
    if (SampleRewardedVideo.isAdAvailable()) {
        // Ad already available, use the forwarder to send a success callback
        // to AdMob.
        mRewardedVideoEventForwarder.onAdLoaded();
    } else {
        // No ad available, use the forwarder to send a failure callback.
        mRewardedVideoEventForwarder.onAdFailedToLoad();
    }
}

最初の広告リクエストでは、MediationRewardedVideoAdListener.onInitializationSucceeded() メソッドを呼び出した直後に、loadAd() が呼び出される場合があります。この時点で広告ネットワークで広告の読み込みが終わっていない場合、直ちに広告の読み込み失敗を通知してしまうと、動画リワード広告に対する最初のリクエストの大部分で広告が返されない結果となる可能性があります。そこで、このような場合には、アダプタで広告の読み込み状況をトラッキングして、広告の読み込みが終わる(成功するか失敗する)まで、Google Mobile Ads SDK への通知を遅らせることをおすすめします。なお、アダプタが迅速に応答しない場合に備え、Google Mobile Ads SDK にはタイムアウトが設定されています。

動画リワード広告の表示

Google Mobile Ads SDK では、広告の読み込み成功の通知をアダプタから受け取ると、その後はいつでもアダプタの showVideo() メソッドを呼び出す可能性があります。showVideo() メソッドは、loadAd() コールバックが成功するごとに 1 回だけ呼び出されます。このメソッドが呼び出されたら、アダプタで動画リワードを再生します。

@Override
public void showVideo() {
    // Show the rewarded video ad.
    if (SampleRewardedVideo.isAdAvailable()) {
        // Rewarded video ad available, show ad.
        SampleRewardedVideo.showAd();
    } else {
        // Show ad will only be called if the adapter sends back an ad
        // loaded callback in response to a loadAd request. If for any
        // reason the adapter is not ready to show an ad after sending
        // an ad loaded callback, log a warning.
        Log.w(TAG, "No ads to show.");
    }
}

リワードの定義

アダプタでユーザーに報酬を提供する準備ができたら、RewardItem インターフェースに適合するオブジェクトを作成する必要があります。以下に RewardItem の実装サンプルを示します。

/**
* A {@link RewardItem} that maps the sample reward type and reward amount.
*/
public class SampleRewardItem implements RewardItem {
    private String mRewardType;
    private int mRewardAmount;

    /**
    * Creates a {@link SampleRewardItem}.
    *
    * @param rewardType   the sample reward type.
    * @param rewardAmount the sample reward amount.
    */
    public SampleRewardItem(String rewardType, int rewardAmount) {
        this.mRewardType = rewardType;
        this.mRewardAmount = rewardAmount;
    }

    @Override
    public String getType() {
        return mRewardType;
    }

    @Override
    public int getAmount() {
        return mRewardAmount;
    }
}

ユーザーに報酬が提供されることを Google Mobile Ads SDK に通知するには、アダプタで RewardItem のインスタンスを引数として使用した MediationRewardedVideoAdListener.onRewarded() メソッドを呼び出す必要があります。

Google Mobile Ads SDK に対する広告イベントの転送

次のいずれかの広告イベントが発生した場合は、アダプタで Google Mobile Ads SDK に通知する必要があります。

MediationRewardedVideoAdListener メソッド 呼び出すケース
onAdOpened() 全画面オーバーレイがアプリ コンテンツを覆ったとき
onVideoStarted() 動画広告が始まったとき
onAdClicked() 動画広告がクリックされたとき
onAdLeftApplication() 動画広告が原因でユーザーがアプリを離れたとき(ブラウザに移動するなど)
onRewarded() 動画広告でユーザーに報酬が提供されたとき
onAdClosed() 動画広告が閉じられたとき

Google Mobile Ads SDK に広告の転送を実装する方法の一例を以下に示します。

/**
* A SampleRewardedVideoAdListener that forwards events to AdMob mediation's
* link.
*/
public class SampleMediationRewardedVideoEventForwarder extends SampleRewardedVideoAdListener {
    private MediationRewardedVideoAdListener mMediationRewardedVideoAdListener;
    private SampleAdapter mSampleAdapter;
    private boolean mIsInitialized;

    /**
    * Creates a new SampleMediationRewardedVideoEventForwarder.
    *
    * @param listener      An AdMob Mediation MediationRewardedVideoAdListener that should
    *                      receive forwarded events.
    * @param sampleAdapter A SampleAdapter mediation adapter.
    */
    public SampleMediationRewardedVideoEventForwarder(MediationRewardedVideoAdListener listener,
    SampleAdapter sampleAdapter) {
        this.mMediationRewardedVideoAdListener = listener;
        this.mSampleAdapter = sampleAdapter;
    }

    /**
    * @return whether or not the Sample SDK is initialized.
    */
    public boolean isInitialized() {
        return mIsInitialized;
    }

    @Override
    public void onRewardedVideoInitialized() {
        super.onRewardedVideoInitialized();
        mIsInitialized = true;
        mMediationRewardedVideoAdListener.onInitializationSucceeded(mSampleAdapter);
    }

    @Override
    public void onRewardedVideoInitializationFailed(SampleErrorCode error) {
        super.onRewardedVideoInitializationFailed(error);
        mIsInitialized = false;
        mMediationRewardedVideoAdListener.onInitializationFailed(
        mSampleAdapter, getAdMobErrorCode(error));
    }

    @Override
    public void onAdRewarded(final String rewardType, final int amount) {
        super.onAdRewarded(rewardType, amount);

        /*
        * AdMob requires a reward item with a reward type and amount to be
        * sent when sending the rewarded callback. If your SDK does not
        * have a reward amount you need to do the following:
        *
        * 1. AdMob provides an ability to override the reward value in the
        * front end. Document this asking the publisher to override the
        * reward value on AdMob's front end.
        *
        * 2. Send a reward item with default values for the type (an empty
        * string "") and reward amount (1).
        */
        mMediationRewardedVideoAdListener.onRewarded(
                mSampleAdapter, new SampleRewardItem(rewardType, amount));
    }

    @Override
    public void onAdClicked() {
        super.onAdClicked();
        mMediationRewardedVideoAdListener.onAdClicked(mSampleAdapter);
    }

    @Override
    public void onAdFullScreen() {
        super.onAdFullScreen();
        mMediationRewardedVideoAdListener.onAdOpened(mSampleAdapter);
        // Only send video started here if your SDK starts video
        // immediately after the ad has been opened/is fullscreen.
        mMediationRewardedVideoAdListener.onVideoStarted(mSampleAdapter);
    }

    @Override
    public void onAdClosed() {
        super.onAdClosed();
        mMediationRewardedVideoAdListener.onAdClosed(mSampleAdapter);
    }

    /**
    * Forwards the ad loaded event to AdMob SDK. The Sample SDK does not
    * have an ad loaded callback, the adapter calls this method if an ad
    * is available when loadAd is called.
    */
    protected void onAdLoaded() {
        mMediationRewardedVideoAdListener.onAdLoaded(mSampleAdapter);
    }

    /**
    * Forwards the ad failed event to AdMob SDK. The Sample SDK does not
    * have an ad failed to load callback, the adapter calls this method
    * to forward the failure callback.
    */
    protected void onAdFailedToLoad() {
        mMediationRewardedVideoAdListener.onAdFailedToLoad(
        mSampleAdapter, AdRequest.ERROR_CODE_NO_FILL);
    }

    /**
    * Converts SampleErrorCode into an AdMob SDK's AdRequest error code.
    *
    * @param errorCode a Sample SDK error code.
    * @return an AdMob SDK readable error code.
    */
    private int getAdMobErrorCode(SampleErrorCode errorCode) {
        switch (errorCode) {
            case BAD_REQUEST:
            return AdRequest.ERROR_CODE_INVALID_REQUEST;
        case NETWORK_ERROR:
            return AdRequest.ERROR_CODE_NETWORK_ERROR;
        case NO_INVENTORY:
            return AdRequest.ERROR_CODE_NO_FILL;
        case UNKNOWN:
        default:
            return AdRequest.ERROR_CODE_INTERNAL_ERROR;
        }
    }
}

第三者広告ネットワークでは、その広告ネットワーク用の広告イベント リスナーを使用している可能性があります。第三者 SDK の広告イベントは、アダプタの initialize() メソッドで指定された MediationRewardedVideoAdListener に対応する広告イベントにマッピングして、適切なタイミングで呼び出すことができます。

コンテキストの変更を通知する

アダプタでは、OnContextChangedListener を実装して、現在のコンテキストに加えられた変更が通知されるようにすることもできます。onContextChanged() オブジェクトの現在のコンテキストに変更があった場合は、RewardedVideoAd メソッドが呼び出されます。変更されたアクティビティのコンテキストには、以下に示すようにアクセスできます。

@Override
public void onContextChanged(Context context) {
    if (context instanceof Activity) {
        SampleRewardedVideo.setCurrentActivity((Activity) context);
    }
}

ターゲット設定の追加パラメータ

MediationAdRequest には、広告のターゲットを設定する際に参照できる、ターゲット設定の一般情報が含まれています。

アダプタへのカスタム パラメータの導入

アダプタでメディエーションの対象としている広告ネットワークによっては、MediationAdRequest で提供される情報で対応できない、特別なターゲット設定パラメータや入力値がサポートされている場合があります。このような場合には、情報のバンドルをネットワークに提供するようパブリッシャーに依頼できます。このバンドルは、initialize()loadAd() の両方のメソッドでアダプタに渡されます。

たとえば、パブリッシャーは次の方法で SampleAdapter アダプタにバンドルを提供できます。

Bundle bundle = new Bundle();
bundle.putBoolean("ShouldAddAwesomeSauce", true);
AdRequest adRequest = new AdRequest.Builder()
        .addNetworkExtrasBundle(SampleAdapter.class, bundle)
        .build();

デベロッパーがこのバンドルを簡単に作成できるように、次に示す便利なクラスをアダプタに追加して、パブリッシャーにアダプタ用のバンドルを構築してもらうことをおすすめます。

public static final class MediationExtrasBundleBuilder {

    // Keys to add and obtain the extra parameters from the bundle.
    private static final String KEY_AWESOME_SAUCE = "awesome_sauce";

    /**
    * An extra value used to populate the "ShouldAddAwesomeSauce" property
    * of the Sample SDK's ad request.
    */
    private boolean mShouldAddAwesomeSauce;

    public MediationExtrasBundleBuilder setShouldAddAwesomeSauce(
            boolean shouldAddAwesomeSauce) {
        this.mShouldAddAwesomeSauce = shouldAddAwesomeSauce;
        return MediationExtrasBundleBuilder.this;
    }

    public MediationExtrasBundleBuilder setIncome(int income) {
        this.mIncome = income;
        return MediationExtrasBundleBuilder.this;
    }

    public Bundle build() {
        Bundle extras = new Bundle();
        extras.putInt(KEY_INCOME, mIncome);
        return extras;
    }
}

次の便利なクラスを使用すると、ネットワーク用のバンドルの生成に役立つ簡潔な API が提供されます。

Bundle sampleAdNetworkBundle =
        new SampleAdapter.MediationExtrasBundleBuilder().setShouldAddAwesomeSauce(true).build();