原生進階

選取平台: Android iOS

顯示 NativeAd

載入原生廣告時,Google Mobile Ads SDK 會叫用相應廣告格式的監聽器。然後由應用程式負責顯示廣告 (但不必立即顯示)。SDK 提供了一些實用資源,以利顯示系統定義的廣告格式,詳情請見下文。

定義 NativeAdView 類別

定義 NativeAdView 類別。這個類別是 ViewGroup 類別,也是 NativeAdView 類別的頂層容器。每個原生廣告檢視區塊都包含原生廣告素材資源,例如 MediaView 檢視區塊元素或 Title 檢視區塊元素,這些元素必須是 NativeAdView 物件的子項。

XML 版面配置

在專案中新增 XML NativeAdView

<com.google.android.gms.ads.nativead.NativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
    android:orientation="vertical">
        <LinearLayout
        android:orientation="horizontal">
          <ImageView
          android:id="@+id/ad_app_icon" />
          <TextView
            android:id="@+id/ad_headline" />
        </LinearLayout>
        <!--Add remaining assets such as the image and media view.-->
    </LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>

Jetpack Compose

加入 JetpackComposeDemo/compose-util 模組,其中包含用於組合 NativeAdView 及其資產的輔助程式。

使用 compose-util 模組撰寫 NativeAdView

  import com.google.android.gms.compose_util.NativeAdAttribution
  import com.google.android.gms.compose_util.NativeAdView

  @Composable
  /** Display a native ad with a user defined template. */
  fun DisplayNativeAdView(nativeAd: NativeAd) {
      NativeAdView {
          // Display the ad attribution.
          NativeAdAttribution(text = context.getString("Ad"))
          // Add remaining assets such as the image and media view.
        }
    }

處理已載入的原生廣告

載入原生廣告時,請處理回呼事件、擴充原生廣告檢視區塊,並將其加入檢視區塊階層:

Java

AdLoader.Builder builder = new AdLoader.Builder(this, "/21775744923/example/native")
    .forNativeAd(new NativeAd.OnNativeAdLoadedListener() {
        @Override
        public void onNativeAdLoaded(NativeAd nativeAd) {
            // Assumes you have a placeholder FrameLayout in your View layout
            // (with ID fl_adplaceholder) where the ad is to be placed.
            FrameLayout frameLayout =
                findViewById(R.id.fl_adplaceholder);
            // Assumes that your ad layout is in a file call native_ad_layout.xml
            // in the res/layout folder
            NativeAdView adView = (NativeAdView) getLayoutInflater()
                .inflate(R.layout.native_ad_layout, null);
            // This method sets the assets into the ad view.
            populateNativeAdView(nativeAd, adView);
            frameLayout.removeAllViews();
            frameLayout.addView(adView);
        }
});

Kotlin

val builder = AdLoader.Builder(this, "/21775744923/example/native")
    .forNativeAd { nativeAd ->
        // Assumes you have a placeholder FrameLayout in your View layout
        // (with ID fl_adplaceholder) where the ad is to be placed.
        val frameLayout: FrameLayout = findViewById(R.id.fl_adplaceholder)
        // Assumes that your ad layout is in a file call native_ad_layout.xml
        // in the res/layout folder
        val adView = layoutInflater
                .inflate(R.layout.native_ad_layout, null) as NativeAdView
        // This method sets the assets into the ad view.
        populateNativeAdView(nativeAd, adView)
        frameLayout.removeAllViews()
        frameLayout.addView(adView)
    }

Jetpack Compose

@Composable
/** Load and display a native ad. */
fun NativeScreen() {
  var nativeAd by remember { mutableStateOf<NativeAd?>(null) }
  val context = LocalContext.current
  var isDisposed by remember { mutableStateOf(false) }

  DisposableEffect(Unit) {
    // Load the native ad when we launch this screen
    loadNativeAd(
      context = context,
      onAdLoaded = { ad ->
        // Handle the native ad being loaded.
        if (!isDisposed) {
          nativeAd = ad
        } else {
          // Destroy the native ad if loaded after the screen is disposed.
          ad.destroy()
        }
      },
    )
    // Destroy the native ad to prevent memory leaks when we dispose of this screen.
    onDispose {
      isDisposed = true
      nativeAd?.destroy()
      nativeAd = null
    }
  }

  // Display the native ad view with a user defined template.
  nativeAd?.let { adValue -> DisplayNativeAdView(adValue) }
}

