ネイティブ広告のカスタム イベント

前提条件

カスタム イベントのセットアップを完了します。

ネイティブ広告をリクエストする

ウォーターフォール メディエーション チェーンでカスタム イベント広告申込情報に到達すると、カスタム イベントの作成時に指定したクラス名で loadNativeAd() メソッドが呼び出されます。この場合、メソッドは SampleCustomEvent にあり、SampleNativeCustomEventLoaderloadNativeAd() メソッドを呼び出します。

ネイティブ広告をリクエストするには、Adapter を拡張して loadNativeAd() を実装するクラスを作成または変更します。Adapter を拡張するクラスがすでに存在する場合は、そこに loadNativeAd() を実装します。また、UnifiedNativeAdMapper を実装するための新しいクラスを作成します。

カスタム イベントの例では、SampleCustomEventAdapter クラスを拡張し、SampleNativeCustomEventLoader にデリゲートします。

Java

package com.google.ads.mediation.sample.customevent;

import com.google.android.gms.ads.mediation.Adapter;
import com.google.android.gms.ads.mediation.MediationAdConfiguration;
import com.google.android.gms.ads.mediation.MediationAdLoadCallback;

import com.google.android.gms.ads.mediation.MediationNativeAdCallback;
...
public class SampleCustomEvent extends Adapter {
  private SampleNativeCustomEventLoader nativeLoader;

  @Override
  public void loadNativeAd(
      @NonNull MediationNativeAdConfiguration adConfiguration,
      @NonNull MediationAdLoadCallback<UnifiedNativeAdMapper, MediationNativeAdCallback> callback) {
    nativeLoader = new SampleNativeCustomEventLoader(adConfiguration, callback);
    nativeLoader.loadAd();
  }
}

SampleNativeCustomEventLoader の役割は次のとおりです。

  • ネイティブ広告を読み込む。

  • UnifiedNativeAdMapper クラスを実装する。

  • 広告イベント コールバックを受信して Google Mobile Ads SDK に報告する。

AdMob の管理画面で定義されたオプション パラメータが広告設定に含まれています。このパラメータには adConfiguration.getServerParameters().getString(MediationConfiguration.CUSTOM_EVENT_SERVER_PARAMETER_FIELD) を介してアクセスできます。このパラメータは通常、広告オブジェクトをインスタンス化する際に広告ネットワーク SDK が要求する広告ユニット ID です。

Java

package com.google.ads.mediation.sample.customevent;

import com.google.android.gms.ads.mediation.Adapter;
import com.google.android.gms.ads.mediation.MediationNativeAdConfiguration;
import com.google.android.gms.ads.mediation.MediationAdLoadCallback;
import com.google.android.gms.ads.mediation.MediationNativeAdCallback;
...

public class SampleNativeCustomEventLoader extends SampleNativeAdListener {
  /** Configuration for requesting the native ad from the third-party network. */
  private final MediationNativeAdConfiguration mediationNativeAdConfiguration;

  /** Callback that fires on loading success or failure. */
  private final MediationAdLoadCallback<UnifiedNativeAdMapper, MediationNativeAdCallback>
      mediationAdLoadCallback;

  /** Callback for native ad events. */
  private MediationNativeAdCallback nativeAdCallback;

  /** Constructor */
  public SampleNativeCustomEventLoader(
      @NonNull MediationNativeAdConfiguration mediationNativeAdConfiguration,
      @NonNull MediationAdLoadCallback<MediationNativeAd, MediationNativeAdCallback>
              mediationAdLoadCallback) {
    this.mediationNativeAdConfiguration = mediationNativeAdConfiguration;
    this.mediationAdLoadCallback = mediationAdLoadCallback;
  }

