네이티브 템플릿 광고
NAM SDK 8.5.0 버전부터는 네이티브 심플 광고 형식을 통해 복잡한 설정 및 추가 작업 없이 네이티브 광고를 적용할 수 있습니다. 이 가이드에서는 네이티브 심플 광고 형식으로 네이티브 광고를 로드 및 게재하는 방식인 네이티브 템플릿 옵션에 대해서 설명합니다.
네이티브 템플릿은 네이티브 광고를 좀 더 빠르게 구현하고 손쉽게 수정할 수 있게 고안된 것으로 네이티브 템플릿을 사용하면 처음 만드는 네이티브 광고도 수 분안에 구현할 수 있고, 많은 코드 없이도 디자인과 스타일을 빠르게 맞춤설정할 수 있습니다.
이 가이드를 효과적으로 적용하려면 네이티브 광고를 구현하는 것에 익숙해야 합니다.
시작하기 앞서
네이티브 심플 광고 가이드를 참고하여 네이티브 심플 광고를 로드 및 게재하는 방법을 알아보세요.
네이티브 템플릿 옵션
네이티브 심플 광고 형식을 통해 네이티브 광고를 로드 및 게재할 경우, GfpNativeSimpleAdOptions.Builder().setNativeTemplateOptions() 메서드를 사용하여 네이티브 템플릿 사용을 선언할 수 있습니다.
GfpNativeSimpleAdOptions 를 빌드하면서 GfpNativeTemplateOptions 를 설정하지 않으면, 해당 GfpNativeSimpleAdOptions 로 로드되는 네이티브 심플 광고는 네이티브 템플릿 광고를 사용하지 않는 것으로 간주됩니다. 이 경우 일반적인 네이티브 심플 광고 사용과 동일하게 네이티브 심플 광고 로드만 수행됩니다.
아래 예시는 GfpNativeTemplateOptions 을 기본값으로 적용하여 네이티브 템플릿을 적용하는 예시를 보여줍니다.
- Kotlin
- Java
val nativeTemplateOptions = GfpNativeTemplateOptions.Builder().build()
val nativeSimpleAdOptions = GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
.build()
val adLoader = GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions) { nativeSimpleAd ->
...
}
.build()
GfpNativeTemplateOptions nativeTemplateOptions = new GfpNativeTemplateOptions.Builder().build();
GfpNativeSimpleAdOptions nativeSimpleAdOptions = new GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
.build();
GfpAdLoader adLoader = new GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions, nativeSimpleAd -> {
...
})
.build();
커스텀 네이티브 템플릿
위 예시와 같이 기본 값의 GfpNativeTemplateOptions 을 적용할 경우, SDK 에 내장된 기본 템플릿을 통해 아래 이미지와 같이 네이티브 광고를 렌더링하게 됩니다.

네이티브 템플릿을 사용하면서 네이티브 광고의 레이아웃을 처음부터 직접 디자인하고 싶다면 아래 예시를 따라주시면 됩니다.
1. 네이티브 템플릿 레이아웃 정의
네이티브 광고의 레이아웃을 아래 예시와 같이 정의합니다.
네이티브 템플릿을 위한 광고 레이아웃을 정의할 때, 정의된 최상위 ViewGroup 은 SDK에 의해 자동으로 GfpNativeAdView의 자식 뷰로 추가됩니다. 따라서 기존의 네이티브 광고 레이아웃과 달리, 광고 에셋을 GfpNativeAdView 내부에 직접 포함할 필요가 없습니다.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="ContentDescription,RtlHardcoded,SpUsage,RtlSymmetry"
tools:parentTag="com.naver.example.CustomNativeTemplateAdView">
<LinearLayout
android:id="@+id/ad_top_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp">
<ImageView
android:id="@+id/ad_icon"
android:layout_width="35dp"
android:layout_height="35dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:id="@+id/ad_advertiser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textColor="@android:color/black"
android:textSize="15dp" />
<TextView
android:id="@+id/ad_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="AD"
android:textColor="@android:color/darker_gray"
android:textSize="12dp" />
</LinearLayout>
<com.naver.gfpsdk.GfpAdChoicesView
android:id="@+id/ad_choices"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<com.naver.gfpsdk.GfpMediaView
android:id="@+id/ad_media"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ad_top_container"
android:gravity="center" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ad_media"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:id="@+id/ad_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:ellipsize="end"
android:gravity="center_vertical"
android:lines="2"
android:textColor="@android:color/black"
android:textSize="12dp" />
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="#4286F4"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:textColor="@android:color/white"
android:textSize="12sp" />
</LinearLayout>
</merge>
2. 네이티브 템플릿 뷰 정의
앞서 정의한 레이아웃을 사용하여 커스텀한 네이티브 템플릿 뷰를 정의합니다.
- Kotlin
- Java
package com.naver.example
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import com.naver.example.R
import com.naver.gfpsdk.GfpAdChoicesView
import com.naver.gfpsdk.GfpMediaView
import com.naver.gfpsdk.GfpNativeAdView
import com.naver.gfpsdk.mediation.NativeAssetProvider
import com.naver.gfpsdk.mediation.NativeTemplateAdView
class CustomNativeTemplateAdView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr), NativeTemplateAdView {
class Factory : NativeTemplateAdView.Factory {
override fun create(context: Context): NativeTemplateAdView {
return CustomNativeTemplateAdView(context)
}
}
private val iconView: ImageView
private val advertiserView: TextView
private val bodyView: TextView
private val callToActionView: Button
private val adChoicesView: GfpAdChoicesView
private val mediaView: GfpMediaView
init {
LayoutInflater.from(context).inflate(R.layout.custom_native_template_ad_view, this)
iconView = findViewById(R.id.ad_icon)
advertiserView = findViewById(R.id.ad_advertiser)
adChoicesView = findViewById(R.id.ad_choices)
mediaView = findViewById(R.id.ad_media)
bodyView = findViewById(R.id.ad_body)
callToActionView = findViewById(R.id.ad_call_to_action)
}
override fun bind(
nativeAdView: GfpNativeAdView,
nativeAssetProvider: NativeAssetProvider,
renderingOptions: NativeTemplateAdView.RenderingOptions
) {
val icon = nativeAssetProvider.icon
if (icon != null) {
iconView.visibility = View.VISIBLE
iconView.setImageDrawable(icon.drawable)
nativeAdView.iconView = iconView
} else {
iconView.visibility = View.GONE
}
val advertiser = nativeAssetProvider.advertiserName
if (advertiser != null) {
advertiserView.visibility = View.VISIBLE
advertiserView.text = advertiser
nativeAdView.advertiserView = advertiserView
} else {
advertiserView.visibility = View.GONE
}
val body = nativeAssetProvider.body
if (body != null) {
bodyView.visibility = View.VISIBLE
bodyView.text = body
nativeAdView.bodyView = bodyView
} else {
bodyView.visibility = View.GONE
}
val callToAction = nativeAssetProvider.callToAction
if (callToAction != null) {
callToActionView.visibility = View.VISIBLE
callToActionView.text = callToAction
nativeAdView.callToActionView = callToActionView
} else {
callToActionView.visibility = View.GONE
}
nativeAdView.adChoicesView = adChoicesView
nativeAdView.mediaView = mediaView
}
override fun onUserShowInterestChanged(
showInterest: Boolean,
nativeAssetProvider: NativeAssetProvider,
renderingOptions: NativeTemplateAdView.RenderingOptions
) {
// do nothing
}
}
package com.naver.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.naver.gfpsdk.GfpAdChoicesView;
import com.naver.gfpsdk.GfpMediaView;
import com.naver.gfpsdk.GfpNativeAdView;
import com.naver.gfpsdk.mediation.NativeAssetProvider;
import com.naver.gfpsdk.mediation.NativeTemplateAdView;
public class CustomNativeTemplateAdView extends RelativeLayout implements NativeTemplateAdView {
public static class Factory implements NativeTemplateAdView.Factory {
@Override
public NativeTemplateAdView create(Context context) {
return new CustomNativeTemplateAdView(context);
}
}
private ImageView iconView;
private TextView advertiserView;
private TextView bodyView;
private Button callToActionView;
private GfpAdChoicesView adChoicesView;
private GfpMediaView mediaView;
public CustomNativeTemplateAdView(Context context) {
this(context, null);
}
public CustomNativeTemplateAdView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomNativeTemplateAdView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater.from(context).inflate(R.layout.custom_native_template_ad_view, this);
iconView = findViewById(R.id.ad_icon);
advertiserView = findViewById(R.id.ad_advertiser);
adChoicesView = findViewById(R.id.ad_choices);
mediaView = findViewById(R.id.ad_media);
bodyView = findViewById(R.id.ad_body);
callToActionView = findViewById(R.id.ad_call_to_action);
}
@Override
public void bind(
GfpNativeAdView nativeAdView,
NativeAssetProvider nativeAssetProvider,
NativeTemplateAdView.RenderingOptions renderingOptions
) {
NativeAssetProvider.Icon icon = nativeAssetProvider.getIcon();
if (icon != null) {
iconView.setVisibility(View.VISIBLE);
iconView.setImageDrawable(icon.getDrawable());
nativeAdView.setIconView(iconView);
} else {
iconView.setVisibility(View.GONE);
}
String advertiser = nativeAssetProvider.getAdvertiserName();
if (advertiser != null) {
advertiserView.setVisibility(View.VISIBLE);
advertiserView.setText(advertiser);
nativeAdView.setAdvertiserView(advertiserView);
} else {
advertiserView.setVisibility(View.GONE);
}
String body = nativeAssetProvider.getBody();
if (body != null) {
bodyView.setVisibility(View.VISIBLE);
bodyView.setText(body);
nativeAdView.setBodyView(bodyView);
} else {
bodyView.setVisibility(View.GONE);
}
String callToAction = nativeAssetProvider.getCallToAction();
if (callToAction != null) {
callToActionView.setVisibility(View.VISIBLE);
callToActionView.setText(callToAction);
nativeAdView.setCallToActionView(callToActionView);
} else {
callToActionView.setVisibility(View.GONE);
}
nativeAdView.setAdChoicesView(adChoicesView);
nativeAdView.setMediaView(mediaView);
}
@Override
public void onUserShowInterestChanged(
boolean showInterest,
NativeAssetProvider nativeAssetProvider,
NativeTemplateAdView.RenderingOptions renderingOptions
) {
// do nothing
}
}
각 작업은 다음과 같습니다:
1. NativeTemplateAdView 를 상속하는 커스텀 뷰를 생성
커스텀 템플릿용 뷰를 생성할 때는 아래 예시와 같이 반드시 NativeTemplateAdView 를 implement 해야 합니다. 또한, 앞서 생성한 레이아웃을 사용하여 뷰를 생성합니다.
- Kotlin
- Java
class CustomNativeTemplateAdView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr),
NativeTemplateAdView {
...
private val iconView: ImageView
private val advertiserView: TextView
private val bodyView: TextView
private val callToActionView: Button
private val adChoicesView: GfpAdChoicesView
private val mediaView: GfpMediaView
init {
LayoutInflater.from(context).inflate(R.layout.custom_native_template_ad_view, this)
iconView = findViewById(R.id.ad_icon)
advertiserView = findViewById(R.id.ad_advertiser)
adChoicesView = findViewById(R.id.ad_choices)
mediaView = findViewById(R.id.ad_media)
bodyView = findViewById(R.id.ad_body)
callToActionView = findViewById(R.id.ad_call_to_action)
}
}
public class CustomNativeTemplateAdView extends RelativeLayout implements NativeTemplateAdView {
...
public CustomNativeTemplateAdView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater.from(context).inflate(R.layout.custom_native_template_ad_view, this);
iconView = findViewById(R.id.ad_icon);
advertiserView = findViewById(R.id.ad_advertiser);
adChoicesView = findViewById(R.id.ad_choices);
mediaView = findViewById(R.id.ad_media);
bodyView = findViewById(R.id.ad_body);
callToActionView = findViewById(R.id.ad_call_to_action);
}
}
2. bind() 메서드에서 광고 에셋을 각 View에 매핑
NativeTemplateAdView 의 bind() 메서드를 오버라이드하여 NativeAssetProvider 가 제공하는 광고 에셋을 각 View에 바인딩합니다.
- GfpAdChoicesView 와 GfpMediaView: 별도 설정 없이 GfpNativeAdView 에 등록만 하면 됩니다.
- 기타 광고 에셋: 이미지나 텍스트를 먼저 설정한 후 GfpNativeAdView 에 등록해야 합니다.
- Kotlin
- Java
class CustomNativeTemplateAdView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr),
NativeTemplateAdView {
...
override fun bind(
nativeAdView: GfpNativeAdView,
nativeAssetProvider: NativeAssetProvider,
renderingOptions: NativeTemplateAdView.RenderingOptions
) {
val icon = nativeAssetProvider.icon
if (icon != null) {
iconView.visibility = View.VISIBLE
iconView.setImageDrawable(icon.drawable)
nativeAdView.iconView = iconView
} else {
iconView.visibility = View.GONE
}
val advertiser = nativeAssetProvider.advertiserName
if (advertiser != null) {
advertiserView.visibility = View.VISIBLE
advertiserView.text = advertiser
nativeAdView.advertiserView = advertiserView
} else {
advertiserView.visibility = View.GONE
}
...
nativeAdView.adChoicesView = adChoicesView
nativeAdView.mediaView = mediaView
}
}
public class CustomNativeTemplateAdView extends RelativeLayout implements NativeTemplateAdView {
...
@Override
public void bind(
GfpNativeAdView nativeAdView,
NativeAssetProvider nativeAssetProvider,
NativeTemplateAdView.RenderingOptions renderingOptions
) {
NativeAssetProvider.Icon icon = nativeAssetProvider.getIcon();
if (icon != null) {
iconView.setVisibility(View.VISIBLE);
iconView.setImageDrawable(icon.getDrawable());
nativeAdView.setIconView(iconView);
} else {
iconView.setVisibility(View.GONE);
}
String advertiser = nativeAssetProvider.getAdvertiserName();
if (advertiser != null) {
advertiserView.setVisibility(View.VISIBLE);
advertiserView.setText(advertiser);
nativeAdView.setAdvertiserView(advertiserView);
} else {
advertiserView.setVisibility(View.GONE);
}
...
nativeAdView.setAdChoicesView(adChoicesView);
nativeAdView.setMediaView(mediaView);
}
}
3. Factory 클래스 생성
커스텀 네이티브 템플릿 뷰를 생성하려면 반드시 NativeTemplateAdView.Factory 를 상속하는 Factory 클래스가 필요합니다. 생성된 Factory 객체는 GfpNativeTemplateOptions 에 등록하여 커스텀 네이티브 템플릿 뷰로 사용할 수 있습니다.
- Kotlin
- Java
class CustomNativeTemplateAdView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr),
NativeTemplateAdView {
...
class Factory : NativeTemplateAdView.Factory {
override fun create(context: Context): NativeTemplateAdView {
return CustomNativeTemplateAdView(context)
}
}
}
public class CustomNativeTemplateAdView extends RelativeLayout implements NativeTemplateAdView {
...
public static class Factory implements NativeTemplateAdView.Factory {
@Override
public NativeTemplateAdView create(Context context) {
return new CustomNativeTemplateAdView(context);
}
}
}
4. (Optional) onUserShowInterestChanged() 메서드
NativeTemplateAdView 의 onUserShowInterestChanged() 메서드는 사용자의 광고 관심도 변화 시점에 호출됩니다.
호출 시점:
- 관심 시작: 광고 영역의 50% 이상이 1초 동안 노출될 때, showInterest 값이 true 로 전달됨.
- 관심 종료: 광고 영역이 더 이상 노출되지 않을 때, showInterest 값이 false 로 전달됨.
활용 예시: 사용자가 관심을 보이는 시점에 Call to Action 버튼의 색상을 변경하여 광고 주목도를 높이는 등의 동적 UI 처리가 가능합니다.
- Kotlin
- Java
class CustomNativeTemplateAdView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr),
NativeTemplateAdView {
...
override fun onUserShowInterestChanged(
showInterest: Boolean,
nativeAssetProvider: NativeAssetProvider,
renderingOptions: NativeTemplateAdView.RenderingOptions
) {
if (showInterest) {
callToActionView.setBackgroundColor(highlightedBgColor)
} else {
callToActionView.setBackgroundColor(defaultBgColor)
}
}
}
public class CustomNativeTemplateAdView extends RelativeLayout implements NativeTemplateAdView {
...
@Override
public void onUserShowInterestChanged(
boolean showInterest,
NativeAssetProvider nativeAssetProvider,
NativeTemplateAdView.RenderingOptions renderingOptions
) {
if (showInterest) {
callToActionView.setBackgroundColor(highlightedBgColor);
} else {
callToActionView.setBackgroundColor(defaultBgColor);
}
}
}
3. 네이티브 템플릿 등록
커스텀 네이티브 템플릿 뷰를 사용하려면 GfpNativeTemplateOptions 에 등록해야 합니다.
다음과 같이 Factory 를 등록합니다:
- addNativeTemplateAdViewFactory() 메서드 사용
- GfpNativeTemplateOptions.DEFAULT_VISUAL_KEY 를 비주얼 키로 설정
- 앞서 생성한 커스텀 네이티브 템플릿 뷰 Factory 객체 전달
- Kotlin
- Java
val nativeTemplateOptions = GfpNativeTemplateOptions.Builder()
.addNativeTemplateAdViewFactory(
GfpNativeTemplateOptions.DEFAULT_VISUAL_KEY, CustomNativeTemplateAdView.Factory()
)
.build()
val nativeSimpleAdOptions = GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
...
.build()
val adLoader = GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions) { nativeSimpleAd ->
...
}
.build()
GfpNativeTemplateOptions nativeTemplateOptions = new GfpNativeTemplateOptions.Builder()
.addNativeTemplateAdViewFactory(
GfpNativeTemplateOptions.DEFAULT_VISUAL_KEY, new CustomNativeTemplateAdView.Factory()
)
.build();
GfpNativeSimpleAdOptions nativeSimpleAdOptions = new GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
...
.build();
GfpAdLoader adLoader = new GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions, nativeSimpleAd -> {
...
})
.build();
4. 광고 요청 및 렌더링
위 과정까지 마쳤다면, 이후의 광고 요청 및 렌더링 그리고 광고 리소스 해제 같은 처리는 기존 네이티브 심플 광고와 사용이 동일합니다. 단, 네이티브 템플릿을 사용할 경우는 네이티브 광고가 네이티브 심플 광고 형식을 통해 처리되므로 GfpAdLoader 를 빌드하는 과정에서 네이티브 광고 로드시 필요한 아래와 같은 처리가 포함되지 말아야 합니다.
- Kotlin
- Java
val nativeTemplateOptions = GfpNativeTemplateOptions.Builder()
.addNativeTemplateAdViewFactory(
GfpNativeTemplateOptions.DEFAULT_VISUAL_KEY, CustomNativeTemplateAdView.Factory()
)
.build()
val nativeSimpleAdOptions = GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
...
.build()
val adLoader = GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions) { nativeSimpleAd ->
...
}
.withNativeAd { nativeAd ->
// 네이티브 템플릿 사용시 withNativeAd() 는 포함되지 말아야 합니다.
}
.build()
GfpNativeTemplateOptions nativeTemplateOptions = new GfpNativeTemplateOptions.Builder()
.addNativeTemplateAdViewFactory(
GfpNativeTemplateOptions.DEFAULT_VISUAL_KEY, new CustomNativeTemplateAdView.Factory()
)
.build();
GfpNativeSimpleAdOptions nativeSimpleAdOptions = new GfpNativeSimpleAdOptions.Builder()
.setNativeTemplateOptions(nativeTemplateOptions)
...
.build();
GfpAdLoader adLoader = new GfpAdLoader.Builder(this, adParam)
...
.withNativeSimpleAd(nativeSimpleAdOptions, nativeSimpleAd -> {
...
})
.withNativeAd( nativeAd ->
// 네이티브 템플릿 사용시 withNativeAd() 는 포함되지 말아야 합니다.
)
.build();