fun loadNativeAd(context: Context, onAdLoaded: (NativeAd) -> Unit) {
  val adLoader =
    AdLoader.Builder(context, NATIVE_AD_UNIT_ID)
      .forNativeAd { nativeAd -> onAdLoaded(nativeAd) }
      .withAdListener(
        object : AdListener() {
          override fun onAdFailedToLoad(error: LoadAdError) {
            Log.e(TAG, "Native ad failed to load: ${error.message}")
          }

          override fun onAdLoaded() {
            Log.d(TAG, "Native ad was loaded.")
          }

          override fun onAdImpression() {
            Log.d(TAG, "Native ad recorded an impression.")
          }

          override fun onAdClicked() {
            Log.d(TAG, "Native ad was clicked.")
          }
        }
      )
      .build()
  adLoader.loadAd(AdRequest.Builder().build())
}

請注意,特定原生廣告的所有素材資源都應在 NativeAdView 版面配置中算繪。當原生素材資源在原生廣告檢視區塊版面配置外顯示時,Google Mobile Ads SDK 會嘗試記錄警告。

廣告檢視區塊類別也提供方法,用於註冊所有個別素材資源的檢視區塊,以及註冊 NativeAd 物件本身。以這種方式註冊檢視區塊,可讓 SDK 自動處理下列工作:

  • 記錄點擊
  • 畫面顯示第一個像素時,系統會記錄曝光
  • 為原生遞補廣告素材顯示 AdChoices 疊加層,目前僅限部分發布商使用

AdChoices 廣告標籤

SDK 會在系統傳回候補廣告時,將 AdChoices 疊加層新增為廣告檢視畫面。如果應用程式使用原生廣告遞補功能,請在原生廣告檢視區塊的偏好角落預留空間,供系統自動插入 AdChoices 標誌。此外,疊加在廣告中的 AdChoices 標籤必須清楚易見,因此請選用合適的背景顏色和圖片。請參閱程式輔助原生廣告導入指南,進一步瞭解重疊廣告的外觀和功能。

程式輔助原生廣告的廣告出處

顯示程式輔助原生廣告時,您必須顯示廣告標示,表明該檢視區塊是廣告。詳情請參閱政策指南

程式碼範例

顯示原生廣告的步驟如下:

  1. 建立 NativeAdView 類別的執行個體。
  2. 如要顯示各項廣告素材資源,請確認符合下列條件:

    1. 在廣告物件中填入素材資源,並顯示在素材資源檢視畫面中。
    2. 使用 NativeAdView 類別註冊素材資源檢視區塊。
  3. 如果原生廣告版面配置包含大型媒體素材資源,請註冊 MediaView

  4. 使用 NativeAdView 類別註冊廣告物件。

以下是顯示 NativeAd 的函式範例:

Java

private void displayNativeAd(ViewGroup parent, NativeAd ad) {

  // Inflate a layout and add it to the parent ViewGroup.
  LayoutInflater inflater = (LayoutInflater) parent.getContext()
          .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  NativeAdView adView = (NativeAdView) inflater
          .inflate(R.layout.ad_layout_file, parent);

  // Locate the view that will hold the headline, set its text, and call the
  // NativeAdView's setHeadlineView method to register it.
  TextView headlineView = adView.findViewById<TextView>(R.id.ad_headline);
  headlineView.setText(ad.getHeadline());
  adView.setHeadlineView(headlineView);

  // Repeat the process for the other assets in the NativeAd
  // using additional view objects (Buttons, ImageViews, etc).

  // If the app is using a MediaView, it should be
  // instantiated and passed to setMediaView. This view is a little different
  // in that the asset is populated automatically, so there's one less step.
  MediaView mediaView = (MediaView) adView.findViewById(R.id.ad_media);
  adView.setMediaView(mediaView);

  // Call the NativeAdView's setNativeAd method to register the
  // NativeAdObject.
  adView.setNativeAd(ad);

  // Ensure that the parent view doesn't already contain an ad view.
  parent.removeAllViews();

  // Place the AdView into the parent.
  parent.addView(adView);
}

Kotlin