  /** Loads the native ad from the third-party ad network. */
  public void loadAd() {
    // Create one of the Sample SDK's ad loaders to request ads.
    Log.i("NativeCustomEvent", "Begin loading native ad.");
    SampleNativeAdLoader loader =
        new SampleNativeAdLoader(mediationNativeAdConfiguration.getContext());

    // All custom events have a server parameter named "parameter" that returns
    // back the parameter entered into the UI when defining the custom event.
    String serverParameter = mediationNativeAdConfiguration
        .getServerParameters()
        .getString(MediationConfiguration
        .CUSTOM_EVENT_SERVER_PARAMETER_FIELD);
    Log.d("NativeCustomEvent", "Received server parameter.");

    loader.setAdUnit(serverParameter);

    // Create a native request to give to the SampleNativeAdLoader.
    SampleNativeAdRequest request = new SampleNativeAdRequest();
    NativeAdOptions options = mediationNativeAdConfiguration.getNativeAdOptions();
    if (options != null) {
      // If the NativeAdOptions' shouldReturnUrlsForImageAssets is true, the adapter should
      // send just the URLs for the images.
      request.setShouldDownloadImages(!options.shouldReturnUrlsForImageAssets());

      request.setShouldDownloadMultipleImages(options.shouldRequestMultipleImages());
      switch (options.getMediaAspectRatio()) {
        case NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_LANDSCAPE:
          request.setPreferredImageOrientation(SampleNativeAdRequest.IMAGE_ORIENTATION_LANDSCAPE);
          break;
        case NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_PORTRAIT:
          request.setPreferredImageOrientation(SampleNativeAdRequest.IMAGE_ORIENTATION_PORTRAIT);
          break;
        case NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_SQUARE:
        case NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_ANY:
        case NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_UNKNOWN:
        default:
          request.setPreferredImageOrientation(SampleNativeAdRequest.IMAGE_ORIENTATION_ANY);
      }
    }

    loader.setNativeAdListener(this);

    // Begin a request.
    Log.i("NativeCustomEvent", "Start fetching native ad.");
    loader.fetchAd(request);
  }
}

広告の取得が成功した場合もエラーが発生した場合も、onSuccess() または onFailure() を呼び出すことになります。onSuccess() は、MediationNativeAd を実装するクラスのインスタンスを渡すことで呼び出されます。

通常、これらのメソッドは、アダプタが実装するサードパーティ SDK のコールバック内に実装されます。この例では、関連するコールバックを含む SampleAdListener が「Sample SDK」に含まれています。

Java

@Override
public void onNativeAdFetched(SampleNativeAd ad) {
  SampleUnifiedNativeAdMapper mapper = new SampleUnifiedNativeAdMapper(ad);
  mediationNativeAdCallback = mediationAdLoadCallback.onSuccess(mapper);
}

@Override
public void onAdFetchFailed(SampleErrorCode errorCode) {
  mediationAdLoadCallback.onFailure(SampleCustomEventError.createSampleSdkError(errorCode));
}

ネイティブ広告をマッピングする

ネイティブ広告を扱うフォーマットは、SDK ごとに異なります。たとえば、「title」フィールドを含むオブジェクトを返すものもあれば、「headline」フィールドを含むものもあります。また、インプレッションの測定とクリックの処理に使われるメソッドが SDK によって異なることもあります。

UnifiedNativeAdMapper は、こうした違いを解消するため、メディエーション向け SDK のネイティブ広告オブジェクトを、Google Mobile Ads SDK で期待されるインターフェースに適合するように調整します。カスタム イベントによりこのクラスが拡張され、メディエーション向け SDK に固有の独自のマッパーが作成される必要があります。サンプル カスタム イベント プロジェクトのサンプル マッパーを次に示します。

Java

package com.google.ads.mediation.sample.customevent;

import com.google.android.gms.ads.mediation.UnifiedNativeAdMapper;
import com.google.android.gms.ads.nativead.NativeAd;
...

public class SampleUnifiedNativeAdMapper extends UnifiedNativeAdMapper {

  private final SampleNativeAd sampleAd;

  public SampleUnifiedNativeAdMapper(SampleNativeAd ad) {
    sampleAd = ad;
    setHeadline(sampleAd.getHeadline());
    setBody(sampleAd.getBody());
    setCallToAction(sampleAd.getCallToAction());
    setStarRating(sampleAd.getStarRating());
    setStore(sampleAd.getStoreName());
    setIcon(
        new SampleNativeMappedImage(
            ad.getIcon(), ad.getIconUri(), SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));
    setAdvertiser(ad.getAdvertiser());

    List<NativeAd.Image> imagesList = new ArrayList<NativeAd.Image>();
    imagesList.add(new SampleNativeMappedImage(ad.getImage(), ad.getImageUri(),
        SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));
    setImages(imagesList);

    if (sampleAd.getPrice() != null) {
      NumberFormat formatter = NumberFormat.getCurrencyInstance();
      String priceString = formatter.format(sampleAd.getPrice());
      setPrice(priceString);
    }

    Bundle extras = new Bundle();
    extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, ad.getDegreeOfAwesomeness());
    this.setExtras(extras);

