原生進階

選取平台: Android iOS

顯示 NativeAd

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

定義 NativeAdView 類別

定義 NativeAdView 類別。這是 ViewGroup 類別,也是 NativeAdView 類別的頂層容器。每個原生廣告檢視區塊都包含原生廣告素材資源 (例如 MediaViewTitle 檢視區塊元素),這類素材資源須為 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, "ca-app-pub-3940256099942544/2247696110")
    .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, "ca-app-pub-3940256099942544/2247696110")
    .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, "ca-app-pub-3940256099942544/2247696110")
        // ...
        .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, "ca-app-pub-3940256099942544/2247696110")
        // ...
        .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()

GitHub 上的範例

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

Java Kotlin JetpackCompose

後續步驟

請參閱下列主題: