自定义的原生广告格式

自定义的原生广告格式

除了系统定义的原生广告格式之外,Ad Manager 发布商还可以通过自行指定一系列素材资源来创建自己的原生广告格式。这类格式称为自定义原生广告格式,可以用于预订型广告。这样,发布商就可以将任意结构化数据传递给应用。这些广告由 NativeCustomFormatAd 对象表示。

加载自定义的原生广告格式

本指南介绍了如何加载和显示自定义原生广告格式

构建 AdLoader

与原生广告一样,自定义的原生广告格式也是使用 AdLoader 类加载的:

Java

AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
    .forCustomFormatAd("10063170",
      new NativeCustomFormatAd.OnCustomFormatAdLoadedListener() {
          @Override
          public void onCustomFormatAdLoaded(NativeCustomFormatAd ad) {
              // Show the custom format and record an impression.
          }
      },
      new NativeCustomFormatAd.OnCustomClickListener() {
          @Override
          public void onCustomClick(NativeCustomFormatAd ad, String s) {
              // Handle the click action
          }
      })
    .withAdListener( ... )
    .withNativeAdOptions( ... )
    .build();

Kotlin

val adLoader = AdLoader.Builder(this, "/6499/example/native")
        .forCustomFormatAd("10063170",
            { ad ->
                // Show the custom format and record an impression.
            },
            { ad, s ->
            // Handle the click action
            })
        .withAdListener( ... )
        .withNativeAdOptions( ... )
        .build()

forCustomFormatAd 方法会配置 AdLoader,以请求自定义的原生广告格式。有三个参数传入该方法中:

  • AdLoader 应请求的自定义原生广告格式的 ID。每种自定义原生广告格式都有一个与其关联的 ID。此参数指示您的应用希望 AdLoader 请求哪种格式。
  • 广告成功加载后要调用的 OnCustomFormatAdLoadedListener
  • 用户点按或点击广告时要调用的 OnCustomClickListener(可选)。如需详细了解此监听器,请参阅下面的“处理点击次数和展示次数”部分。

由于单个广告单元可以设置为投放多种广告素材格式,因此可以使用唯一格式 ID 多次调用 forCustomFormatAd,以便为可能存在的多种自定义原生广告格式准备广告加载程序。

自定义的原生广告格式 ID

您可以在 Ad Manager 界面的投放下拉菜单中的原生部分找到用于标识自定义原生广告格式的格式 ID:

每个自定义的原生广告格式 ID 都会显示在其名称旁边。点击其中一个名称可以转到详细信息屏幕,该屏幕显示了有关该格式字段的信息:

在这里,您可以添加、修改和移除各个字段。请注意每项资产的名称。名称是用于在展示自定义原生广告格式时获取每个素材资源数据的键。

展示自定义原生广告格式

自定义原生广告格式与系统定义的原生广告格式的不同之处在于,发布商有权定义自己的构成广告的素材资源列表。因此,与系统定义的格式相比,展示自定义格式的过程会在以下几个方面有所不同:

  1. 因为 NativeCustomFormatAd 类用于处理您在 Ad Manager 中定义的任何自定义原生广告格式,因此它没有命名的素材资源 get 程序。而是提供了 getTextgetImage 等将字段名称作为参数的方法。
  2. 没有 NativeAdView 等可用于 NativeCustomFormatAd 的专用广告视图类。您可以随意使用任何有助于改善用户体验的布局。
  3. 由于没有专用的 ViewGroup 类,因此您无需注册任何用于展示广告素材资源的视图。这会在展示广告时节省几行代码,但也意味着您后续需要做一些额外的工作来处理点击。

以下是一个显示 NativeCustomFormatAd 的示例函数:

Java

public void displayCustomFormatAd (ViewGroup parent,
                                     NativeCustomFormatAd customFormatAd) {
    // Inflate a layout and add it to the parent ViewGroup.
    LayoutInflater inflater = (LayoutInflater) parent.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View adView = inflater.inflate(R.layout.custom_format_ad, parent);

    // Locate the TextView that will hold the value for "Headline" and
    // set its text.
    TextView myHeadlineView = (TextView) adView.findViewById(R.id.headline);
    myHeadlineView.setText(customFormatAd.getText("Headline"));

    // Locate the ImageView that will hold the value for "MainImage" and
    // set its drawable.
    Button myMainImageView = (ImageView) adView.findViewById(R.id.main_image);
    myMainImageView.setImageDrawable(
            customFormatAd.getImage("MainImage").getDrawable());

    ...
    // Continue locating views and displaying assets until finished.
    ...
}

Kotlin