    setOverrideClickHandling(false);
    setOverrideImpressionRecording(false);

    setAdChoicesContent(sampleAd.getInformationIcon());
  }

  @Override
  public void recordImpression() {
    sampleAd.recordImpression();
  }

  @Override
  public void handleClick(View view) {
    sampleAd.handleClick(view);
  }

  // The Sample SDK doesn't do its own impression/click tracking, instead relies on its
  // publishers calling the recordImpression and handleClick methods on its native ad object. So
  // there's no need to pass a reference to the View being used to display the native ad. If
  // your mediated network does need a reference to the view, the following method can be used
  // to provide one.

  @Override
  public void trackViews(View containerView, Map<String, View> clickableAssetViews,
      Map<String, View> nonClickableAssetViews) {
    super.trackViews(containerView, clickableAssetViews, nonClickableAssetViews);
    // If your ad network SDK does its own impression tracking, here is where you can track the
    // top level native ad view and its individual asset views.
  }

  @Override
  public void untrackView(View view) {
    super.untrackView(view);
    // Here you would remove any trackers from the View added in trackView.
  }
}

次に、コンストラクタ コードについて詳しく見てみましょう。

メディエーション対象ネイティブ広告オブジェクトへの参照を保持する

コンストラクタは、サンプル SDK がネイティブ広告用に使用するネイティブ広告クラスである SampleNativeAd パラメータを受け取ります。クリック イベントとインプレッション イベントを渡すことができるように、マッパーはメディエーション対象広告への参照を必要とします。SampleNativeAd はローカル変数として保存されます。

マッピングされたアセット プロパティを設定する

コンストラクタは SampleNativeAd オブジェクトを使用して、アセットを UnifiedNativeAdMapper に自動入力します。

このスニペットは、メディエーション対象広告の価格データを取得し、そのデータを使ってマッパーの価格を設定します。

Java

if (sampleAd.getPrice() != null) {
    NumberFormat formatter = NumberFormat.getCurrencyInstance();
    String priceString = formatter.format(sampleAd.getPrice());
    setPrice(priceString);
}

この例では、メディエーション対象広告では価格は double として保存されますが、AdMob では、そのアセットに対して String が使用されます。マッパーは、このような変換の処理を担当します。

画像アセットをマッピングする

画像アセットのマッピングは、doubleString などのデータ型のマッピングに比べると複雑です。画像は自動でダウンロードされることもあれば、URL 値として返されることもあります。ピクセル密度もさまざまに異なる可能性があります。

こういった細かい部分を管理しやすいよう、Google Mobile Ads SDK には NativeAd.Image クラスが用意されています。デベロッパーは、UnifiedNativeAdMapper のサブクラスを作成して、メディエーション対象ネイティブ広告をマッピングする必要がありますが、同様に NativeAd.Image のサブクラスを作成して、画像アセットをマッピングする必要もあります。

カスタム イベントの SampleNativeMappedImage クラスの例を次に示します。

Java

public class SampleNativeMappedImage extends NativeAd.Image {

  private Drawable drawable;
  private Uri imageUri;
  private double scale;

  public SampleNativeMappedImage(Drawable drawable, Uri imageUri, double scale) {
    this.drawable = drawable;
    this.imageUri = imageUri;
    this.scale = scale;
  }

  @Override
  public Drawable getDrawable() {
    return drawable;
  }

  @Override
  public Uri getUri() {
    return imageUri;
  }

  @Override
  public double getScale() {
    return scale;
  }
}

SampleNativeAdMapper は、マッピングされた画像クラスを次の行で使用して、マッパーのアイコン画像アセットを設定します。

Java

setIcon(new SampleNativeMappedImage(ad.getAppIcon(), ad.getAppIconUri(),
    SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));

Bundle(extras)にフィールドを追加する

メディエーション向け SDK によっては、AdMob ネイティブ広告フォーマット以外の追加アセットが用意されていることがあります。UnifiedNativeAdMapper クラスには、これらのアセットをパブリッシャーに渡すために使用される setExtras() メソッドが含まれています。SampleNativeAdMapper では、これが、サンプル SDK の「degree of awesomeness」アセットに対して使用されます。

Java

Bundle extras = new Bundle();
extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, ad.getDegreeOfAwesomeness());
this.setExtras(extras);

パブリッシャーは、NativeAd クラスの getExtras() メソッドを使用してデータを取得できます。

AdChoices

