自訂原生廣告格式
除了系統定義的原生格式之外,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 UI 中,「廣告放送」下拉式選單的「原生」部分下方,即可找到用於識別自訂原生廣告格式的格式 ID:
每個自訂原生廣告格式 ID 都會顯示在名稱旁邊。按一下其中一個名稱,即可前往詳細資料畫面,顯示格式欄位的相關資訊:
您可以在這裡新增、編輯和移除個別欄位。記下各項資產的名稱。這個名稱是顯示自訂原生廣告格式時,用來取得各項素材資源資料的鍵。
顯示自訂原生廣告格式
自訂原生廣告格式與系統定義的格式不同,發布商有權自行定義組成廣告的素材資源清單。因此,顯示一種與系統定義格式的程序有以下幾個方面不同:
NativeCustomFormatAd
類別是用來處理您在 Ad Manager 中定義的任何自訂原生廣告格式,因此沒有為素材資源命名。而是提供getText
和getImage
等方法,這些方法會將欄位名稱做為參數。- 沒有專屬廣告檢視畫面類別 (例如
NativeAdView
) 可與NativeCustomFormatAd
搭配使用。您可以自行運用任何能滿足使用者體驗的版面配置元素。 - 由於沒有專屬的
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. ... }
顯示 AdChoices 圖示
為配合《數位服務法》(DSA) 發展行動,歐洲經濟區 (EEA) 上的預訂廣告需要 AdChoices 圖示和 Google 的「關於這則廣告」頁面連結。導入自訂原生廣告時,您必須負責顯示 AdChoices 圖示。顯示主要廣告素材資源時,建議您採取必要步驟來顯示及設定 AdChoices 圖示的點擊事件監聽器。
以下範例假設您已在檢視區塊階層中定義用來存放 AdChoices 標誌的 <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>
以下範例會顯示 AdChoices 圖示,並設定適當的點擊行為。
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 Mobile Ads SDK。
記錄曝光次數
如要記錄自訂格式廣告的曝光,請在對應的 NativeCustomFormatAd
上呼叫 recordImpression
方法:
myCustomFormatAd.recordImpression();
如果應用程式不小心針對同一廣告呼叫這個方法兩次,SDK 會自動避免為單一請求記錄重複曝光。
回報點擊次數
如要向 SDK 回報在素材資源檢視畫面上發生點擊,請在對應的 NativeCustomFormatAd
上呼叫 performClick
方法,並傳入所點選素材資源的名稱。舉例來說,如果您有一個名為「MainImage」的自訂格式素材資源,並想回報與該素材資源對應的 ImageView
點擊,程式碼會如下所示:
myCustomFormatAd.performClick("MainImage");
請注意,您不需要為每個與廣告相關的檢視畫面呼叫此方法。如果有一個名稱為「Caption」的欄位,旨在向使用者顯示,但使用者並未點選或輕觸,應用程式就不必針對該資產的檢視畫面呼叫 performClick
。
回應自訂點擊動作
當點擊自訂格式廣告時,SDK 會依序嘗試產生三種可能的回應:
- 從
AdLoader
叫用OnCustomClickListener
(如有提供)。 - 針對每個廣告的深層連結網址,嘗試找出內容解析器並啟動第一個解析的工具。
- 開啟瀏覽器,並前往廣告傳統的到達網頁網址。
forCustomFormatAd
方法接受 OnCustomClickListener
。如果您傳入事件監聽器物件,SDK 會改為叫用其 onCustomClick
方法,且不會採取進一步動作。不過,如果您將空值做為事件監聽器傳遞,SDK 就會改回使用於廣告註冊的深層連結和/或到達網頁網址。
自訂點擊事件監聽器可讓應用程式決定回應點擊的最佳動作,無論是更新 UI、啟動新活動,還是單純記錄點擊都沒問題。以下範例只會記錄點擊發生的位置:
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 能夠繼續控制對點擊的回應。它能自動對已針對廣告素材設定的第三方追蹤網址進行連線偵測 (例如),並在背景處理其他工作,完全不需要任何其他程式碼。