맞춤 네이티브 광고 형식
Ad Manager 게시자는 시스템 정의 네이티브 형식 외에 맞춤 애셋 목록을 생성하여 자체적인 네이티브 광고 형식을 만들 수 있습니다. 이를 맞춤 네이티브 광고 형식이라고 하며, 예약 광고와 함께 사용할 수 있습니다. 이를 통해 게시자는 임의의 구조화된 데이터를 앱에 전달할 수 있습니다. 이 광고는
NativeCustomFormatAd
객체를 통해 표현됩니다.
맞춤 네이티브 광고 형식 로드
이 가이드에서는 맞춤 네이티브 광고 형식을 로드하고 표시하는 방법을 설명합니다.
AdLoader 빌드
네이티브 광고와 마찬가지로 맞춤 네이티브 광고 형식은 AdLoader
클래스를 통해 로드됩니다.
자바
AdLoader adLoader = new AdLoader.Builder(context, "/21775744923/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, "/21775744923/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
를 여러 번 호출하여 광고 로더가 2개 이상의 노출 가능한
맞춤 네이티브 광고 형식의 광고를 게재하게 할 수 있습니다.
맞춤 네이티브 광고 형식 ID
맞춤 네이티브 광고 형식을 식별하는 데 사용되는 형식 ID는 Ad Manager UI의 게재 드롭다운에 있는 네이티브 섹션에서 확인할 수 있습니다.
맞춤 네이티브 광고 형식 ID가 각 이름 옆에 표시됩니다. 이름 중 하나를 클릭하면 형식 필드에 대한 정보를 표시하는 세부정보 화면이 나타납니다.
여기에서 개별 필드를 추가, 수정, 삭제할 수 있습니다. 각 애셋의 이름을 기록합니다. 이름은 맞춤 네이티브 광고 형식을 표시할 때 각 애셋의 데이터를 가져오는 데 사용되는 키입니다.
맞춤 네이티브 광고 형식 표시
맞춤 네이티브 광고 형식은 게시자가 광고를 구성하는 애셋 목록을 정의할 수 있다는 점에서 시스템 정의 광고 형식과 다릅니다. 따라서 맞춤 네이티브 광고 형식의 표시 방법은 시스템 정의 형식과 여러 면에서 다릅니다.
NativeCustomFormatAd
클래스는 Ad Manager에서 정의한 맞춤 네이티브 광고 형식을 처리하는 것이 목적이므로 애셋에 'getters'라는 이름을 지정하지 않습니다. 대신 필드의 이름을 매개변수로 사용하는getText
,getImage
등의 메서드를 제공합니다.NativeCustomFormatAd
와 함께 사용하는 전용 광고 조회 클래스(예:NativeAdView
)는 없습니다. 사용자 환경에 적합한 레이아웃을 자유롭게 사용할 수 있습니다.- 전용
ViewGroup
클래스가 없으므로 광고 애셋을 표시할 때 사용하는 뷰를 등록하지 않아도 됩니다. 이렇게 하면 광고를 표시할 때 코드 몇 행이 줄어들지만, 나중에 클릭을 처리할 때 약간의 작업을 추가로 해야 합니다.
다음은 NativeCustomFormatAd
를 표시하는 함수의 예입니다.
자바
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 아이콘을 렌더링하고 적절한 클릭 동작을 구성합니다.
자바
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()
를 호출하여 미디어 보기의 미디어 콘텐츠를 설정합니다.
광고에 동영상 콘텐츠가 없으면 동영상 없이 광고를
표시하는 대체 계획을 세우세요.
다음은 광고에 동영상 콘텐츠가 있는지 확인하고 동영상을 사용할 수 없는 경우 대신 이미지를 표시하는 방법의 예입니다.
자바
// 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에서 세 가지 가능한 응답이 다음 순서대로 시도됩니다.
AdLoader
에서OnCustomClickListener
호출(해당 객체가 제공된 경우)- 광고의 딥 링크 URL별로 콘텐츠 리졸버를 찾고 해결할 첫 번째 URL을 시작합니다.
- 브라우저를 열고 광고의 기존 도착 URL로 이동합니다.
forCustomFormatAd
메서드는 OnCustomClickListener
를 허용합니다. 리스너 객체를 전달하면
SDK가 onCustomClick
메서드를 호출하고
더 이상의 조치를 취하지 않습니다. 그러나 null 값을 리스너로 전달하면
SDK가 광고와 함께 등록된
딥 링크 또는 도착 URL로 돌아갑니다.
맞춤 클릭 리스너를 사용하면 UI 업데이트, 새 활동 시작 또는 단순한 클릭 로깅처럼 클릭에 대한 응답으로 취할 수 있는 최상의 조치를 앱에서 정할 수 있습니다. 다음은 클릭이 발생했음을 기록하는 예입니다.
자바
AdLoader adLoader = new AdLoader.Builder(context, "/21775744923/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, "/21775744923/example/native") .forCustomFormatAd("10063170", { ad -> // Display the ad. }, { ad, assetName -> Log.i("MyApp", "A custom click just happened for $assetName!") }).build()
처음에는 맞춤 클릭 리스너의 존재가 이상하게 보일 수 있습니다. 앱에서 SDK에 클릭이 발생했음을 알렸는데, SDK가 이를 앱에 다시 보고하는 이유는 쉽게 이해하기 힘듭니다.
이러한 정보 흐름은 몇 가지 이유에서 유용합니다. 가장 중요한 점은 SDK가 클릭에 대한 응답을 계속 통제할 수 있다는 것입니다. 예를 들어 광고 소재에 설정된 서드 파티 추적 URL을 자동으로 핑하고, 추가 코드 없이 다른 작업을 백그라운드에서 처리할 수 있습니다.