カスタム イベントは、UnifiedNativeAdMappersetAdChoicesContent() メソッドを使用して AdChoices アイコンを提供する役割を担います。SampleNativeAdMapper から抜粋した次のスニペットは、AdChoices アイコンを提供する方法を示しています。

Java

public SampleNativeAdMapper(SampleNativeAd ad) {
    ...
    setAdChoicesContent(sampleAd.getInformationIcon());
}

インプレッション イベントとクリック イベント

インプレッションとクリックの発生は、Google Mobile Ads SDK とメディエーション対象 SDK の両方で検知される必要がありますが、それをイベントとしてトラッキングする必要があるのは一方の SDK だけです。カスタム イベントで使用できるトラッキングのアプローチは 2 種類あります。メディエーション対象 SDK がインプレッションとクリックの独自トラッキングに対応しているかどうかに応じて、適切なほうを選びましょう。

クリックとインプレッションのトラッキングを Google Mobile Ads SDK で行う

メディエーション対象の SDK が、インプレッションとクリックの独自トラッキングは行わないものの、クリックとインプレッションを記録するメソッドを提供している場合は、Google Mobile Ads SDK がそれらのイベントをトラッキングしてアダプタに通知することができます。UnifiedNativeAdMapper クラスには recordImpression()handleClick() の 2 つのメソッドがあり、カスタム イベントはこれらのメソッドを実装して、メディエーション対象ネイティブ広告オブジェクトの対応メソッドを呼び出します。

Java

@Override
public void recordImpression() {
  sampleAd.recordImpression();
}

@Override
public void handleClick(View view) {
  sampleAd.handleClick(view);
}

SampleNativeAdMapper にはサンプル SDK のネイティブ広告オブジェクトへの参照が保持されるため、そのオブジェクト上の適切なメソッドを呼び出すだけで、クリックまたはインプレッションが報告されます。handleClick() メソッドは単一のパラメータ(クリックを受けたネイティブ広告アセットに対応する View オブジェクト)を受け取ります。

クリックとインプレッションのトラッキングをメディエーション対象 SDK で行う

メディエーション対象 SDK の中には、クリックとインプレッションを独自にトラッキングさせたほうがよいものもあります。その場合は、UnifiedNativeAdMapper のコンストラクタで次の 2 つの呼び出しを行うことによって、デフォルトのクリックとインプレッションのトラッキングをオーバーライドする必要があります。

Java

setOverrideClickHandling(true);
setOverrideImpressionRecording(true);

クリックとインプレッションのトラッキングをオーバーライドするカスタム イベントは、onAdClicked() イベントと onAdImpression() イベントを Google Mobile Ads SDK に報告する必要があります。

インプレッションとクリックをトラッキングするには、メディエーション対象 SDK がトラッキングを有効にするためにビューにアクセスする必要があります。カスタム イベントは trackViews() メソッドをオーバーライドし、そのメソッドを使ってネイティブ広告のビューをメディエーション向け SDK に渡してトラッキングする必要があります。このアプローチは、カスタム イベントのサンプル プロジェクト(このガイドのコード スニペットの取得元)のサンプル SDK では使用されませんが、仮に使用される場合、カスタム イベントのコードは次のようになります。

Java

@Override
public void trackViews(View containerView,
    Map<String, View> clickableAssetViews,
    Map<String, View> nonClickableAssetViews) {
  sampleAd.setNativeAdViewForTracking(containerView);
}

メディエーション向け SDK が個々のアセットのトラッキングをサポートしている場合、clickableAssetViews 内でどのビューをクリック可能にする必要があるかを確認できます。このマップは、NativeAdAssetNames 内のアセット名でキー付けされます。UnifiedNativeAdMapper には対応する untrackView() メソッドが用意されており、カスタム イベントはこのメソッドをオーバーライドしてビューへの参照をすべて解放し、ネイティブ広告オブジェクトとの関連付けを解除します。

メディエーション イベントを Google Mobile Ads SDK に転送する

メディエーションがサポートするすべてのコールバックについては、MediationNativeAdCallback のドキュメントをご覧ください。

カスタム イベントには、こうしたコールバックを可能な限り漏れなく転送させましょう。これにより、アプリは同等イベントを Google Mobile Ads SDK から受け取ることができます。コールバックの使用例を以下に示します。

これで、ネイティブ広告のカスタム イベントの実装が完了しました。サンプル全体は GitHub で入手できます。