public fun displayCustomFormatAd (parent: ViewGroup,
                                customFormatAd: NativeCustomFormatAd) {
    val adView = layoutInflater
            .inflate(R.layout.ad_simple_custom_format, null)

    val myHeadlineView = adView.findViewById<TextView>(R.id.headline)
    myHeadlineView.setText(customFormatAd.getText("Headline"));

    // Locate the ImageView that will hold the value for "MainImage" and
    // set its drawable.
    val myMainImageView = adView.findViewById(R.id.main_image);
    myMainImageView.setImageDrawable(
            customFormatAd.getImage("MainImage").drawable);

    ...
    // Continue locating views and displaying assets until finished.
    ...
}

呈现“广告选择”图标

根据支持《数字服务法案》(DSA) 的规定,在欧洲经济区 (EEA) 投放的预订型广告必须包含“广告选择”图标和指向 Google 的“关于此广告”页面的链接。植入自定义原生广告时,您需要负责呈现“广告选择”图标。我们建议您采取措施,在呈现主要广告素材资源时呈现“广告选择”图标并设置点击监听器。

以下示例假定您已在视图层次结构中定义了一个 <ImageView /> 元素来保存“广告选择”徽标。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
    <ImageView
        android:id="@+id/adChoices"
        android:layout_width="15dp"
        android:layout_height="15dp"
        android:adjustViewBounds="true"
        android:contentDescription="AdChoices icon." />
</LinearLayout>

以下示例呈现了“广告选择”图标并配置适当的点击行为。

Java

private AdSimpleCustomTemplateBinding customTemplateBinding;

private void populateAdView(final NativeCustomFormatAd nativeCustomFormatAd) {
  // Render the AdChoices icon.
  String adChoicesKey = NativeAdAssetNames.ASSET_ADCHOICES_CONTAINER_VIEW;
  NativeAd.Image adChoicesAsset = nativeCustomFormatAd.getImage(adChoicesKey);
  if (adChoicesAsset == null) {
    customTemplateBinding.adChoices.setVisibility(View.GONE);
  } else {
    customTemplateBinding.adChoices.setVisibility(View.VISIBLE);
    customTemplateBinding.adChoices.setImageDrawable(adChoicesAsset.getDrawable());

    // Enable clicks on AdChoices.
    customTemplateBinding.adChoices.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            nativeCustomFormatAd.performClick(adChoicesKey);
          }
        });
  }
  ...
}

Kotlin

private lateinit var customTemplateBinding: AdSimpleCustomTemplateBinding

private fun populateAdView(nativeCustomFormatAd: NativeCustomFormatAd) {
  // Render the AdChoices icon.
  val adChoicesKey = NativeAdAssetNames.ASSET_ADCHOICES_CONTAINER_VIEW
  val adChoicesAsset = nativeCustomFormatAd.getImage(adChoicesKey)
  if (adChoicesAsset == null) {
    customTemplateBinding.adChoices.visibility = View.GONE
  } else {
    customTemplateBinding.adChoices.setImageDrawable(adChoicesAsset.drawable)
    customTemplateBinding.adChoices.visibility = View.VISIBLE

    // Enable clicks on AdChoices.
    customTemplateBinding.adChoices.setOnClickListener {
      nativeCustomFormatAd.performClick(adChoicesKey)
    }
  }
  ...
}

自定义原生广告格式的原生视频

创建自定义格式时,您可以选择让格式适用于视频。

在您的应用实现中,您可以使用 NativeCustomFormatAd.getMediaContent() 获取媒体内容。然后调用 setMediaContent(),将媒体视图上的媒体内容设置为媒体视图。如果广告没有视频内容,则需要制定备用方案,以便在没有视频的情况下也能展示广告。

以下示例会检查广告是否包含视频内容,如果没有视频,会在相应位置展示图片:

Java

// Called when a custom native ad loads.
@Override
public void onCustomFormatAdLoaded(final NativeCustomFormatAd ad) {

  MediaContent mediaContent = ad.getMediaContent();

  // Assumes you have a FrameLayout in your view hierarchy with the id media_placeholder.
  FrameLayout mediaPlaceholder = (FrameLayout) findViewById(R.id.media_placeholder);

  // Apps can check the MediaContent's hasVideoContent property to determine if the
  // NativeCustomFormatAd has a video asset.
  if (mediaContent != null && mediaContent.hasVideoContent()) {
    MediaView mediaView = new MediaView(mediaPlaceholder.getContext());
    mediaView.setMediaContent(mediaContent);
    mediaPlaceholder.addView(mediaView);

    // Create a new VideoLifecycleCallbacks object and pass it to the VideoController. The
    // VideoController will call methods on this object when events occur in the video
    // lifecycle.
    VideoController vc = mediaContent.getVideoController();
    vc.setVideoLifecycleCallbacks(
        new VideoController.VideoLifecycleCallbacks() {
          @Override
          public void onVideoEnd() {
            // Publishers should allow native ads to complete video playback before
            // refreshing or replacing them with another ad in the same UI location.
            super.onVideoEnd();
          }
        });
  } else {
    ImageView mainImage = new ImageView(this);
    mainImage.setAdjustViewBounds(true);
    mainImage.setImageDrawable(ad.getImage("MainImage").getDrawable());
    mediaPlaceholder.addView(mainImage);
    mainImage.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View view) {
            ad.performClick("MainImage");
          }
        });
  }
}

Kotlin

// Called when a custom native ad loads.
NativeCustomFormatAd.OnCustomFormatAdLoadedListener { ad ->

  val mediaContent = ad.mediaContent

  // Apps can check the MediaContent's hasVideoContent property to determine if the
  // NativeCustomFormatAd has a video asset.
  if (mediaContent != null && mediaContent.hasVideoContent()) {
    val mediaView = MediaView(mediaPlaceholder.getContest())
    mediaView.mediaContent = mediaContent

    val videoController = mediaContent.videoController

    // Create a new VideoLifecycleCallbacks object and pass it to the VideoController. The
    // VideoController will call methods on this object when events occur in the video
    // lifecycle.
    if (videoController != null) {
      videoController.videoLifecycleCallbacks =
        object : VideoController.VideoLifecycleCallbacks() {
          override fun onVideoEnd() {
            // Publishers should allow native ads to complete video playback before refreshing
            // or replacing them with another ad in the same UI location.
            super.onVideoEnd()
          }
        }
    }
  } else {
    val mainImage = ImageView(this)
    mainImage.adjustViewBounds = true
    mainImage.setImageDrawable(ad.getImage("MainImage")?.drawable)

    mainImage.setOnClickListener { ad.performClick("MainImage") }
    customTemplateBinding.simplecustomMediaPlaceholder.addView(mainImage)
  }
}

如需详细了解如何自定义自定义原生广告的视频体验,请参阅 MediaContent

您可以下载 Ad Manager 自定义呈现示例,以获取实际投放的原生视频广告示例。

自定义原生广告格式的点击次数和展示次数

使用自定义原生广告格式时,您的应用负责记录展示次数,并向 Google 移动广告 SDK 报告点击事件。

记录展示次数

要记录自定义格式广告的展示次数,请对相应 NativeCustomFormatAd 调用 recordImpression 方法:

myCustomFormatAd.recordImpression();

如果您的应用不小心针对同一个广告调用该方法两次,则 SDK 会自动阻止系统针对单个请求重复记录展示。

报告点击次数

要向 SDK 报告在素材资源视图中发生了点击,请在相应 NativeCustomFormatAd 上调用 performClick 方法,并传入获得点击的素材资源的名称。例如,如果您的自定义格式中有一个名为“MainImage”的素材资源,并且您希望报告与该素材资源对应的 ImageView 上的点击,则代码如下所示:

myCustomFormatAd.performClick("MainImage");

请注意,您无需为与广告相关联的每个视图调用此方法。例如,如果您有另一个名为“Caption”的字段,该字段只作展示之用,不会用于接受用户的点击或点按,则您的应用就不需要为该素材资源的视图调用 performClick

响应自定义点击操作

当自定义格式的广告上发生点击时,SDK 可能会作出的响应有三种,具体尝试的响应顺序如下:

  1. AdLoader 调用 OnCustomClickListener(如果已提供)。
  2. 对于每个广告的深层链接网址,尝试查找内容解析器并启动第一个能够解析网址的内容解析器。
  3. 打开浏览器并转至广告的传统目标网址。

forCustomFormatAd 方法接受 OnCustomClickListener。如果您传入监听器对象,SDK 会改为调用其 onCustomClick 方法,并且不会采取进一步操作。但是,如果您传递 null 值作为监听器,SDK 会回退到在广告中注册的深层链接和/或目标网址。

借助自定义点击监听器,您的应用可以决定响应点击的最佳操作,无论是更新界面、启动新 activity,还是仅记录点击。以下是一个仅记录发生的点击的示例:

Java

AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
    .forCustomFormatAd("10063170",
      new NativeCustomFormatAd.OnCustomFormatAdLoadedListener() {
        // Display the ad.
      },
      new NativeCustomFormatAd.OnCustomClickListener() {
          @Override
          public void onCustomClick(NativeCustomFormatAd ad, String assetName) {
            Log.i("MyApp", "A custom click just happened for " + assetName + "!");
          }
      }).build();

Kotlin

val adLoader = AdLoader.Builder(this, "/6499/example/native")
    .forCustomFormatAd("10063170",
        { ad ->
            // Display the ad.
        },
        { ad, assetName ->
                Log.i("MyApp", "A custom click just happened for $assetName!")
    }).build()

乍一看,自定义点击监听器的存在似乎很奇怪。毕竟,您的应用刚刚告诉 SDK 发生了一次点击,为什么 SDK 应该反过来向应用报告?

这种信息流动其实有多方面的用处,但最重要的是,它让 SDK 能够保持对点击响应的控制。例如,它可以自动对已为广告素材设置的第三方跟踪网址执行 ping 操作,并在后台处理其他任务,而无需任何其他代码。