Feed 타입 (2.0)

BuzzAd Benefit 2.0 SDK: Type B - Feed

본 가이드는 BuzzAd-Benefit SDK의 피드 타입 광고를 연동하는 방법을 다루는 문서입니다.


※ 주의사항

  1. Feed 타입을 연동하기 전, 공통 가이드의 연동 사항을 모두 적용했는지 확인해주세요.

  2. Feed 의 커스터마이즈는 상단 툴바, 광고 리스트 아이템 영역, 헤더, 디자인 커스터마이즈가 가능합니다.

     

  3. Feed는 다크테마를 지원합니다.
    만일 다크테마를 지원하지 않는다면 가이드를 확인해주세요.

(중요) Basic Usage 를 모두 적용한 뒤, 하단의 Advanced Usage를 적용해해주세요.

 

Index

 

Basic Usage


FeedConfig 및 FeedHandler 설정

  1. Feed unit id로 FeedConfig를 설정합니다.

  2. FeedConfig 객체를 사용하여 FeedHandler를 생성합니다.

  3. startFeedActivity()를 호출하여 Feed 액티비티를 실행합니다.

1 2 3 4 5 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .feedHeaderViewAdapterClass(DefaultFeedHeaderViewAdapter.class) .build(); final FeedHandler feedHandler = new FeedHandler(feedConfig); feedHandler.startFeedActivity(this);

 

autoLoadingEnabled 설정

FeedConfig 설정에 autoLoadingEnabled 값을 true 로 설정하면, Feed 의 스크롤이 일정 이상 내려갔을 때, 더 많은 광고 노출을 위해 광고 할당을 추가로 진행합니다. (단, 광고 물량 상황에 따라, 오토로딩으로 추가되는 광고가 없을 수 있습니다.)

1 2 3 4 5 6 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... // 아래의 설정 조건을 확인하여 적용해야 합니다. .autoLoadingEnabled(true) ... .build();

2.9.x 버전에서 다음과 같이 변경되었습니다.

(기존) Feed Tab UI 를 사용하는 경우, 한 번에 많은 양의 광고를 받아오기 때문에, autoLoadingEnabled 를 설정하지 않습니다. (설정해도, 동작하지 않았음)

(변경) autoLoadingEnabled 을 사용할 수 있도록, Feed Tab UI 의 광고 요청 방식이 변경되었습니다. 2.5.x ~ 2.7.x 버전에서 autoLoadingEnable 을 제거했던 파트너의 경우, 해당 코드 추가 여부를 확인 부탁드립니다.

[1] Feed Tab UI 를 사용하지 않으며 액션형을 광고를 노출하는 경우, 필수로 적용해야 합니다. 

[2] 그 외에 노출형 광고만 연동하는 경우, 많은 광고 노출을 위해 적용을 권장합니다. 

 

 


Feed Tab UI 및 Filter UI 활성화

Feed에 Tab UI를 추가하여 기존 광고를 일반 광고와 쇼핑 적립형 (CPS) 광고로 구분하여 보여줍니다. 또한 Tab UI를 사용하는 경우 Filter UI를 추가하여 같이 사용할 수 있습니다.

 

Feed Tab UI 활성화

FeedConfig 빌드 시점에 tabUiEnabled 값을 설정하여 Feed Tab UI를 사용할 수 있습니다

1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .tabUiEnabled(true) .build();

.autoLoadingEnabled() 항목은 제거해야 합니다.

 

Feed Filter UI 활성화

Feed Tab UI가 Enable되어 있는 경우, 아래와 같이 Filter UI를 설정할 수 있습니다

1 2 3 4 5 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .tabUiEnabled(true) // set tabUiEnabled to true .filterUiEnabled(true) .build();

 

Feed의 광고 현황 확인

Basic Usage처럼 바로 startFeedActivity를 호출하는 경우 Feed 액티비티가 실행되면서 광고를 로드하게 되어, 유저에게 보여줄 수 있는 광고가 없어 빈 화면이 보이게 될 수도 있습니다. 이에 Feed 액티비티를 실행하기 전에 preload()를 호출한 뒤 onPreloaded() 콜백을 호출하여 상태를 확인한 후 광고가 있을때만 피드로 진입할 수 있도록 하는 것을 추천합니다.

  • feedHandler.getSize() : 광고의 개수

  • feedHandler.getTotalReward() : 적립 가능한 총 포인트 금액

 

