네이티브(Native)
네이티브를 추가하고 설정하고 SDK 인터페이스를 사용해 부가 기능을 구현하는 방법을 알아보세요.
주요 특징
Buzzvil SDK가 제공하는 네이티브는 앱 화면과 자연스럽게 임베드되는 앱 맞춤형 광고를 게재할 수 있는 인벤토리입니다. 또한 유저가 광고에 참여한 후 자동으로 다음 광고를 노출하여, 하나의 네이티브 지면에서 끊임없이 광고를 송출하여 앱 수익화를 가속할 수 있도록 진화된 기능입니다. 유저가 더 많은 광고에 참여할 수 있도록 유도하는 다이나믹한 기능들도 제공합니다.
연동
앱에 네이티브를 연동하는 방법을 확인해 보세요.
1 단계. 준비하기
- 시작하기 적용 완료
- 네이티브 지면에 사용할 Unit ID (이하
YOUR_NATIVE_UNIT_ID
)
2 단계. 광고 레이아웃 구성하기
네이티브 광고 레이아웃을 구성하는 요소와 UI에 대해서는 아래의 그림과 표를 참고하세요.
구성 요소 | 설명 |
---|---|
광고 제목 (필수) | 광고의 제목입니다. 최대 10자까지 권장하며, 필요에 따라 글자 수에 상관 없이 일정 부분은 생략 부호도 대체할 수 있습니다. |
광고 소재 (필수) |
|
광고 설명 (필수) | 광고에 대한 상세 설명입니다. 최대 40자까지 권장하며, 필요에 따라 글자 수에 상관 없이 일정 부분은 생략 부호로 대체할 수 있습니다. |
광고주 아이콘 (필수) |
|
CTA 버튼 (필수) |
|
광고 알림 문구 (권장) | 광고임을 명시하는 문구입니다. (예: 광고 , ad , 스폰서 , Sponsored ) |
네이티브 광고 레이아웃은 액티비티 또는 프래그먼트 레이아웃에 아래 구조에 맞게 구성해야 합니다. 네이티브 광고 지면을 구현하려면 NativeAd2View
의 규격에 맞는 레이아웃(your_native_ad.xml
)을 구현하세요.
다음은 NativeAd2View
의 레이아웃 예시입니다.
<com.buzzvil.buzzad.benefit.nativead2.api.NativeAd2View
android:id="@+id/nativeAd2View">
<!-- MediaView와 CtaView는 NativeAd2View의 하위 컴포넌트로 구현해야합니다.-->
<com.buzzvil.buzzad.benefit.presentation.media.MediaView
android:id="@+id/mediaView"
...생략... />
<TextView
android:id="@+id/textTitle"
...생략... />
<TextView
android:id="@+id/textDescription"
...생략... />
<ImageView
android:id="@+id/imageIcon"
...생략... />
<com.buzzvil.buzzad.benefit.presentation.media.DefaultCtaView
android:id="@+id/ctaView"
...생략... />
</com.buzzvil.buzzad.benefit.nativead2.api.NativeAd2View>
✏️ 참고
액티비티 또는 프래그먼트 이외의 다른 방식으로 네이티브 지면을 구현하려면 버즈빌 담당자(help@buzzvil.com)에게 문의하세요.
3 단계. 광고 보여주기
광고 레이아웃에 광고를 보여주기 위해 예시 코드를 참고하여 다음의 절차를 따르세요.
NativeAd2ViewBinder.Builder
를 사용하여nativeAd2View
,MediaView
등 광고를 보여주기 위해 필요한 뷰를 모두 설정하고build()
를 호출하여NativeAd2ViewBinder
객체를 생성하세요.- (Optional) 광고 요청 상태에 따른 UI를 구현하려면 NativeAd2StateChangedListener를 등록하세요.
- 생성된
NativeAd2ViewBinder
객체의bind()
를 호출하면 자동으로 광고를 할당받고 레이아웃에 표시합니다.- 광고 할당에 실패하면 레이아웃에 광고가 표시되지 않습니다. 실패시 동작을 정의하려면 NativeAd2StateChangedListener를 사용하세요.
- 유저가 광고 참여를 완료(CTA View가
참여 완료
로 변경)하고 네이티브 지면으로 돌아오면 자동으로 다음 광고로 갱신됩니다.
✏️ 참고
- 참여 완료 상태가 존재하지 않는 논리워드 콘텐츠, 이미 참여 완료된 광고는 클릭 후 랜딩 페이지에서 네이티브 지면으로 돌아올 때 다음 광고로 갱신됩니다.
- 유저가 광고에 참여 중인 상태(CTA View가 '참여 확인 중'인 경우)에는 다음 광고로 갱신되지 않습니다.
✏️ 참고
자동 광고 갱신을 비활성화하려면 버즈빌 담당자(help@buzzvil.com)에게 문의하세요.
final NativeAd2View nativeAd2View = findViewById(R.id.nativeAd2View);
final MediaView mediaView = findViewById(R.id.mediaView);
final TextView titleTextView = findViewById(R.id.textTitle);
final TextView descriptionTextView = findViewById(R.id.textDescription);
final ImageView iconImageView = findViewById(R.id.imageIcon);
final DefaultCtaView ctaView = findViewById(R.id.ctaView);
// 광고 레이아웃을 설정합니다.
NativeAd2ViewBinder binder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.titleTextView(titleTextView)
.descriptionTextView(descriptionTextView)
.iconImageView(iconImageView)
.ctaView(ctaView)
.build("YOUR_NATIVE_UNIT_ID");
// (Optional) 광고 요청 상태에 따른 UI를 구현합니다.
binder.addNativeAd2StateChangedListener(new NativeAd2StateChangedListener() {
@Override
public void onRequested() {
// 광고 할당을 요청한 상태입니다.
// 이후에는 onNext(), onComplete(), onError() 중 하나가 호출됩니다.
// 광고 자동 갱신을 시도할 때마다 반복적으로 호출됩니다.
// 로딩 화면 등을 구현할 수 있습니다.
}
@Override
public void onNext(NativeAd2 nativeAd2) {
// 광고 할당에 성공하면 호출됩니다.
// 이후에 광고 갱신 시 onRequested()가 다시 호출됩니다.
// 광고 자동 갱신을 성공할 때마다 반복적으로 호출됩니다.
// 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
}
@Override
public void onComplete() {
// 더 이상 갱신할 수 있는 광고가 없을 때 호출됩니다.
// 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
}
@Override
public void onError(@NonNull AdError adError) {
// 최초 광고 할당에 실패하면 호출됩니다.
// 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
}
});
// 광고 할당 및 표시를 자동으로 수행합니다.
binder.bind();
✏️ 참고
- 최초 광고 할당 요청에 실패했을 때는
onError()
가 호출되고 광고가 노출되지 않습니다. 광고 미할당 시 발생하는AdError
오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.- 광고 갱신 시 할당 받을 수 있는 광고가 없을 때는
onComplete()
가 호출되고 이전 광고가 유지됩니다.
4 단계. 네이티브 광고 지면에 베네핏허브로 이동하는 레이아웃 추가하기
NativeAdView
레이아웃에 유저가 클릭하면 바로 베네핏허브로 이동하는 UI(NativeToFeedLayout
)를 추가하세요.
❗️ 주의
NativeToFeedLayout
에<Button />
은 사용할 수 없습니다.
✏️ 참고
NativeToFeedLayout
은 자유롭게 구성할 수 있습니다. 아래 그림과 같이 베네핏허브 이동 안내 텍스트와 화살표 아이콘을 적용하는 것을 추천합니다.- 베네핏허브 이동 안내 텍스트에 베네핏허브에 진입만 해도 받을 수 있는 포인트를 표시할 수도 있습니다. 자세한 내용은 베이스 리워드 금액 표시하기 토픽을 참고하세요.
네이티브 광고 지면에서 베네핏허브 지면으로 이동하는 레이아웃을 추가하려면 다음의 절차를 따르세요.
NativeAdView
레이아웃에NativeToFeedLayout
를 추가하세요.<com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView>
<com.buzzvil.buzzad.benefit.presentation.feed.navigation.NativeToFeedLayout
android:id="@+id/your_native_to_feed_layout">
<!-- 레이아웃의 컴포넌트 정의는 생략했습니다 -->
<TextView />
<ImageView />
</com.buzzvil.buzzad.benefit.presentation.feed.navigation.NativeToFeedLayout>
</com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView>NativeToFeedLayout
에 Native Unit ID를 설정하세요.// Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
NativeToFeedLayout nativeToFeedLayout = findViewById(R.id.your_native_to_feed_layout);
nativeToFeedLayout.setNativeUnitId(YOUR_NATIVE_UNIT_ID);
}
베이스 리워드 금액 표시하기
NativeToFeedLayout
에 유저가 베네핏허브에 진입하기만 해도 받을 수 있는 베이스 리워드(BaseReward
) 금액 표시해 유저의 클릭율을 높일 수 있습니다.
다음은 NativeToFeedLayout
에 기본 적립 포인트를 표시하는 예시입니다.
BaseRewardManager baseRewardManager = BuzzAdBenefit.getBaseRewardManager();
@Override
public void onResume() {
super.onResume();
updateNavigationTextView();
}
private void updateNavigationTextView() {
baseRewardManager.getAvailableFeedBaseReward(
YOUR_FEED_UNIT_ID,
reward -> {
if (reward < 1) {
navigationTextView.setText("더 많은 참여 기회 보기");
} else {
navigationTextView.setText(String.format(Locale.ROOT, "%d P 무료 적립하고 더 많은 참여 기회 보기", reward));
}
}
);
}
❗️ 주의
유저에게 지급하는 포인트 금액의 정확하게 표시하기 위해Activity
의onResume()
시점에 기본 적립 포인트를 포함한 유도 문구를 업데이트해야 합니다.
5 단계. 기본 연동 테스트하기
모든 기본 연동 단계를 완료한 후 광고가 정상적으로 할당되고 표시되는지 확인하세요. 그리고 NativeToFeedLayout
(네이티브 광고 지면에 베네핏허브로 이동하는 레이아웃)이 제대로 동작하여 클릭하면 베네핏허브로 이동하는지 확인하세요.
추가 구현
네이티브에 추가 기능을 구현하는 방법을 안내합니다.
네이티브 오버레이 추가하기
유저가 네이티브 광고에 참여한 후 앱으로 되돌아오면 참여 완료 광고 위에 베네핏허브 진입을 유도하는 텍스트와 아이콘이 오버레이되도록 설정할 수 있습니다. 텍스트와 아이콘으로 구성되는 이 UI는 최소 1분의 간격을 두고 표시됩니다. 예를 들어, 네이티브 오버레이가 표시된 이후에 1분 동안은 광고 참여 후에 네이티브 오버레이가 표시되지 않습니다.
네이티브 오버레이를 사용하려면 네이티브 지면의 기본 설정 시 enableNativeToFeedOverlay()
를 추가하세요.
✏️ 참고
네이티브 지면의 기본 설정에 대한 자세한 내용은 네이티브 지면 연동 토픽을 참고하세요.
viewBinder.bind(nativeAd);
nativeAdView.enableNativeToFeedOverlay(); // Native Overlay 기능 활성화
onResume
에서 Native 광고 할당 요청을 수행하면 앱으로 되돌아온 후에 광고가 재할당되어 네이티브 오버레이가 표시되지 않습니다. 네이티브 광고 할당에 대한 자세한 내용은 3 단계. 광고 보여주기 토픽을 참고하세요.
동영상 광고 리스너 등록하기
동영상 광고에서 발생하는 콜백 이벤트를 수신할 수 있습니다.
다음은 MediaView
에 동영상 광고 이벤트 리스너를 등록하는 예시입니다.
mediaView.setVideoEventListener(new com.buzzvil.buzzad.benefit.presentation.video.VideoEventListener() {
@Override
public void onVideoStarted() {
}
@Override
public void onError(@NonNull VideoErrorStatus videoErrorStatus, @Nullable String errorMessage) {
if (errorMessage != null) {
Toast.makeText(mediaView.getContext(), errorMessage, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onResume() {
}
@Override
public void onPause() {
}
@Override
public void onReplay() {
}
@Override
public void onVideoEnded() {
// 동영상 재생 완료 시 필요한 처리
}
@Override
public void onLanding() {
// 동영상 광고 랜딩 시 필요한 처리
}
});
광고 이벤트 리스너 등록하기
✏️ 참고
광고 참여 상태에 따라 CTA View를 변경하기 위해 이벤트 리스너를 사용했다면, 더 이상 사용할 필요 없습니다.리워드 적립 결과(
RewardResult
) 종류는 리워드 적립 결과(RewardResult
) 종류를 참고하세요.
NativeAd2EventListener
를 통해 광고 콜백 이벤트를 수신할 수 있습니다. 광고 콜백 이벤트를 수신하려면 NativeAd2ViewBinder.bind()
함수를 호출하기 전에 리스너를 등록해야 합니다.
다음은 NativeAd2ViewBinder
에 광고 이벤트 리스너를 등록하는 예시입니다.
NativeAd2ViewBinder binder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.titleTextView(titleTextView)
.descriptionTextView(descriptionTextView)
.iconImageView(iconImageView)
.ctaView(ctaView)
.build("YOUR_NATIVE_UNIT_ID");
binder.addNativeAd2StateChangedListener(new NativeAd2StateChangedListener() {
@Override
public void onRequested() {
}
@Override
public void onNext(NativeAd2 nativeAd2) {
}
// ...중략
});
// 광고 이벤트 리스너를 등록합니다.
binder.addNativeAd2EventListener(new NativeAd2EventListener() {
@Override
public void onImpressed(@NonNull NativeAd2 nativeAd2) {
// Native 광고가 유저에게 노출되었을 때 호출됩니다.
}
@Override
public void onClicked(@NonNull NativeAd2 nativeAd2) {
// 유저가 Native 광고를 클릭했을 때 호출됩니다.
}
@Override
public void onRewardRequested(@NonNull NativeAd2 nativeAd2) {
// 리워드 적립을 요청했을 때 호출됩니다.
}
@Override
public void onRewarded(@NonNull NativeAd2 nativeAd2, @NonNull RewardResult rewardResult) {
// 리워드가 적립되었을 때 호출됩니다.
}
@Override
public void onParticipated(@NonNull NativeAd2 nativeAd2) {
// 유저가 광고 참여를 완료하였을 때 호출됩니다.
}
});
binder.bind();
리워드 적립 결과(RewardResult
) 종류
RewardResult | 결과 | 설명 |
---|---|---|
SUCCESS | 적립성공 | 적립에 성공했습니다. |
ALREADY_PARTICIPATED | 적립 실패 | 이미 적립된 광고입니다. |
MISSING_REWARD | 적립 실패 | 리워드가 없는 광고입니다. |
TOO_SHORT_TO_PARTICIPATE | 적립 실패 | 광고 랜딩 페이지에서 너무 빨리 돌아왔습니다. |
NETWORK_TIMEOUT | 적립 실패 | 네트워크 타임 아웃이 발생했습니다. |
NETWORK_TIMEOUT_IN_POWER_SAVE_MODE | 적립 실패 | 단말의 절전모드 로 인해 네트워크 타임아웃이 발생했습니다. |
BROWSER_NOT_LAUNCHED | 적립 실패 | 광고 랜딩 페이지를 보기위한 브라우저가 실행되지 않았습니다. |
REQUEST_ERROR | 적립 실패 | 잘못된 요청입니다. |
UNKNOWN_NETWORK_ERROR | 적립 실패 | 알 수 없는 네트워크 오류가 발생했습니다. |
UNKNOWN_SERVER_ERROR | 적립 실패 | 알 수 없는 서버 오류가 발생했습니다. |
UNKNOWN_CLIENT_ERROR | 적립 실패 | 알 수 없는 클라이언트 오류가 발생했습니다. |
UNKNOWN_ERROR | 적립 실패 | 알 수 없는 오류가 발생했습니다. |
- 유저가 단말의
절전모드
를 활성화하면 백그라운드 실행 제한으로 인해 클릭형 광고(CPC, CPM)의 적립이 높은 확률로 실패합니다.RewardResult.NETWORK_TIMEOUT_IN_POWER_SAVE_MODE
를 활용하면절전모드
를 활성화 한 유저에게 적립 실패 사유를 안내를 할 수 있습니다.
캐러셀 구현하기
캐러셀(Carousel)은 여러 개의 광고를 가로로 스크롤 하여 유저에게 노출할 수 있는 UI입니다. Buzzvil SDK를 사용하여 네이티브 지면에 캐러셀을 생성하고 필수 기능을 구현해 캐러셀을 구현할 수 있습니다. 또한 선택에 따라 구현할 수 있는 부가 기능들을 통해 유저 경험을 최적화할 수 있습니다.
✏️ 참고
전체 코드를 확인하려면 샘플 코드를 참고하세요.
캐러셀의 기본 기능 구현하기
1 단계. 광고 할당 받기
네이티브에서 여러 개의 광고를 할당 받기 위해서는 광고 중복 할당을 제어하는 클래스인 NativeAd2Pool
을 사용해야 합니다.
NativeAd2Pool.init()
을 호출하여 현재 할당 받을 수 있는 광고의 갯수를 확인합니다.
✏️ 참고
- 최대 10개의 광고를 요청할 수 있습니다.
- 1개 이상의 광고가 할당된 경우
onLoaded()
가 호출됩니다. 할당에 성공한 광고의 갯수는 요청한 광고의 갯수보다 적을 수 있습니다.- 최초 광고 할당 요청에 실패했을 때는
onError()
가 호출되고 광고가 노출되지 않습니다. 광고 미할당 시 발생하는AdError
오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.
public class NativeAd2CarouselActivity extends AppCompatActivity {
private final String unitId = App.UNIT_ID_NATIVE_AD;
// 최대 10개의 광고를 요청할 수 있습니다.
private final int REQUEST_AD_COUNT = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
initCarousel();
}
private void initCarousel() {
// 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 NativeAd2Pool 인스턴스를 생성하여 사용합니다.
NativeAd2Pool carouselPool = new NativeAd2Pool(unitId);
// 현재 할당 받을 수 있는 광고의 갯수를 확인합니다.
carouselPool.init(REQUEST_AD_COUNT, new NativeAd2PoolInitListener() {
@Override
public void onLoaded(int adCount) {
// TODO 할당 받은 광고 갯수(adCount)만큼 아이템 리스트를 만들어 RecyclerView 어댑터를 초기화 합니다.
}
@Override
public void onError(@NonNull AdError adError) {
// TODO 광고 레이아웃을 숨김 처리 하는 등 적절한 에러 처리를 할 수 있습니다.
}
});
}
}
2 단계. RecyclerView 생성하기
Buzzvil SDK에서는 아이템 뷰를 화면에 가로 레이아웃으로 표시하는 RecyclerView
와 이를 처리하는 어댑터를 사용하여 네이티브 지면에 캐러셀을 구현할 수 있습니다.
RecyclerView
를 생성하려면 다음의 절차를 따르세요.
캐러셀을 넣고 싶은 영역에
RecyclerView
를 추가한 액티비티 레이아웃 파일(activity_native_carousel.xml
)을 구현하세요.<!-- activity_native_ad2_carousel.xml -->
...
<!-- 광고를 표시할 Carousel -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carouselRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/view_native_ad2_item" />
...뷰 레이아웃 파일(
view_native_ad2_item.xml
)에RecyclerView
의 각 아이템에 대한 레이아웃을 작성하세요.✏️ 참고
네이티브 기본 연동에서 사용한NativeAd2View
레이아웃을 그대로 사용할 수 있습니다. 자세한 내용은 샘플 코드를 참고해주세요.<?xml version="1.0" encoding="utf-8"?>
<!-- 네이티브 기본 예제와 캐러셀 예제에서 함께 사용하는 레이아웃 리소스 파일입니다. -->
<com.buzzvil.buzzad.benefit.nativead2.api.NativeAd2View xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nativeAd2View"
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</com.buzzvil.buzzad.benefit.nativead2.api.NativeAd2View>RecyclerView
의 각 아이템을 담당할NativeAd2CarouselItem
클래스를 선언하세요.✏️ 참고
RecyclerView
에는 베네핏허브 지면으로의 진입점도 추가할 수 있습니다. 그러므로 확장성을 고려하여NativeAd2CarouselItem
을 기반 클래스로 선언하고, 실제 각 아이템은 이를 상속하여 선언하는 것을 권장합니다. 베네핏허브 지면으로의 진입점을 추가하는 방법에 대한 자세한 내용은 아래 베네핏허브 진입 슬라이드를 참고하세요.다음은 기반 클래스인
NativeAd2CarouselItem
을 선언하고, 이를 확장해서NativeAd2Item
클래스를 선언하는 예시입니다.public class NativeAd2CarouselItem {
// 리사이클러 뷰에서 해당 아이템이 네이티브 2.0인지 타입을 구분하기 위한 클래스입니다.
static class NativeAd2Item extends NativeAd2CarouselItem {
}
// TODO 베네핏허브 진입 슬라이드를 위한 클래스 추가
}
3 단계. RecyclerView 어댑터 구현하기
RecyclerView 어댑터와 ViewHolder를 구현하기 위해 다음의 절차를 따르세요.
NativeAd2View를 바인딩 하는
NativeAd2CarouselViewHolder
를 구현하세요.public class NativeAd2CarouselViewHolder extends RecyclerView.ViewHolder {
private NativeAd2ViewBinder nativeAd2ViewBinder;
public NativeAd2CarouselViewHolder(String unitId, NativeAd2View nativeAd2View) {
super(nativeAd2View);
MediaView mediaView = nativeAd2View.findViewById(R.id.mediaView);
ImageView imageIcon = nativeAd2View.findViewById(R.id.imageIcon);
TextView textTitle = nativeAd2View.findViewById(R.id.textTitle);
TextView textDescription = nativeAd2View.findViewById(R.id.textDescription);
DefaultCtaView ctaView = nativeAd2View.findViewById(R.id.ctaView);
// NativeAd2View와 하위 컴포넌트를 바인드합니다.
nativeAd2ViewBinder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.iconImageView(imageIcon)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.ctaView(ctaView)
.build(unitId);
}
public void setPool(NativeAd2Pool carouselPool, int adKey) {
// 해당 position(adKey)에 해당하는 NativeAd2ViewBinder가 carouselPool을 사용하도록 합니다.
nativeAd2ViewBinder.setPool(adKey, carouselPool);
}
public void bind(int position) {
// NativeAd2ViewBinder의 bind()를 호출하면 광고 할당 및 갱신이 자동으로 수행됩니다.
nativeAd2ViewBinder.bind(position);
}
public void unbind(int position) {
// unbind를 반드시 호출하여 뷰를 재사용할 때 문제가 발생하지 않게 합니다.
nativeAd2ViewBinder.unbind(position);
}
}캐러셀을 처리하기 위한 어댑터(
NativeAd2CarouselAdapter
)를 구현하세요.✅ 중요
광고 중복 할당을 방지하기 위해서는 캐러셀에 포함 된 모든NativeAd2ViewBinder
에 동일한NativeAd2Pool
인스턴스를 설정해주어야 합니다.onBindViewHolder()
에서NativeAd2CarouselViewHolder
에 선언한setPool()
을 통해NativeAd2ViewBinder.setPool()
를 호출하세요.❗️ 주의
광고의 상태가 여러 뷰와 섞이지 않도록 반드시onViewRecycled()
에서NativeAd2View
를 해제해주어야 합니다.NativeAd2CarouselViewHolder
에 선언한unbind()
을 통해NativeAd2ViewBinder.unbind()
를 호출하세요.public class NativeAd2CarouselAdapter extends RecyclerView.Adapter<NativeAd2CarouselViewHolder> {
private String unitId;
private List<NativeAd2CarouselItem> list;
private NativeAd2Pool carouselPool;
public NativeAd2CarouselAdapter(String unitId, List<NativeAd2CarouselItem> list, NativeAd2Pool carouselPool) {
this.unitId = unitId;
this.list = list;
this.carouselPool = carouselPool;
}
@NonNull
@Override
public NativeAd2CarouselViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
NativeAd2View nativeAd2View = (NativeAd2View) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_native_ad2_item, parent, false);
return new NativeAd2CarouselViewHolder(unitId, nativeAd2View);
}
@Override
public void onBindViewHolder(@NonNull NativeAd2CarouselViewHolder holder, int position) {
// 해당 position에 해당하는 NativeAd2ViewBinder가 carouselPool을 사용하도록 합니다.
holder.setPool(carouselPool, position);
holder.bind(position);
}
@Override
public void onViewRecycled(NativeAd2CarouselViewHolder holder) {
super.onViewRecycled(holder);
// unbind를 반드시 호출하여 뷰를 재사용할 때 문제가 발생하지 않게 합니다.
holder.unbind(holder.getAdapterPosition());
}
@Override
public int getItemCount() {
return list.size();
}
}
4 단계. 액티비티 또는 프래그먼트에 결합하기
다음은 위에서 구현한 NativeAd2CarouselAdapter
를 액티비티(NativeAd2CarouselActivity
)에서 생성하는 예시입니다.
- 할당 받은 광고 갯수(
adCount
) 크기의 아이템 리스트를 만들기 위해buildCarouselItems()
를 구현합니다. NativeAd2PoolInitListener.onLoaded()
에서buildCarouselItems()
를 사용하여NativeAd2CarouselAdapter
를 생성하고 RecyclerView에 설정합니다.
다음은 NativeAd2CarouselActivity
구현 코드 예시입니다.
public class NativeAd2CarouselActivity extends AppCompatActivity {
private final String unitId = App.UNIT_ID_NATIVE_AD;
// 최대 10개의 광고를 요청할 수 있습니다.
private final int REQUEST_AD_COUNT = 5;
private RecyclerView carouselRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_native_ad2_carousel);
initCarousel();
}
private void initCarousel() {
// 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 NativeAd2Pool 인스턴스를 생성하여 사용합니다.
NativeAd2Pool carouselPool = new NativeAd2Pool(unitId);
// 현재 할당 받을 수 있는 광고의 갯수를 확인합니다.
carouselPool.init(REQUEST_AD_COUNT, new NativeAd2PoolInitListener() {
@Override
public void onLoaded(int adCount) {
// 어댑터를 초기화합니다.
initAdapter(adCount, carouselPool);
}
@Override
public void onError(@NonNull AdError adError) {
// TODO 광고 레이아웃을 숨김 처리 하는 등 적절한 에러 처리를 할 수 있습니다.
}
});
}
private void initAdapter(int adCount, NativeAd2Pool carouselPool) {
// 할당 받은 광고 갯수(adCount) 크기의 아이템 리스트를 만들어 NativeAd2CarouselAdapter를 생성합니다.
List<NativeAd2CarouselItem> list = buildCarouselItems(adCount);
NativeAd2CarouselAdapter adapter = new NativeAd2CarouselAdapter(unitId, list, carouselPool);
// RecyclerView에 어댑터를 설정합니다.
carouselRecyclerView.setAdapter(adapter);
}
private List<NativeAd2CarouselItem> buildCarouselItems(int adCount) {
// adCount 크기의 배열을 생성합니다.
NativeAd2CarouselItem[] carouselItems = new NativeAd2CarouselItem[adCount];
// 배열을 NativeAd2Item으로 채웁니다.
Arrays.fill(carouselItems, new NativeAd2CarouselItem.NativeAd2Item());
return Arrays.asList(carouselItems);
}
}
이제 앱을 실행하면 캐러셀이 동작하는 모습을 확인할 수 있습니다. 이어서 아래 캐러셀의 필수 기능 구현하기를 참고하여 캐러셀 연동을 완료하세요.
캐러셀의 필수 기능 구현하기
Buzzvil SDK는 다양한 광고 및 유저가 취향에 맞게 광고를 필터링할 수 있는 베네핏허브 지면 진입 경로인 슬라이드 페이지와 진입점을 제공합니다.
✅ 중요
기존에 베네핏허브 지면을 연동하고 있거나 연동할 예정이 있는 경우, SDK 연동의 효용성을 극대화하기 위해 베네핏허브 진입 슬라이드 및 베네핏허브 진입점을 반드시 구현하시기 바랍니다.
베네핏허브 진입 슬라이드
베네핏허브로 진입할 수 있는 슬라이드(Carousel To Feed Slide)를 캐러셀에 구현할 수 있습니다. 캐러셀 내에서 원하는 순서에 베네핏허브 진입 슬라이드를 추가할 수 있으며 추가 갯수 제한도 없어 광고 사이사이에 앱 수익화 효과가 가장 높은 베네핏허브로의 진입점을 자유롭게 추가할 수 있습니다. 이를 위해 Buzzvil SDK는 아래 표에 나열된 클래스를 제공합니다.
코드 | 설명 |
---|---|
FeedPromotion | 베네핏허브 진입 슬라이드에 표시할 리소스(이미지, 문구)를 가지고 있는 객체입니다. |
FeedPromotionFactory | FeedPromotion 객체를 생성합니다.
|
FeedPromotionViewBinder | NativeAd2View 에 FeedPromotion 을 보여줄 수 있도록 연결합니다.
|
베네핏허브 진입 슬라이드를 구현하려면 다음의 절차를 따르세요.
NativeAd2CarouselItem
에서 베네핏허브 진입 슬라이드를 보여주기 위한 클래스의 선언을 추가하세요.다음은 기존의
NativeAd2CarouselItem
구현에서CarouselToFeedSlideItem
클래스의 선언을 추가하는 예시입니다.class NativeAd2CarouselItem {
// RecyclerView에서 해당 아이템이 네이티브 2.0인지 타입을 구분하기 위한 클래스입니다.
static class NativeAd2Item extends NativeAd2CarouselItem {
}
// RecyclerView에서 해당 아이템이 베네핏허브 진입 슬라이드인지 타입을 구분하기 위한 클래스입니다.
static class CarouselToFeedSlideItem extends NativeAd2CarouselItem {
public final FeedPromotion feedPromotion;
CarouselToFeedSlideItem(final FeedPromotion feedPromotion) {
this.feedPromotion = feedPromotion;
}
}
}CarouselToFeedSlideItem
에 맞는 동작을 구현하기 위해 어댑터(NativeAd2CarouselAdapter
)와 뷰 홀더(NativeAd2CarouselViewHolder
)를 구현하세요.i.
NativeAd2CarouselViewHolder
에서 아이템 타입에 따라FeedPromotionViewBinder
를 연결합니다.public class NativeAd2CarouselViewHolder extends RecyclerView.ViewHolder {
...
private FeedPromotionViewBinder carouselToFeedViewBinder;
NativeAd2CarouselViewHolder(String unitId, NativeAd2View nativeAd2View) {
super(nativeAd2View);
...
// CarouselToFeedSlideItem을 위한 바인더를 빌드합니다.
carouselToFeedViewBinder = new FeedPromotionViewBinder.Builder(nativeAd2View, mediaView)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.iconImageView(imageIcon)
.ctaView(ctaView)
.build();
}
...
public void bind(int position, FeedPromotion feedPromotion) {
// FeedPromotion 객체를 뷰에 바인드합니다.
carouselToFeedViewBinder.bind(feedPromotion);
}
public void unbind(int position) {
// unbind를 반드시 호출하여 뷰를 재사용할 때 문제가 발생하지 않게 합니다.
carouselToFeedViewBinder.unbind();
}
}다음은
NativeAd2CarouselViewHolder
전체 코드 예시입니다.public class NativeAd2CarouselViewHolder extends RecyclerView.ViewHolder {
private NativeAd2ViewBinder nativeAd2ViewBinder;
private FeedPromotionViewBinder carouselToFeedViewBinder;
NativeAd2CarouselViewHolder(String unitId, NativeAd2View nativeAd2View) {
super(nativeAd2View);
MediaView mediaView = nativeAd2View.findViewById(R.id.mediaView);
ImageView imageIcon = nativeAd2View.findViewById(R.id.imageIcon);
TextView textTitle = nativeAd2View.findViewById(R.id.textTitle);
TextView textDescription = nativeAd2View.findViewById(R.id.textDescription);
DefaultCtaView ctaView = nativeAd2View.findViewById(R.id.ctaView);
// NativeAd2View와 하위 컴포넌트를 바인드합니다.
nativeAd2ViewBinder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.iconImageView(imageIcon)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.ctaView(ctaView)
.build(unitId);
// CarouselToFeedSlideItem을 위한 바인더를 빌드합니다.
carouselToFeedViewBinder = new FeedPromotionViewBinder.Builder(nativeAd2View, mediaView)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.iconImageView(imageIcon)
.ctaView(ctaView)
.build();
}
public void setPool(NativeAd2Pool carouselPool, int adKey) {
// 해당 position(adKey)에 해당하는 NativeAd2ViewBinder가 carouselPool을 사용하도록 합니다.
nativeAd2ViewBinder.setPool(adKey, carouselPool);
}
public void bind(int position) {
// NativeAd2ViewBinder의 bind()를 호출하면 광고 할당 및 갱신이 자동으로 수행됩니다.
nativeAd2ViewBinder.bind(position);
}
public void bind(int position, FeedPromotion feedPromotion) {
// FeedPromotion 객체를 뷰에 바인드합니다.
carouselToFeedViewBinder.bind(feedPromotion);
}
public void unbind(int position) {
// unbind를 반드시 호출하여 뷰를 재사용할 때 문제가 발생하지 않게 합니다.
nativeAd2ViewBinder.unbind(position);
carouselToFeedViewBinder.unbind();
}
}ii.
NativeAd2CarouselAdapter
의onBindeViewHolder
에서CarouselToFeedSlideItem
일 때 호출할 bind 함수를 연결하세요.public class NativeAd2CarouselAdapter extends RecyclerView.Adapter<NativeAd2CarouselViewHolder> {
...
@Override
public void onBindViewHolder(@NonNull NativeAd2CarouselViewHolder holder, int position) {
...
// 아이템의 타입을 구분하여 적절한 bind() 함수를 호출합니다.
NativeAd2CarouselItem item = list.get(position);
if (item instanceof NativeAd2CarouselItem.NativeAd2Item) {
holder.bind(position);
} else if (item instanceof NativeAd2CarouselItem.CarouselToFeedSlideItem) {
holder.bind(position, ((NativeAd2CarouselItem.CarouselToFeedSlideItem) item).feedPromotion);
}
}
}다음은
NativeAd2CarouselAdapter
전체 코드 예시입니다.public class NativeAd2CarouselAdapter extends RecyclerView.Adapter<NativeAd2CarouselViewHolder> {
private String unitId;
private List<NativeAd2CarouselItem> list;
private NativeAd2Pool carouselPool;
public NativeAd2CarouselAdapter(String unitId, List<NativeAd2CarouselItem> list, NativeAd2Pool carouselPool) {
this.unitId = unitId;
this.list = list;
this.carouselPool = carouselPool;
}
@NonNull
@Override
public NativeAd2CarouselViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
NativeAd2View nativeAd2View = (NativeAd2View) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_native_ad2_item, parent, false);
return new NativeAd2CarouselViewHolder(unitId, nativeAd2View);
}
@Override
public void onBindViewHolder(@NonNull NativeAd2CarouselViewHolder holder, int position) {
// 해당 position에 해당하는 NativeAd2ViewBinder가 carouselPool을 사용하도록 합니다.
holder.setPool(carouselPool, position);
// 아이템의 타입을 구분하여 적절한 bind() 함수를 호출합니다.
NativeAd2CarouselItem item = list.get(position);
if (item instanceof NativeAd2CarouselItem.NativeAd2Item) {
holder.bind(position);
} else if (item instanceof NativeAd2CarouselItem.CarouselToFeedSlideItem) {
holder.bind(position, ((NativeAd2CarouselItem.CarouselToFeedSlideItem) item).feedPromotion);
}
}
@Override
public void onViewRecycled(NativeAd2CarouselViewHolder holder) {
super.onViewRecycled(holder);
// unbind를 반드시 호출하여 뷰를 재사용할 때 문제가 발생하지 않게 합니다.
holder.unbind(holder.getAdapterPosition());
}
}어댑터에 전달하는 아이템 리스트를 생성하는
buildCarouselItems()
에서 원하는 순서에FeedPromotion
을 붙여 넣으세요.다음은 베네핏허브 진입 슬라이드가 캐러셀의 마지막 아이템으로 구현되도록 작성한 코드 예제입니다.
public class NativeAd2CarouselActivity extends AppCompatActivity {
...
private List<NativeAd2CarouselItem> buildCarouselItems(int adCount) {
// 마지막 페이지에 CarouselToFeedSlideItem을 추가하기 위해 1개 더 큰 사이즈로 배열을 생성합니다.
NativeAd2CarouselItem[] carouselItems = new NativeAd2CarouselItem[adCount + 1];
// 배열을 NativeAd2Item으로 채웁니다.
Arrays.fill(carouselItems, new NativeAd2CarouselItem.NativeAd2Item());
// 마지막 아이템은 CarouselToFeedSlideItem으로 설정합니다.
carouselItems[carouselItems.length - 1] = new NativeAd2CarouselItem.CarouselToFeedSlideItem(new FeedPromotionFactory(unitId).buildForCarousel());
return Arrays.asList(carouselItems);
}
}
베네핏허브 진입점
캐러셀에서 베네핏허브로 진입할 수 있는 UI인 진입점(Carousel To Feed Link)을 캐러셀의 하단에 구현해야 합니다.
베네핏허브 진입점을 구현하려면 다음의 절차를 따르세요.
캐러셀로 사용할 RecyclerView 아래에
FeedEntryView
를 추가하세요.✅ 중요
app:buzzvilFeedEntryViewName
은 아래 예제 코드처럼"carousel_to_feed_link"
로 설정하세요.activity_native_ad2_carousel.xml
의 전체 코드는 여기에서 확인할 수 있습니다.<!-- activity_native_ad2_carousel.xml -->
<!-- 광고를 표시할 Carousel -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carouselRecyclerView"
... />
<!-- Carousel 하단에서 Feed를 열 수 있게 하는 Carousel To Feed Link -->
<!-- buzzvilFeedEntryViewName의 값은 "carousel_to_feed_link"를 사용해야 합니다. -->
<com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView
android:id="@+id/toFeedLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="16dp"
android:layout_marginEnd="36dp"
app:buzzvilFeedEntryViewName="carousel_to_feed_link">
<!-- 내부 레이아웃은 자유롭게 설정할 수 있습니다. 아래는 LinearLayout으로 구현한 예시입니다. -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/NativeCarouselToFeedLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="포인트 더 받으러 가기" />
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:scaleType="centerInside"
android:src="@drawable/ic_chevron_right" />
</LinearLayout>
</com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView>광고 할당 요청에 대한 응답 상태에 따른 베네핏허브 진입점의 표시 여부를 설정하세요.
캐러셀 및 베네핏허브 진입점 표시: 보여줄 광고가 있는 경우
캐러셀 및 베네핏허브 진입점 미표시: 광고가 아직 로드되지 않은 경우, 오류가 발생하는 경우, 광고가 없는 경우
다음은
NativeAd2CarouselActivity
에서 광고 할당 요청 성공 여부에 따라RecyclerView
(캐러셀)와FeedEntryView
의 visibility를 변경하는 예시입니다.public class NativeAd2CarouselActivity extends AppCompatActivity {
...
private RecyclerView carouselRecyclerView;
private FeedEntryView toFeedLink;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_native_ad2_carousel);
carouselRecyclerView = findViewById(R.id.carouselRecyclerView);
toFeedLink = findViewById(R.id.toFeedLink);
initCarousel();
}
private void initCarousel() {
carouselRecyclerView.setVisibility(View.GONE);
toFeedLink.setVisibility(View.GONE);
...
carouselPool.init(REQUEST_AD_COUNT, new NativeAd2PoolInitListener() {
@Override
public void onLoaded(int adCount) {
carouselRecyclerView.setVisibility(View.VISIBLE);
toFeedLink.setVisibility(View.VISIBLE);
...
}
@Override
public void onError(@NonNull AdError adError) {
// 광고 레이아웃을 숨김 처리 하는 등 적절한 에러 처리를 할 수 있습니다.
carouselRecyclerView.setVisibility(View.GONE);
toFeedLink.setVisibility(View.GONE);
}
});
}
...
}
베네핏허브 진입점 위치를 고정하세요.
각 광고 아이템의 설명 텍스트(
textDescription
) 길이 차이로 인해 라인 수가 상이하면 각 슬라이드의 베네핏허브 진입점의 위치가 계속 변경되는 현상이 발생할 수 있습니다. 이러한 현상의 발생을 방지하기 위해 광고 설명 텍스트를 표시하는 뷰의lines
값을 고정하여 항상 일정한 위치를 유지할 수 있습니다.다음은 광고 설명 텍스트를 표시하는 뷰의 lines 값을
2
로 설정한 예시입니다.<!-- view_native_ad2_item.xml -->
...
<TextView
android:id="@+id/textDescription"
android:ellipsize="end"
android:lines="2"
...
/>
이제 앱을 실행하면 캐러셀의 마지막 페이지에 베네핏허브 진입 슬라이드가 표시되고, 캐러셀 하단에 베네핏허브 진입점이 추가된 모습을 확인할 수 있습니다. 이어서 아래 캐러셀의 부가 기능 구현하기를 참고하여 유저 친화적인 UI/UX를 제공해보세요.
캐러셀의 부가 기능 구현하기
이 항목에서는 캐러셀에 부가 기능을 구현하기 위한 다양한 방법 중 일부를 제시합니다. 필요에 따라 적절하게 코드를 변형하여 사용해주세요.
✏️ 참고
이 문서에서는 설명에 필요한 코드의 일부만 제공합니다. 전체 코드를 확인하려면 샘플 코드를 참고하세요.
무한 루프 구현하기
캐러셀에서 유한한 아이템을 끊임 없이 스크롤할 수 있는 무한 루프 기능을 구현할 수 있습니다. 캐러셀의 무한 루프를 구현하는 방법는 매우 다양하나, 이 가이드에서는 Adapter의 getItemCount()
가 매우 큰 값을 반환하게 하는 간단한 방법을 제시합니다.
무한 루프를 구현하려면 다음의 절차를 따르세요.
어댑터(
NativeAd2CarouselAdapter
)가isInfiniteLoopEnabled
파라미터를 받도록 변경하세요.public class NativeAd2CarouselAdapter extends RecyclerView.Adapter<NativeAd2CarouselViewHolder> {
...
private boolean isInfiniteLoopEnabled;
public NativeAd2CarouselAdapter(String unitId, List<NativeAd2CarouselItem> list, NativeAd2Pool carouselPool, boolean isInfiniteLoopEnabled) {
...
this.isInfiniteLoopEnabled = isInfiniteLoopEnabled;
}
...
}NativeAd2CarouselAdapter
에서getItemCount()
의 구현을 변경하고, position을 사용할 때 실제 인덱스를 가져오기 위해 리스트의 크기로 나눈 나머지를 사용하세요.
getItemCount()
: RecyclerView가 무한한 데이터를 가진 것처럼 표시되도록,isInfiniteLoopEnabled
가true
이고 보여줄 아이템이 있는 경우에는Integer.MAX_VALUE
를 반환하도록 변경하세요.getItemPosition()
: 무한 루프의position
을 나누어 실제 index 값을 반환합니다.public class NativeAd2CarouselAdapter extends RecyclerView.Adapter<NativeAd2CarouselViewHolder> {
...
@Override
public void onBindViewHolder(@NonNull NativeAd2CarouselViewHolder holder, int position) {
int itemPosition = getItemPosition(position);
// position 대신 itemPosition을 사용합니다.
holder.setPool(carouselPool, itemPosition);
NativeAd2CarouselItem item = list.get(itemPosition);
if (item instanceof NativeAd2CarouselItem.NativeAd2Item) {
holder.bind(itemPosition);
} else if (item instanceof NativeAd2CarouselItem.CarouselToFeedSlideItem) {
holder.bind(itemPosition, ((NativeAd2CarouselItem.CarouselToFeedSlideItem) item).feedPromotion);
}
}
@Override
public void onViewRecycled(NativeAd2CarouselViewHolder holder) {
super.onViewRecycled(holder);
int itemPosition = getItemPosition(holder.getAdapterPosition());
// holder.getAdapterPosition() 대신 itemPosition을 사용합니다.
holder.unbind(itemPosition);
}
@Override
public int getItemCount() {
int actualItemCount = list.size();
if (isInfiniteLoopEnabled && actualItemCount > 0) {
// 무한 루프를 쉽게 구현하는 방법으로 매우 큰 수를 여기서 반환합니다.
return Integer.MAX_VALUE;
}
return actualItemCount;
}
private int getItemPosition(int position) {
if (isInfiniteLoopEnabled) {
return position % list.size();
} else {
return position;
}
}
}
액티비티(
NativeAd2CarouselActivity
)에NativeAd2CarouselAdapter(isInfiniteLoopEnabled)
를 추가하세요.public class NativeAd2CarouselActivity extends AppCompatActivity {
...
// 무한 스크롤을 적용합니다.
boolean isInfiniteLoopEnabled = true;
...
private void initAdapter(int adCount, NativeAd2Pool carouselPool) {
...
// 어댑터를 설정합니다.
NativeAd2CarouselAdapter adapter = new NativeAd2CarouselAdapter(unitId, list, carouselPool, isInfiniteLoopEnabled);
carouselRecyclerView.setAdapter(adapter);
if (isInfiniteLoopEnabled) {
// 적당히 큰 수의 position으로 이동하여 무한 스크롤 효과를 구현합니다.
carouselRecyclerView.getLayoutManager().scrollToPosition(list.size() * 10000);
}
}
...
}
로딩 화면 구현하기
NativeAd2StateChangedListener
를 통해 광고 참여 후 갱신 시 로딩 화면을 구현하여 네트워크 요청에 따른 딜레이를 시각적으로 안내합니다.
✏️ 참고
RecyclerView에서는 뷰 홀더가 재활용 되면서 로딩 뷰가 visible 상태로 남아있을 수 있습니다. 아이템 타입 별bind()
에서 적절하게 초기화를 수행해주세요.
public class NativeAd2CarouselViewHolder extends RecyclerView.ViewHolder {
private LinearLayout loadingView;
private NativeAd2ViewBinder nativeAd2ViewBinder;
private FeedPromotionViewBinder carouselToFeedViewBinder;
NativeAd2CarouselViewHolder(String unitId, NativeAd2View nativeAd2View) {
super(nativeAd2View);
this.loadingView = nativeAd2View.findViewById(R.id.loadingView);
MediaView mediaView = nativeAd2View.findViewById(R.id.mediaView);
ImageView imageIcon = nativeAd2View.findViewById(R.id.imageIcon);
TextView textTitle = nativeAd2View.findViewById(R.id.textTitle);
TextView textDescription = nativeAd2View.findViewById(R.id.textDescription);
DefaultCtaView ctaView = nativeAd2View.findViewById(R.id.ctaView);
// NativeAd2View와 하위 컴포넌트를 바인드합니다.
nativeAd2ViewBinder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.iconImageView(imageIcon)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.ctaView(ctaView)
.build(unitId);
// 필요에 따라 광고 갱신 상태를 받아올 수 있는 NativeAd2StateChangedListener를 설정하세요.
nativeAd2ViewBinder.addNativeAd2StateChangedListener(new NativeAd2StateChangedListener() {
@Override
public void onRequested() {
setLoadingView(true);
}
@Override
public void onNext(@NonNull NativeAd2 nativeAd2) {
setLoadingView(false);
}
@Override
public void onComplete() {
setLoadingView(false);
}
@Override
public void onError(@NonNull AdError adError) {
setLoadingView(false);
}
});
// CarouselToFeedSlideItem을 위한 바인더를 빌드합니다.
carouselToFeedViewBinder = new FeedPromotionViewBinder.Builder(nativeAd2View, mediaView)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.iconImageView(imageIcon)
.ctaView(ctaView)
.build();
}
public void bind(int position, FeedPromotion feedPromotion) {
// FeedPromotion 객체를 뷰에 바인드합니다.
carouselToFeedViewBinder.bind(feedPromotion);
// 베네핏허브 진입 슬라이드는 로딩 뷰가 필요 없기 때문에 false로 설정합니다.
setLoadingView(false);
}
private void setLoadingView(boolean isLoading) {
if (isLoading) {
loadingView.setVisibility(View.VISIBLE);
} else {
loadingView.setVisibility(View.GONE);
}
}
}
광고 이벤트 리스너 등록하기
캐러셀에 포함된 광고가 유저에게 노출되거나 유저가 클릭하는 등의 광고 이벤트가 발생하는 시점을 기록하여 유저 행동을 파악할 수 있습니다.
✏️ 참고
리워드 적립 결과(RewardResult
) 종류는 리워드 적립 결과(RewardResult
) 종류를 참고하세요.
❗️ 주의
- 광고 이벤트 리스너로 베네핏허브 진입 슬라이드의 노출 또는 클릭 이벤트를 수신할 수는 없습니다.
- 로그 기록, 단순 알림 외에 다른 동작을 추가하는 것을 권장하지 않습니다. 직접 구현한 동작이 네이티브의 광고 자동 갱신 등의 기능과 충돌할 수 있습니다.
public class NativeAd2CarouselViewHolder extends RecyclerView.ViewHolder {
private NativeAd2ViewBinder nativeAd2ViewBinder;
NativeAd2CarouselViewHolder(String unitId, NativeAd2View nativeAd2View) {
super(nativeAd2View);
TextView eventTextView = nativeAd2View.findViewById(R.id.eventTextView);
MediaView mediaView = nativeAd2View.findViewById(R.id.mediaView);
ImageView imageIcon = nativeAd2View.findViewById(R.id.imageIcon);
TextView textTitle = nativeAd2View.findViewById(R.id.textTitle);
TextView textDescription = nativeAd2View.findViewById(R.id.textDescription);
DefaultCtaView ctaView = nativeAd2View.findViewById(R.id.ctaView);
// NativeAd2View와 하위 컴포넌트를 바인드합니다.
nativeAd2ViewBinder = new NativeAd2ViewBinder.Builder()
.nativeAd2View(nativeAd2View)
.mediaView(mediaView)
.iconImageView(imageIcon)
.titleTextView(textTitle)
.descriptionTextView(textDescription)
.ctaView(ctaView)
.build(unitId);
// 필요에 따라 광고 이벤트 상태를 받아올 수 있는 NativeAd2EventListener를 설정하세요.
// 로그 기록, 단순 알림 외에 다른 동작을 추가하는 것을 권장하지 않습니다. 자동 갱신 등 네이티브 2.0의 기능과 직접 구현한 동작이 충돌할 수 있습니다.
nativeAd2ViewBinder.addNativeAd2EventListener(new NativeAd2EventListener() {
@Override
public void onImpressed(@NonNull NativeAd2 nativeAd2) {
eventTextView.setText("event: onImpressed");
}
@Override
public void onClicked(@NonNull NativeAd2 nativeAd2) {
eventTextView.setText("event: onClicked");
}
@Override
public void onRewardRequested(@NonNull NativeAd2 nativeAd2) {
eventTextView.setText("event: onRewardRequested");
}
@Override
public void onRewarded(@NonNull NativeAd2 nativeAd2, @NonNull RewardResult rewardResult) {
eventTextView.setText("event: onRewarded, result: " + rewardResult.name());
}
@Override
public void onParticipated(@NonNull NativeAd2 nativeAd2) {
eventTextView.setText("event: onParticipated");
}
});
}
}
앞뒤 광고 아이템을 부분적으로 노출하기
RecyclerView의 padding
과 clipToPadding
속성을 사용하여 아이템 크기를 줄이고 앞뒤 광고를 부분적으로 노출하면 유저의 스크롤을 유도할 수 있습니다.
<!-- activity_native_ad2_carousel.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".nativead2.carousel.NativeAd2CarouselActivity">
<!-- 광고를 표시할 Carousel -->
<!-- clipToPadding, paddingHorizontal: 이전과 이후 아이템을 살짝 보여주기 위해 설정 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carouselRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingHorizontal="32dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/view_native_ad2_item" />
</LinearLayout>
광고 아이템 사이의 여백 설정하기
RecyclerView에서 광고 아이템 사이의 여백을 설정하려면 다양한 방법을 적용할 수 있습니다. 이 가이드에서는 ItemDecoration
을 사용하는 방법을 제시합니다. 다음의 절차를 따르세요.
RecyclerView.ItemDecoration
를 상속받아PaddingDividerDecoration
를 구현합니다.public class PaddingDividerDecoration extends RecyclerView.ItemDecoration {
private final int paddingDp;
public PaddingDividerDecoration(int paddingDp) {
this.paddingDp = paddingDp;
}
@Override
public void getItemOffsets(
@NonNull Rect outRect,
@NonNull View view,
@NonNull RecyclerView parent,
@NonNull RecyclerView.State state
) {
// 여백을 한 쪽만 설정하면 PagerSnapHelper가 약간 어긋나게 동작하므로, 양쪽에 동일하게 여백을 넣습니다.
int paddingPx = dpToPx(paddingDp / 2);
outRect.left = paddingPx;
outRect.right = paddingPx;
}
private int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}RecyclerView에
PaddingDividerDecoration
을 추가하세요.
public class NativeAd2CarouselActivity extends AppCompatActivity {
...
private RecyclerView carouselRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_native_ad2_carousel);
carouselRecyclerView = findViewById(R.id.carouselRecyclerView);
initCarousel();
}
private void initCarousel() {
...
carouselPool.init(REQUEST_AD_COUNT, new NativeAd2PoolInitListener() {
@Override
public void onLoaded(int adCount) {
// 어댑터를 초기화합니다.
initAdapter(adCount, carouselPool);
}
...
});
}
private void initAdapter(int adCount, NativeAd2Pool carouselPool) {
// 아이템 간에 여백을 넣는 Decoration을 추가합니다.
int itemPaddingDp = 16;
carouselRecyclerView.addItemDecoration(new PaddingDividerDecoration(itemPaddingDp));
...
}
}