fun displayNativeAd(parent: ViewGroup, ad: NativeAd) {

  // Inflate a layout and add it to the parent ViewGroup.
  val inflater = parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)
          as LayoutInflater
  val adView = inflater.inflate(R.layout.ad_layout_file, parent) as NativeAdView

  // Locate the view that will hold the headline, set its text, and use the
  // NativeAdView's headlineView property to register it.
  val headlineView = adView.findViewById<TextView>(R.id.ad_headline)
  headlineView.text = ad.headline
  adView.headlineView = headlineView

  // Repeat the process for the other assets in the NativeAd using
  // additional view objects (Buttons, ImageViews, etc).

  val mediaView = adView.findViewById<MediaView>(R.id.ad_media)
  adView.mediaView = mediaView

  // Call the NativeAdView's setNativeAd method to register the
  // NativeAdObject.
  adView.setNativeAd(ad)

  // Ensure that the parent view doesn't already contain an ad view.
  parent.removeAllViews()

  // Place the AdView into the parent.
  parent.addView(adView)
}

Jetpack Compose

@Composable
/** Display a native ad with a user defined template. */
fun DisplayNativeAdView(nativeAd: NativeAd) {
  val context = LocalContext.current
  Box(modifier = Modifier.padding(8.dp).wrapContentHeight(Alignment.Top)) {
    // Call the NativeAdView composable to display the native ad.
    NativeAdView {
      // Inside the NativeAdView composable, display the native ad assets.
      Column(Modifier.align(Alignment.TopStart).wrapContentHeight(Alignment.Top)) {
        // Display the ad attribution.
        NativeAdAttribution(text = context.getString(R.string.attribution))
        Row {
          // If available, display the icon asset.
          nativeAd.icon?.let { icon ->
            NativeAdIconView(Modifier.padding(5.dp)) {
              icon.drawable?.toBitmap()?.let { bitmap ->
                Image(bitmap = bitmap.asImageBitmap(), "Icon")
              }
            }
          }
          Column {
            // If available, display the headline asset.
            nativeAd.headline?.let {
              NativeAdHeadlineView {
                Text(text = it, style = MaterialTheme.typography.headlineLarge)
              }
            }
            // If available, display the star rating asset.
            nativeAd.starRating?.let {
              NativeAdStarRatingView {
                Text(text = "Rated $it", style = MaterialTheme.typography.labelMedium)
              }
            }
          }
        }

        // If available, display the body asset.
        nativeAd.body?.let { NativeAdBodyView { Text(text = it) } }
        // Display the media asset.
        NativeAdMediaView(Modifier.fillMaxWidth().height(500.dp).fillMaxHeight())

        Row(Modifier.align(Alignment.End).padding(5.dp)) {
          // If available, display the price asset.
          nativeAd.price?.let {
            NativeAdPriceView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
              Text(text = it)
            }
          }
          // If available, display the store asset.
          nativeAd.store?.let {
            NativeAdStoreView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
              Text(text = it)
            }
          }
          // If available, display the call to action asset.
          // Note: The Jetpack Compose button implements a click handler which overrides the native
          // ad click handler, causing issues. Use the NativeAdButton which does not implement a
          // click handler. To handle native ad clicks, use the NativeAd AdListener onAdClicked
          // callback.
          nativeAd.callToAction?.let { callToAction ->
            NativeAdCallToActionView(Modifier.padding(5.dp)) { NativeAdButton(text = callToAction) }
          }
        }
      }
    }
  }
}