1 2 3 4 5 6 7 8 9 10 11 12 feedHandler.preload(new FeedHandler.FeedPreloadListener() { @Override public void onPreloaded() { int feedAdSize = feedHandler.getSize(); int feedTotalReward = feedHandler.getTotalReward(); } @Override public void onError(AdError error) { // 광고가 없을 경우 호출됩니다. error를 통해 발생한 error의 원인을 알 수 있습니다 } });

 

유의사항

  • 프리로드한 FeedHandler와 동일한 객체에서 startFeedActivity()를 호출해야 합니다.

    • 주의사항 : 하나의 FeedHandler 인스턴스에서 광고를 load/preload 한 경우, 그 인스턴스는 계속 같은 광고를 들고 있게 됩니다. 그래서 activity에서 유저가 이탈하더라도 다시 해당 인스턴스로 startFeedActivity를 하는 경우 같은 광고 리스트를 보게 됩니다. 만약 피드에 진입할 때마다 새로 광고가 로드되는 것을 원하는 경우 새로운 FeedHandler 인스턴스를 만들어서 startFeedActivity()를 호출해야 합니다.

  • FeedHandler를 일회성으로 객체를 생성하여 preload 기능을 사용할 경우, preload에 대한 결과를 받지 못할 수 있습니다. Memory Leak 방지를 위해 feedHandler에 weakReference를 적용하고 있기 때문입니다. FeedHandler의 변수 선언을 지역변수가 아닌 Class 변수로 하는 등 일회적이지 않은 방식으로 객체를 생성하셔야 합니다.

 

1 2 3 4 5 6 7 8 9 10 11 12 // 일회성 사용의 예 private void preloadFeed() { // WeakReference가 적용된 FeedHandler가 지역변수로서 선언이 되어서, 메모리에서 지워져 아래의 Listener 코드가 실행되지 않을 수 있습니다 final FeedHandler feedHandler = new FeedHandler(getFeedConfig()); feedHandler.preload(new FeedHandler.FeedPreloadListener() { @Override public void onPreloaded() { // 실행되지 않을 수 있습니다 } @Override public void onError(AdError error) { // 실행되지 않을 수 있습니다 } }); }

Advanced Usage


디자인 커스터마이즈

(중요) Feed Customization 주의사항

  • FeedToolbarHolder, FeedAdsAdapter, FeedHeaderViewAdapter class의 custom class를 생성할때 다음 조건중 하나를 사용해야합니다.

    1. 각 클래스는 inner class 가 아니어야 합니다.

    2. Inner class로 생성을 해야할 경우, public static class로 선언이 되어야 합니다.

  • 위의 조건에 맞지 않는 경우, class를 찾지못하는 현상이 발생하여 customization이 적용되지 않습니다.

 

툴바 Customization

Feed 상단의 툴바를 커스터마이징할 수 있습니다.

  1. FeedToolbarHolder를 구현하는 class 를 생성합니다.

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class CustomFeedToolbarHolder implements FeedToolbarHolder { private FeedActivityToolbar toolbar; @Override public View getView(final Activity activity, @NonNull final String unitId) { // FeedActivityToolbar is a default toolbar view that you can only change the title and view's attributes. // Create a custom view and return it if you would like to add more UI components. this.toolbar = new FeedActivityToolbar(activity, unitId); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { activity.finish(); } }); toolbar.setTitle("BuzzAdBenefit Feed"); toolbar.setBackgroundColor(Color.parseColor("#1290FF")); // 변경하려는 "색상코드" 를 입력 return toolbar; } @Override public void onTotalRewardUpdated(int totalReward) { // Use this callback if you want to show the current total points that users can get } @Override public void onDestroyView() { // Use this this callback for clearing memory } }

     

  2. FeedConfig 빌드 시점에 해당 FeedToolbarHolder class 를 지정합니다.

    1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .feedToolbarHolderClass(CustomFeedToolbarHolder.class) .build();

FeedToolbarHolder.onDestroyView 는 2.11.x 에서 추가됐습니다.

 

툴바 Height 변경

Customize 된 toolbar가 들어가는 layout의 height값이 기본적으로 고정되어 있습니다. Toolbar의 height 값을 수정하고 싶다면 다음과 같은 코드를 추가 해야합니다.

1 2 3 4 5 6 7 8 9 10 11 12 // AndroidManifest.xml <activity android:name="com.buzzvil.buzzad.benefit.presentation.feed.FeedBottomSheetActivity" android:theme="@style/MyAppTheme" tools:replace="android:theme"/> // styles.xml <style name="AppTheme" parent=...> <!-- Customize your theme here. --> ... <item name="actionBarSize>DESIRED_ACTION_BAR_HEIGHT</item> </style>

 

Feed의 헤더 Customization

Feed 상단의 헤더 영역을 커스터마이징하여, 유저에게 해당 피드가 어떤 공간인지 상세히 안내할 수 있습니다.

  1. FeedHeaderViewAdapter 를 구현하는 class 를 생성합니다.

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class CustomFeedHeaderViewAdapter implements FeedHeaderViewAdapter { @Override public View onCreateView(final Context context, final ViewGroup parent) { final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); return inflater.inflate(R.layout.bz_view_feed_header, parent, false); } @Override public void onBindView(final View view, final int reward) { // Display total reward on the header if needed. final View rewardLayout = view.findViewById(R.id.rewardLayout); if (reward == 0) { rewardLayout.setVisibility(View.GONE); } else { rewardLayout.setVisibility(View.VISIBLE); final TextView rewardTextView = view.findViewById(R.id.rewardText); final String rewardText = view.getContext().getString(R.string.bz_feed_header_view_reward_text, reward); rewardTextView.setText(rewardText); } } }

     

  2. FeedConfig 빌드 시점에 해당 FeedHeaderViewAdapter class 를 지정합니다.

    1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .feedHeaderViewAdapterClass(CustomFeedHeaderViewAdapter.class) .build();

 

Feed 광고 리스트 아이템 영역 Customization - 일반 광고

Feed의 광고 리스트 아이템 뷰를 커스터마이징하고 광고 이벤트에 대한 콜백을 등록할 수 있습니다.

  1. AdsAdapter 를 상속받는 class 를 구현합니다.

    1. onCreateViewHolderonBindViewHolder 를 구현해 Feed 리스트에 보여줄 itemView 의 레이아웃 및 바인딩 로직을 커스터마이징합니다.

    2. CtaView의 getCtaTextView() 및 getRewardImageView() 함수를 호출하여 CtaView에 보여지는 텍스트 및 리워드 이미지에 대한 customization을 할 수 있습니다. (좀 더 유연한 customization을 위해 View를 새로 만들고 싶은 경우에는 아래 CtaView Customization 참조)

    3. (optional) onImpressedonClickedonRewardRequestedonRewardedonParticipated를 오버라이드하여 광고의 임프레션, 클릭, 리워드 요청, 리워드 지급 결과, 참여완료에 대한 이벤트 콜백을 받을 수 있습니다 (콜백의 정의 및 동작은 문서 참조)

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 public class CustomAdsAdapter extends AdsAdapter<AdsAdapter.NativeAdViewHolder> { @Override public NativeAdViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); final NativeAdView feedNativeAdView = (NativeAdView) inflater.inflate(R.layout.bz_view_feed_ad, parent, false); return new NativeAdViewHolder(feedNativeAdView); } @Override public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) { final NativeAdView view = (NativeAdView) holder.itemView; final Ad ad = nativeAd.getAd(); final Creative.Type creativeType = ad.getCreative() == null ? null : ad.getCreative().getType(); final MediaView mediaView = view.findViewById(R.id.mediaView); final LinearLayout titleLayout = view.findViewById(R.id.titleLayout); final TextView titleView = view.findViewById(R.id.textTitle); final ImageView iconView = view.findViewById(R.id.imageIcon); final TextView descriptionView = view.findViewById(R.id.textDescription); final CtaView ctaView = view.findViewById(R.id.ctaView); ctaView.setBackgroundColor(Color.parseColor(“#3976FD”)); // (선택) 변경하려는 "색상코드" final CtaPresenter ctaPresenter = new CtaPresenter(ctaView); // CtaView should not be null ctaPresenter.bind(nativeAd); if (mediaView != null) { mediaView.setCreative(ad.getCreative()); mediaView.setVideoEventListener(new VideoEventListener() // Override and implement methods }); } if (titleView != null) { titleView.setText(ad.getTitle()); } if (iconView != null) { ImageLoader.getInstance().displayImage(ad.getIconUrl(), iconView); } if (descriptionView != null) { descriptionView.setText(ad.getDescription()); } final Collection<View> clickableViews = new ArrayList<>(); clickableViews.add(ctaView); clickableViews.add(mediaView); clickableViews.add(titleLayout); clickableViews.add(descriptionView); view.setMediaView(mediaView); view.setClickableViews(clickableViews); view.setNativeAd(nativeAd); view.addOnNativeAdEventListener(new NativeAdView.OnNativeAdEventListener() { @Override public void onImpressed(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) { } @Override public void onClicked(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { ctaPresenter.bind(nativeAd); } @Override public void onRewardRequested(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { } @Override public void onRewarded(@NonNull NativeAdView view, @NonNull NativeAd nativeAd, @Nullable RewardResult rewardResult) { } @Override public void onParticipated(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) { ctaPresenter.bind(nativeAd); } }); } }

       

  2. FeedConfig 빌드 시점에 해당 AdsAdapter class 를 지정합니다.

    1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .adsAdapterClass(CustomAdsAdapter.class) .build();

 

Feed 광고 리스트 아이템 영역 Customization - 쇼핑 적립 광고 (CPS)

  1. AdsAdapter 를 상속받는 class 를 구현합니다.

    1. onCreateViewHolderonBindViewHolder 를 구현해 Feed 리스트에 보여줄 itemView 의 레이아웃 및 바인딩 로직을 커스터마이징합니다. 

    2. CtaView의 getCtaTextView() 및 getRewardImageView() 함수를 호출하여 CtaView에 보여지는 텍스트 및 리워드 이미지에 대한 customization을 할 수 있습니다. (좀 더 유연한 customization을 위해 View를 새로 만들고 싶은 경우에는 아래 CtaView Customization 참조) 

    3. (optional) onImpressedonClickedonRewardRequestedonRewardedonParticipated를 오버라이드하여 광고의 임프레션, 클릭, 리워드 요청, 리워드 지급 결과, 참여완료에 대한 이벤트 콜백을 받을 수 있습니다 (콜백의 정의 및 동작은 문서 참조)

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 public class CPSAdsAdapter extends AdsAdapter<AdsAdapter.NativeAdViewHolder> { @Override public NativeAdViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); final NativeAdView feedNativeAdView = (NativeAdView) inflater.inflate(R.layout.bz_view_feed_shopping_ad, parent, false); return new NativeAdViewHolder(feedNativeAdView); } @Override public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) { final NativeAdView view = (NativeAdView) holder.itemView; final Ad ad = nativeAd.getAd(); final Creative.Type creativeType = ad.getCreative() == null ? null : ad.getCreative().getType(); final MediaView mediaView = view.findViewById(R.id.mediaView); // Texts for CPS ADs final TextView descriptionView = view.findViewById(R.id.textDescription); final TextView priceText = view.findViewById(R.id.discountedPriceText); final TextView originalPriceText = view.findViewById(R.id.originalPriceText); final TextView discountPercentageText = view.findViewById(R.id.discountPercentageText); final TextView categoryText = view.findViewById(R.id.categoryText); final CtaView ctaView = view.findViewById(R.id.ctaView); ctaView.setBackgroundColor(Color.parseColor("#3976FD")); // (선택) 변경하려는 "색상코드" final CtaPresenter ctaPresenter = new CtaPresenter(ctaView); // CtaView should not be null ctaPresenter.bind(nativeAd); if (mediaView != null) { mediaView.setCreative(ad.getCreative()); mediaView.setVideoEventListener(new VideoEventListener() { // Override and implement methods }); } if (descriptionView != null) { descriptionView.setText(ad.getDescription()); } final Product product = ad.getProduct(); if (product != null) { if (product.getDiscountedPrice() != null) { // 할인이 있는 쇼핑 광고 originalPriceText.setPaintFlags(originalPriceText.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); int percentage = 0; if (product.getPrice() > product.getDiscountedPrice()) { percentage = Math.round(((product.getPrice() - product.getDiscountedPrice()) / product.getPrice() * 100)); } if (percentage > 0) { priceText.setText(getCommaSeparatedPrice(product.getDiscountedPrice().longValue())); originalPriceText.setText(getCommaSeparatedPrice((long) product.getPrice())); discountPercentageText.setText(String.format(Locale.ROOT, "%d%%", percentage)); discountPercentageText.setVisibility(View.VISIBLE); } else { priceText.setText(getCommaSeparatedPrice((long) product.getPrice())); originalPriceText.setText(""); discountPercentageText.setVisibility(View.GONE); } } else { // 할인이 없는 쇼핑 광고 priceText.setText(getCommaSeparatedPrice((long) product.getPrice())); originalPriceText.setText(""); discountPercentageText.setVisibility(View.GONE); } categoryText.setText(product.getCategory()); if (!TextUtils.isEmpty(product.getCategory())) { categoryText.setVisibility(View.VISIBLE); } } final Collection<View> clickableViews = new ArrayList<>(); clickableViews.add(ctaView); clickableViews.add(mediaView); clickableViews.add(descriptionView); view.setMediaView(mediaView); view.setClickableViews(clickableViews); view.setNativeAd(nativeAd); view.addOnNativeAdEventListener(new NativeAdView.OnNativeAdEventListener() { @Override public void onImpressed(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) { } @Override public void onClicked(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { ctaPresenter.bind(nativeAd); } @Override public void onRewardRequested(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { } @Override public void onRewarded(@NonNull NativeAdView view, @NonNull NativeAd nativeAd, @Nullable RewardResult rewardResult) { } @Override public void onParticipated(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) { ctaPresenter.bind(nativeAd); } }); } private String getCommaSeparatedPrice (long price){ return String.format(Locale.getDefault(), "₩%,d", price); } }

       

  2. FeedConfig 빌드 시점에 해당 AdsAdapter class 를 지정합니다.

    1 2 3 4 5 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .tabUiEnabled(true) // set tabUiEnabled to true .cpsAdsAdapterClass(CustomCPSAdsAdapter.class) .build();

 

Feed Tab UI Customization

Feed Tab UI가 enable되어 있는 경우, 아래와 같은 방식으로 몇 가지 Tab의 속성을 바꿀 수 있습니다.

1 2 3 4 5 6 7 8 9 10 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .tabUiEnabled(true) // set tabUiEnabled to true // tabUiEnabled 를 true 로 설정한 경우, 아래의 속성을 사용 .tabDefaultColor(R.color.YOUR_DEFAULT_COLOR) // 탭이 선택되지 않았을 때 색상 (color resource) .tabSelectedColor(R.color.YOUR_SELECTED_COLOR) // 탭이 선택되었을 때 색상 (color resource) .tabBackgroundResId(R.color.YOUR_BACKGROUND_COLOR) // 탭의 배경 색 (color resource) .tabTextArray(new String[] { FIRST_TAB_NAME, SECOND_TAB_NAME }) // 탭에 들어갈 문구 .build();

 

Feed Filter UI Customization

Feed Tab UI와 Filter UI가 enable되어 있는 경우 아래와 같은 방식으로 몇 가지 Filter의 속성을 바꿀 수 있습니다.

1 2 3 4 5 6 7 8 9 10 11 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .tabUiEnabled(true) // set tabUiEnabled to true .filterUiEnabled(true) // set filterUiEnabled to true // tabUiEnabled, filterUiEnabled 를 true 로 설정한 경우, 아래의 속성을 사용 .filterBackgroundDefaultColor(R.color.YOUR_DEFAULT_BG_COLOR) // 필터가 선택되지 않았을 때 배경색 .filterBackgroundSelectedColor(R.color.YOUR_SELECTED_BG_COLOR) // 필터가 선택되었을 때 배경색 .filterTextDefaultColor(R.color.YOUR_DEFAULT_TEXT_COLOR) // 필터가 선택되지 않았을 때 글자색 .filterTextSelectedColor(R.color.YOUR_SELECTED_TEXT_COLOR) // 필터가 선택되었을 때 글자색 .build();

 

CtaView (버튼) Customization

CtaView를 Default로 제공되는 View가 아닌, 다른 모양의 View로 만들고 싶으신 경우 다음과 같이 설정을 진행하면 됩니다.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Override public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) { final NativeAdView view = (NativeAdView) holder.itemView; final Ad ad = nativeAd.getAd(); final Creative.Type creativeType = ad.getCreative() == null ? null : ad.getCreative().getType(); ... // View를 상속받는 CustomCtaView class를 생성하여 원하는 모양의 CtaView를 사용 할 수 있습니다. final CustomCtaView customizedCtaView = view.findViewById(R.id.customCtaView); // 아래 정보를 이용하여 cta view를 업데이트 final String callToAction = nativeAd.getAd().getCallToAction(); final int reward = nativeAd.getAd().getReward(); // 주의사항 참조 final boolean participated = nativeAd.isParticipated(); // 다음과 같은 function을 CustomCtaView class에 생성하여 텍스트 및 아이콘을 업데이트 할 수 있습니다. customizedCtaView.setCtaText(callToAction); customizedCtaView.setRewardText(reward); customizedCtaView.setRewardIcon(R.drawable.your_reward_icon); customizedCtaView.setParticiapted(participated); // 참여 완료된 광고에 대해서 UI를 처리하는 부분 customizedCtaView.setBackgroundColor(Color.parseColor(“#3976FD”)); // 변경하려는 "색상코드" ... final List<View> clickableViews = new ArrayList<>(); clickableViews.add(customizedCtaView); ... nativeAdView.addOnNativeAdEventListener(new NativeAdView.OnNativeAdEventListener() { ... @Override public void onParticipated(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { // 매체사 기획에 따라 UI 처리 // Customize 된 CtaView를 participated 상태에 맞게 업데이트 final boolean participated = nativeAd.isParticipated(); customizedCtaView.setParticipated(participated); } }); }

 

※ 주의사항

유저가 적립을 받은지 시간이 얼마 지나지 않아서 리워드가 부여되지 않거나 또는 원래 광고 자체가 리워드를 가지고 있지 않은 경우가 있을 수 있습니다. 따라서 광고 레이아웃을 구성할 때 Ad Properties를 Assign 하는 과정에서 rewardImage와 rewardText에 대해서 reward > 0 인지 체크해서 리워드를 보여줄지 말지 결정하는 로직이 필요합니다 (아래의 샘플 코드 참조).

 

1 2 3 4 5 6 7 if (reward > 0) { customizedCtaVIew.showRewardImage(CtaView.ImageType.Default); customizedCtaVIew.setRewardText(String.format(Locale.US, "+%d", reward)); } else { customizedCtaVIew.showRewardImage(null); customizedCtaVIew.setRewardText(null); }

 

유저 피드백 Customization

베이스 리워드 지급시 유저에게 제공되는 피드백을 커스터마이즈 할 수 있습니다.

  1. DefaultFeedFeedbackHandler를 상속받는 클래스를 생성합니다.

  2. customize를 원하는 메소드를 override 합니다.

  3. FeedConfig을 초기화할 때, 이전 스텝에서 생성한 Custom FeedFeedbackHandler를 넘겨줍니다.

1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .feedFeedbackHandler(CustomFeedFeedbackHandler.class) .build();
1 2 3 4 5 interface FeedFeedbackHandler { fun getBaseRewardNotificationView(context: Context, reward: Int): View fun onBridgePointBaseRewardReceived(context: Context, reward: Int) }

Methods

Description

Methods

Description

getBaseRewardNotificationView

베이스 리워드 지급시 피드 상단에 보여지는 notification view 입니다.

onBridgePointBaseRewardReceived

베이스 리워드 지급시 브릿지 포인트 연동 중일 경우 호출되는 콜백입니다.

 

Image 타입의 광고 서포트

Feed에 할당되는 광고의 개수를 극대화 하기 위해, 기존에 버즈스크린 잠금화면에 할당하던 Full Screen 광고를 이미지의 일부를 Cropping 한 후 사용 (이하 "Image 타입의 광고")하실 수 있습니다. (자세한 구현 사항은 아래 그림 참조)

  • DefaultAdsAdapter 를 그대로 사용하는 경우에는 별도의 추가 작업 없이도 Image 타입 광고를 제공 받으실 수 가능합니다. 아래 내용은 Customization을 위해 AdsAdapterClass 를 별도로 설정하였을 때에만 해당됩니다.

  • Image 타입의 광고의 경우 기존 광고들과 다르게 icon, title, description 의 내용이 없습니다. 더불어 광고 영역 전체의 상하의 길이가 깁니다. 이런 상황에서 레이아웃을 알맞게 그리기 위한 추가 작업을 한 후 해당 광고 타입을 받을 수 있도록 FeedConfig 에 새로운 설정을 추가해야 합니다.

  1. View의 Height 조정: Image 타입의 광고는 기존의 mediaView 보다 상하 길이가 길기 때문에, customization 하시는 모든 view의 height를 wrap_content로 적용하고 기타 height를 고정하는 로직을 제거해야 합니다.

  2. View의 레이아웃 조정: NativeAd 를 이용해서 광고 뷰를 그리는 과정에서 현재 타입이 Image 인지 확인하여 title, description 을 위한 layout 을 없앱니다.

    1 2 3 4 5 6 7 if (Creative.Type.IMAGE.equals(ad.getCreative().getType())) { titleLayout.setVisibility(View.GONE); descriptionView.setVisibility(View.GONE); } else { titleLayout.setVisibility(View.VISIBLE); descriptionView.setVisibility(View.VISIBLE); }

     

  3. FeedConfig 설정: FeedConfig 빌드 시점에 imageTypeEnabled 를 true 로 설정해서 Image 타입 광고를 받을 수 있게 합니다.

    1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .imageTypeEnabled(true) .build();

 

FeedFragment를 사용한 방식

기본적으로 제공되는 FeedActivity가 아닌 다른 방식으로 Feed를 보여주고 싶을때, FeedFragment를 사용할 수 있습니다.

 

  • FeedFragment 기본 사용 방법

    1 2 3 4 5 6 7 8 9 10 11 <fragment android:id="@+id/feed_fragment" android:name="com.buzzvil.buzzad.benefit.presentation.feed.FeedFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> // XML에 추가 후 아래와 같이 init을 해야합니다 final FeedFragment feedFragment = (FeedFragment) getSupportFragmentManager().findFragmentById(R.id.feed_fragment); if (feedFragment != null) { feedFragment.init(YOUR_FEED_CONFIG); }

     

  • FeedFragment에서도 FeedActivity와 마찬가지로 FeedHandler를 생성한 후 preload()를 호출하고 startFeedActivity()를 호출하지 않으면 Preload와 관련한 기능을 모두 사용할 수 있습니다.

  • FeedFragment에서도 FeedActivity에서 제공하는 Customization 옵션 중 Toolbar를 제외한 AdsAdapter와 Header, Image 타입 광고의 경우 feedConfig에 추가하는 방식을 통해 Customize가 가능합니다.

매번 새로운 광고를 서빙 받기 위해서는 FeedFragment를 초기화 하기 전 FeedHandler를 생성해야 합니다.

 

액션형 광고에 대한 BottomSheet 사용하기

Feed에서 액션형 광고에 한해 BottomSheet을 보여 줄 수 있습니다.

BottomSheet을 사용하고 싶지 않은 경우에는 원래의 방식대로도 사용 가능합니다.

BottomSheet을 사용하기 위해서는 FeedConfig를 기존에 FeedHandler에 추가하는 방식과는 달리 BuzzAdBenefit.init() 시점에 추가해주어야 합니다.

1 2 3 4 5 6 7 8 9 private void initializeBuzzAdBenefit(Context context) { final FeedConfig feedConfig = new FeedConfig.Builder(context, YOUR_FEED_UNIT_ID) ... // customization code can be added .build(); final BuzzAdBenefitConfig buzzAdBenefitConfig = configBuilder .add(feedConfig) .build(); BuzzAdBenefit.init(context, buzzAdBenefitConfig); }

FeedHandler를 사용하여 Feed를 보여줄경우:

1 new FeedHandler(context, YOUR_FEED_UNIT_ID).startFeedActivity(context);

FeedFragment를 사용할 경우:

1 2 FeedConfig feedConfig = BuzzAdBenefit.getInstance().getConfig().getUnitConfig(unitId, FeedConfig.class); feedFragment.init(feedConfig)

 

액션형 광고에 대한 브릿지 페이지(BottomSheet)에 ADN(애드네트워크) 광고 배너 노출

액션형 광고가 랜딩되는 BottomSheet에 배너 광고를 추가할 수 있습니다. BottomSheet을 위한 unit_id를 따로 발급 받아 FeedConfig에 설정해야합니다.

또한 배너, BottomSheet 배너, 종료 인터스티셜 별로 각각의 unit_id를 사용합니다. unit_id를 각각 발급받아 사용해주세요.

1 2 3 4 5 6 7 8 9 10 private void initializeBuzzAdBenefit(Context context) { final FeedConfig feedConfig = new FeedConfig.Builder(context, YOUR_FEED_UNIT_ID) .bottomSheetUnitId(YOUR_FEED_BOTTOM_SHEET_UNIT_ID) ... // customization code can be added .build(); final BuzzAdBenefitConfig buzzAdBenefitConfig = configBuilder .add(feedConfig) .build(); BuzzAdBenefit.init(context, buzzAdBenefitConfig); } 
  • Adfit

    • Feed, Pop 사용시 연동

    • Banner, ExitInterstitial, BottomSheet Banner 연동시 추가 필요

    • 한국

1 2 3 4 5 dependencies { implementation("com.buzzvil.mediation:sdk-adfit:3.4.0.0") implementation("com.buzzvil.mediation:sdk-outbrain:3.9.2.1") implementation("com.buzzvil.mediation:sdk-five:1.1.0") }

 

피드에 프로필 배너 스위치 추가

userProfile이 설정되지 않았거나, userProfile에 생년월일 및 성별이 설정되지 않으면 프로필 배너가 보여질 수 있습니다.

profileBannerEnabled 플래그를 false로 설정하면 프로필 배너가 보여지지 않게 됩니다. (디폴트는 true입니다.)

1 2 3 4 5 6 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... // 프로필 배너를 노출하고 싶지 않을 때 false로 설정합니다. .profileBannerEnabled(false) ... .build();

 

팝 옵트인 버튼 (FAB) Customization

팝이 활성화되어 있지 않을때 피드 우측 하단에 FAB를 보여주어 팝 옵트인을 유도합니다. 유저는 FAB를 클릭하여 pop의 permission을 받고, opt in 하는 절차를 거쳐 팝 아이콘을 보게 됩니다. 이 항목에서는 FAB의 다자인을 커스터마이즈 하는 방법을 소개합니다.

  • FAB 색상과 아이콘은 테마 적용을 통해 커스터마이징 할 수 있습니다.

  • FAB 텍스트 및 클릭시 보여지는 액티비티 커스터마이징은 아래 항목을 참고해주세요.

OptInAndShowPopButtonHandler를 상속받는 클래스를 생성해주세요. 팝 옵트인 버튼의 기본 동작을 재사용하기 위해 DefaultOptInAndShowPopButtonHandler 클래스를 상속받는 것을 권장합니다.

1 2 3 4 5 abstract class OptInAndShowPopButtonHandler { abstract fun getOptInAndShowPopButtonText(context: Context): String abstract fun onOptInAndShowPopButtonClick(view: View) }

Methods

Description

Methods

Description

getOptInAndShowPopButtonText

FAB에 보여지는 스트링입니다.

onOptInAndShowPopButtonClick

FAB 클릭시 호출되는 콜백입니다. FAB 클릭 시 보여지는 액티비를 커스터마이즈 하기 위해 사용할 수 있습니다.

FeedConfig을 초기화할 때, 이전 스텝에서 생성한 Custom OptInAndShowPopButtonHandler를 넘겨줍니다.

1 2 3 4 final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") ... .optInAndShowPopButtonHandler(CustomOptInAndShowPopButtonHandler.class) .build();