個別工作如下:

  1. 加載版面配置

    Java

    LayoutInflater inflater = (LayoutInflater) parent.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    NativeAdView adView = (NativeAdView) inflater
            .inflate(R.layout.ad_layout_file, parent);
    

    Kotlin

    val inflater = parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)
            as LayoutInflater
    val adView = inflater.inflate(R.layout.ad_layout_file, parent) as NativeAdView
    

    這段程式碼會加載 XML 版面配置,其中包含用於顯示原生廣告的檢視區塊,然後找出 NativeAdView 的參照。請注意,如果片段或活動中已有 NativeAdView,您也可以重複使用,甚至可以動態建立例項,不必使用版面配置檔案。

  2. 填入並註冊資產檢視畫面

    這個範例程式碼會找出用於顯示廣告標題的檢視區塊、使用廣告物件提供的字串素材資源設定文字,並向 NativeAdView 物件註冊:

    Java

    TextView headlineView = adView.findViewById<TextView>(R.id.ad_headline);
    headlineView.setText(ad.getHeadline());
    adView.setHeadlineView(headlineView);
    

    Kotlin

    val headlineView = adView.findViewById<TextView>(R.id.ad_headline)
    headlineView.text = ad.headline
    adView.headlineView = headlineView
    

    針對應用程式顯示的原生廣告物件提供的每個素材資源,都應重複執行這個程序,找出檢視區塊、設定值,並向廣告檢視區塊類別註冊。

  3. 處理點擊

    請勿在原生廣告檢視區塊上方或內部的任何檢視區塊,導入任何自訂點擊事件處理常式。只要您正確填入並註冊素材資源檢視區塊,SDK 就會處理廣告檢視區塊素材資源的點擊次數,如上一節所述。

    如要監聽點擊事件,請導入 Google Mobile Ads SDK 點擊回呼:

    Java

    AdLoader adLoader = new AdLoader.Builder(context, "/21775744923/example/native")
        // ...
        .withAdListener(new AdListener() {
            @Override
            public void onAdFailedToLoad(LoadAdError adError) {
                // Handle the failure by logging.
            }
            @Override
            public void onAdClicked() {
                // Log the click event or other custom behavior.
            }
        })
        .build();
    

    Kotlin

    val adLoader = AdLoader.Builder(this, "/21775744923/example/native")
        // ...
        .withAdListener(object : AdListener() {
            override fun onAdFailedToLoad(adError: LoadAdError) {
                // Handle the failure.
            }
            override fun onAdClicked() {
                // Log the click event or other custom behavior.
            }
        })
        .build()
    
  4. 註冊 MediaView

    如要在原生廣告版面配置中加入主要圖片素材資源,須使用 MediaView 素材資源,而不是 ImageView 素材資源。

    MediaView 是一種特殊 View,用於顯示主要媒體素材資源 (影片或圖片)。

    MediaView 可在 XML 版面配置中定義,或動態建構。而且與任何其他素材資源檢視區塊一樣,應加入 NativeAdView 的檢視區塊階層。使用 MediaView 的應用程式必須向NativeAdView註冊:

    Java

     // Populate and register the media asset view.
     nativeAdView.setMediaView(nativeAdBinding.adMedia);
    

    Kotlin

     // Populate and register the media asset view.
     nativeAdView.mediaView = nativeAdBinding.adMedia
    

    ImageScaleType

    顯示圖片時,MediaView 類別會提供 ImageScaleType 屬性。如要變更圖片在 MediaView 中的縮放方式,請使用 MediaViewsetImageScaleType() 方法,設定對應的 ImageView.ScaleType

    Java

    mediaView.setImageScaleType(ImageView.ScaleType.CENTER_CROP);
    

    Kotlin

    mediaView.imageScaleType = ImageView.ScaleType.CENTER_CROP
    

    MediaContent

    MediaContent 類別會保留與原生廣告媒體內容相關的資料,並使用 MediaView 類別顯示。使用 MediaContent 執行個體設定 MediaView mediaContent 屬性時:

    • 系統會緩衝處理影片素材資源 (如有),並在 MediaView 中播放。可以檢查 hasVideoContent(),判斷是否有影片素材資源。

    • 如果廣告不含影片素材資源,系統會下載 mainImage 素材資源,並加到 MediaView 中。

    根據預設,mainImage 是第一個下載的圖片素材資源。如果使用 setReturnUrlsForImageAssets(true)mainImage 的值會是 null,且必須將 mainImage 屬性設為手動下載的圖片。請注意,只有在沒有可用的影片素材資源時,系統才會使用這張圖片。

  5. 註冊原生廣告物件

    最後一個步驟是向負責顯示原生廣告的檢視區塊註冊原生廣告物件。

    Java

    adView.setNativeAd(ad);
    

    Kotlin

    adView.setNativeAd(ad)
    

刪除廣告

顯示原生廣告後,請刪除廣告。以下範例會終止原生廣告:

Java

nativeAd.destroy();

Kotlin

nativeAd.destroy()

測試原生廣告程式碼

直接銷售廣告

如要測試直銷原生廣告,可以使用這個 Ad Manager 廣告單元 ID:

/21775744923/example/native

這個範例已設定為放送範例應用程式安裝廣告和內容廣告,以及包含下列素材資源的自訂原生廣告格式:

  • 廣告標題 (文字)
  • MainImage (圖片)
  • 說明文字 (文字)

自訂原生廣告格式的範本 ID 為 10063170

原生候補廣告

Ad Exchange 遞補功能僅適用於特定發布商。如要測試原生候補廣告的行為,請使用這個 Ad Manager 廣告單元:

/21775744923/example/native-backfill

這個範例會放送應用程式安裝廣告和內容廣告,並顯示 AdChoices 重疊廣告。

請務必先更新程式碼,參照實際的廣告單元和範本 ID,再正式發布。

GitHub 上的範例

完整導入原生廣告的範例:

Java Kotlin JetpackCompose

後續步驟

請參閱下列主題: