커스터마이징
전체 테마
Buzzvil SDK에서 제공하는 기본 UI를 사용해 광고 지면이나 CTA의 색상, 아이콘 이미지 등 테마를 변경할 수 있습니다.
주요 색상
Buzzvil SDK에서 제공하는 UI 중 다이얼로그의 버튼 색상, 바텀 시트 UI의 확인 버튼 등 앱에 연동한 모든 지면 내 주요 UI의 색상(Primary color)을 변경할 수 있습니다.
Primary 색상 변경을 위해 아래와 같이 색상 리소스를 추가하세요.
✏️ 참고
primary light 색상은 primary 색상에 투명도 60%를 적용한 값을 권장합니다. 예를 들어, primary 색상값이#FF0000
이라면 primary light 색상값은#99FF0000
를 사용하세요.
- Swift
- Objective C
import BuzzvilSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
let theme = BuzzBenefitTheme { builder in
builder.primaryColor = YOUR_PRIMARY_COLOR
builder.primaryLightColor = YOUR_PRIMARY_LIGHT_COLOR
}
BuzzBenefit.shared.setGlobalTheme(theme)
BuzzBenefit.shared.initialize(with: config)
return true
}
}
@import BuzzvilSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BuzzBenefitConfig *config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
BuzzBenefitTheme *theme = [BuzzBenefitTheme themeWithBlock:^(BuzzBenefitThemeBuilder * _Nonnull builder) {
builder.primaryColor = YOUR_PRIMARY_COLOR;
builder.primaryLightColor = YOUR_PRIMARY_LIGHT_COLOR;
}];
[[BuzzBenefit sharedInstance] setGlobalTheme:theme];
[[BuzzBenefit sharedInstance] initializeWithConfig:config];
return YES;
}
@end
리워드 아이콘
Buzzvil SDK에서 제공하는 UI 중 CTA 버튼 등의 아이콘을 변경할 수 있습니다.
다음은 BuzzBenefitTheme
에 rewardIcon
를 추가해 리워드 아이콘을 변경하는 예시입니다. 각 속성 값에서 커스터마이징할 수 있는 UI에 대해서는 아래의 표를 참고하세요.
속성 값 | 커스터마이징이 가능한 UI |
---|---|
rewardIcon |
|
participatedIcon |
|
✏️ 참고
테마를 변경하려면BuzzBenefit.initialize()
을 호출해 Buzzvil SDK를 초기화하기 전에BuzzBenefit.setGloabalTheme()
을 호출해야 합니다.
- Swift
- Objective C
import BuzzvilSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
let theme = BuzzBenefitTheme { builder in
builder.rewardIcon = YOUR_REWARD_ICON
builder.participatedIcon = YOUR_PARTICIPATED_ICON
}
BuzzBenefit.shared.setGlobalTheme(theme)
BuzzBenefit.shared.initialize(with: config)
return true
}
}
@import BuzzvilSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BuzzBenefitConfig *config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
BuzzBenefitTheme *theme = [BuzzBenefitTheme themeWithBlock:^(BuzzBenefitThemeBuilder * _Nonnull builder) {
builder.rewardIcon = YOUR_REWARD_ICON;
builder.participatedIcon = YOUR_PARTICIPATED_ICON;
}];
[[BuzzBenefit sharedInstance] setGlobalTheme:theme];
[[BuzzBenefit sharedInstance] initializeWithConfig:config];
return YES;
}
@end
CTA 버튼 자체 구현하기
Buzzvil SDK에서 기본으로 제공하는 UI를 사용하지 않고 CTA 버튼을 자체적으로 구현할 수 있습니다. 자체적으로 구현한 CTA 버튼을 베네핏허브와 네이티브에서 사용할 수 있습니다.
CTA 버튼을 직접 구현하려면 CtaViewProtocol
프로토콜을 준수하는 UIView
클래스의 서브클래스를 생성하세요.
다음은 UIStackView
를 활용하여 CTA View 클래스를 생성한 예시입니다.
- Swift
- Objective-C
import UIKit
import BuzzvilSDK
final class CustomCtaView: UIStackView, BZVCtaViewProtocol {
let rewardImageView = UIImageView(frame: .zero)
let rewardLabel = UILabel(frame: .zero)
let ctaLabel = UILabel(frame: .zero)
required init(coder: NSCoder) {
super.init(coder: coder)
setUpView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setUpView()
}
private func setUpView() {
addArrangedSubview(rewardImageView)
addArrangedSubview(rewardLabel)
addArrangedSubview(ctaLabel)
}
// MARK: BZVCtaViewProtocol
func renderRewardNotAvailableViewState(withCtaText ctaText: String) {
// 리워드가 없는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
rewardImageView.isHidden = true
rewardLabel.isHidden = true
ctaLabel.text = ctaText
}
func renderRewardAvailableViewState(withCtaText ctaText: String, reward: Int) {
// 리워드가 있는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
rewardImageView.isHidden = false
rewardLabel.isHidden = false
rewardImageView.image = UIImage(named: "YOUR_REWARD_IMAGE")
rewardLabel.text = "+\(reward)"
ctaLabel.text = ctaText
}
func renderParticipatingViewState(withCtaText ctaText: String) {
// 참여 확인 중인 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
rewardImageView.isHidden = true
rewardLabel.isHidden = true
ctaLabel.text = "YOUR_PARTICIPATING_TEXT"
}
func renderParticipatedViewState(withCtaText ctaText: String) {
// 참여 완료한 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
rewardImageView.isHidden = false
rewardLabel.isHidden = true
rewardImageView.image = UIImage(named: "YOUR_PARTICIPATED_IMAGE")
ctaLabel.text = "YOUR_PARTICIPATED_TEXT"
}
}
@import UIKit;
@import BuzzvilSDK;
@interface CustomCtaView : UIStackView <BZVCtaViewProtocol>
@end
@interface CustomCtaView ()
@property (nonatomic, strong, readonly) UIImageView *rewardImageView;
@property (nonatomic, strong, readonly) UILabel *rewardLabel;
@property (nonatomic, strong, readonly) UILabel *ctaLabel;
@end
@implementation CustomCtaView
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (void)setupView {
_rewardImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
[self addArrangedSubview:_rewardImageView];
_rewardLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addArrangedSubview:_rewardLabel];
_ctaLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addArrangedSubview:_ctaLabel];
}
#pragma mark - BZVCtaViewProtocol
- (void)renderRewardNotAvailableViewStateWithCtaText:(NSString *)ctaText {
// 리워드가 없는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
[_rewardImageView setHidden:YES];
[_rewardLabel setHidden:YES];
[_ctaLabel setText:ctaText];
}
- (void)renderRewardAvailableViewStateWithCtaText:(NSString *)ctaText reward:(NSInteger)reward {
// 리워드가 있는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
[_rewardImageView setHidden:NO];
[_rewardLabel setHidden:NO];
[_rewardImageView setImage:[UIImage imageNamed:@"YOUR_REWARD_IMAGE"]];
[_rewardLabel setText:[NSString stringWithFormat:@"+%ld", reward]];
[_ctaLabel setText:ctaText];
}
- (void)renderParticipatingViewStateWithCtaText:(NSString *)ctaText {
// 참여 확인 중인 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
[_rewardImageView setHidden:YES];
[_rewardLabel setHidden:YES];
[_ctaLabel setText:@"YOUR_PARTICIPATING_TEXT"];
}
- (void)renderParticipatedViewStateWithCtaText:(NSString *)ctaText {
// 참여 완료한 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
[_rewardImageView setHidden:NO];
[_rewardLabel setHidden:YES];
[_rewardImageView setImage:[UIImage imageNamed:@"YOUR_PARTICIPATED_IMAGE"]];
[_ctaLabel setText:@"YOUR_PARTICIPATED_TEXT"];
}
@end
자체 구현한 CTA 버튼을 GlobalTheme에 적용하기
✅ 중요
커스텀 CTA 버튼을 글로벌 테마에 적용하는 것은 Buzzvil SDK v5.17.x부터 지원합니다.
BuzzBenefitTheme
에 ctaViewClass
를 추가해 자체 구현한 CTA 버튼을 적용하세요.
✏️ 참고
- 기본 광고 디자인을 사용하는 베네핏허브, 인터스티셜 등에 적용됩니다.
- 커스텀 광고 디자인을 지원하는 네이티브, 베네핏허브 등에는 적용되지 않습니다.
- Swift
- Objective C
import BuzzvilSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
let theme = BuzzBenefitTheme { builder in
// ...
builder.ctaViewClass = CustomCtaView.self
}
BuzzBenefit.shared.setGlobalTheme(theme)
// ...
return true
}
}
@import BuzzvilSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BuzzBenefitConfig *config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
BuzzBenefitTheme *theme = [BuzzBenefitTheme themeWithBlock:^(BuzzBenefitThemeBuilder * _Nonnull builder) {
// ...
builder.ctaViewClass = [CustomCtaView class];
}];
[[BuzzBenefit sharedInstance] setGlobalTheme:theme];
// ...
return YES;
}
@end
네이티브
네이티브 오버레이 UI
버즈빌 대시 어드민을 통해 오버레이 UI를 구성하는 이미지와 텍스트를 커스터마이징할 수 있습니다.
✏️ 참고
오버레이 UI를 커스텀하지 않거나 커스터마이징 토글을 OFF 하면 버즈빌이 제공하는 UI가 적용됩니다.
네이티브 오버레이 UI를 커스터마이징하려면 다음의 절차를 따르세요.
- 버즈빌 대시 어드민(https://dashboard.buzzvil.com/) 에 접속하세요.
- Inventory Manager에서 앱을 검색하고 선택한 후 왼쪽 메뉴 패널에서 Entry Point Contents 메뉴로 이동하세요.
- 진입점 유형 드롭다운 목록에서 ‘네이티브 오버레이’를 선택하세요.
- 오버레이 유형별로 커스터마이징 토글을 켜세요.
- 원하는 이미지와 UI 스트링을 등록하세요.
- 커스터마이징 UI를 실시간으로 미리보기할 수 있습니다.
- 오버레이 UI를 커스텀하지 않으면 버즈빌이 제공하는 UI가 적용됩니다.
- 이미지와 UI 스트링이 지원하는 규격은 다음과 같습니다.
- 이미지 포맷: PNG, JPG, JSON(Lottie)
- 파일 크기: 최대 2 MB
- 이미지 비율: 312 x 212 (가로 x 세로)
- UI 스트링 글자 수 & 줄 수: 최대 20 자 (공백 포함) & 두 줄
- 오른쪽 상단의 저장하기 버튼을 클릭하세요.
✏️ 참고
SDK Configuration 에서 비활성화한 기능의 오버레이는 접힌 상태로 표시됩니다.
베네핏허브
Buzzvil SDK에서 제공하는 UI의 디자인을 변경하기 위한 방법을 안내합니다.
럭키박스
SDK 패치 없이 UI 스트링 및 이미지 소재를 풀 커스텀하여 럭키박스의 스타일을 원하는 대로 변경할 수 있습니다. 커스텀하고 싶은 항목과 내용을 버즈빌 담당자(help@buzzvil.com)에게 전달해 주세요.
항목 | 설명 |
---|---|
프로모션 명 |
|
참여 전후 진입점 |
|
참여도 영역 아이콘 |
|
럭키박스 참여 전후 CTA |
|
럭키박스 참여 전후 이미지 |
|
추가보상 배너 |
|
일일 리워드 금액 |
|
연속 참여 성공 리워드 금액 |
|
연속 참여 성공 문구 |
|
연속 참여 성공 문구 색상 |
|
연속 참여 성공 아이콘 |
|
연속 참여 성공 주변 효과 |
|
유의 사항 |
|
미션팩
SDK 패치 없이 UI 스트링 및 이미지 소재를 풀 커스텀하여 미션팩의 스타일을 원하는 대로 변경할 수 있습니다. 커스텀하고 싶은 항목과 내용을 버즈빌 담당자(help@buzzvil.com)에게 전달해 주세요.
항목 | 세부항목 | 설명 |
---|---|---|
베네핏허브 진입점 | 타이틀 |
|
베네핏허브 진입점 | 아이콘 |
|
배경 | 색상 |
|
배경 | 그라데이션 효과 |
|
프로모션 타이틀 | 텍스트 | - |
미션 보너스 | 지급 비율 |
|
미션 보너스 CTA | 텍스트 | - |
도전 중 미션 | 도전 중 타이틀 | - |
도전 중 미션 | 도전 중 아이콘 |
|
도전 중 미션 | 도전 중 미션 설명 |
|
도전 중 미션 | 도전 중 미션 CTA |
|
도전 중 미션 | 미션 완료 CTA |
|
참여 완료 | 참여 완료 타이틀 | - |
미션 구성 | 미션 타이틀 | - |
미션 구성 | 설정 기준 |
|
미션 구성 | 미션별 진행도 |
|
럭키박스 진입점 | CTA |
|
유의 사항 | - |
|
성과 기록 유닛 | - |
|
광고 인정 유닛 | - |
|
미션팩 배경 Gradation 설정하기
- Swift
- Objective C
import BuzzvilSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
let theme = BuzzBenefitTheme { builder in
// ...
builder.backgroundGradientColors = [YOUR_GRADIENT_UICOLOR, ...]
}
BuzzBenefit.shared.setGlobalTheme(theme)
// ...
return true
}
}
@import BuzzvilSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BuzzBenefitConfig *config = ...
// BuzzBenefit.initialize()를 호출하기 전에 GlobalTheme을 설정합니다.
BuzzBenefitTheme *theme = [BuzzBenefitTheme themeWithBlock:^(BuzzBenefitThemeBuilder * _Nonnull builder) {
// ...
builder.backgroundGradientColors = @[YOUR_GRADIENT_UICOLOR, ...];
}];
[[BuzzBenefit sharedInstance] setGlobalTheme:theme];
// ...
return YES;
}
@end
내비게이션 바
베네핏허브 내비게이션 바의 UI 스트링을 수정하거나 내비게이션 바 영역을 자체 구현할 수 있습니다.
내비게이션 바 UI 스트링 변경하기
내비게이션 바의 UI 스트링을 변경할 수 있습니다.
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.navigationBarTitle = "YOUR_TITLE"
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.navigationBarTitle = @"YOUR_TITLE";
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
내비게이션 바 자체 구현하기
하위 뷰 컨트롤러로 베네핏허브 연동하기 항목을 참고하여 내비게이션 바를 자체 구현할 수 있습니다.
헤더
베네핏허브 상단의 헤더를 원하는 목적에 맞게 자유롭게 활용할 수 있습니다. 예를 들어, 베네핏허브 영역을 설명하는 공간으로 활용하거나 적립 가능한 금액을 표시할 수도 있습니다.
✏️ 참고
헤더 영역을 자체 구현하지 않으면총 적립 가능 금액
을 보여주는 기본 헤더가 표시됩니다.
헤더 영역을 사용하지 않으려면 버즈빌 담당자(help@buzzvil.com)에게 연락하세요.
다음은 헤더 영역을 변경하는 예시입니다.
BZVFeedHeaderView
를 상속하는 클래스를 생성하고 Custom View를 헤더 영역에 구현합니다. 그리고 BZVFeedConfig
의 headerViewClass
속성에 새로 구현한 클래스를 추가합니다.
- Swift
- Objective-C
import UIKit
import BuzzvilSDK
final class CustomFeedHeaderView: BZVFeedHeaderView {
let headerLabel = UILabel(frame: .zero)
override class func desiredHeight(_ width: CGFloat) -> CGFloat {
return 60
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
func setupView() {
addSubview(headerLabel)
// LayoutConstraint 설정
// ...
}
override func availableRewardDidUpdate(_ reward: Int) {
headerLabel.text = "리워드 \(reward)원"
}
}
@import UIKit;
@import BuzzvilSDK;
@interface CustomFeedHeaderView : BZVFeedHeaderView
@end
@interface CustomFeedHeaderView ()
@property (nonatomic, strong, readonly) UILabel *headerLabel;
@end
@implementation CustomFeedHeaderView
+ (CGFloat)desiredHeight:(CGFloat)width {
return 60;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (void)setupView {
_headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addSubview:_headerLabel];
// LayoutConstraint 설정
// ...
}
- (void)availableRewardDidUpdate:(NSInteger)reward {
_headerLabel.text = [NSString stringWithFormat:@"리워드 %ld원", reward];
}
@end
- Swift
- Objective-C
let feedConfig = BZVFeedConfig { builder in
builder.unitId = "YOUR_FEED_UNIT_ID"
builder.headerViewClass = CustomFeedHeaderView.self
}
BZVFeedConfig *feedConfig = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
builder.unitId = @"YOUR_FEED_UNIT_ID";
builder.headerViewClass = [CustomFeedHeaderView class];
}];
광고 분류 필터
광고 분류 필터의 기본 색상은 monochrome이며, primary color를 따라가도록 변경할 수 있습니다.
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.usePrimaryColorInFilter = true
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.usePrimaryColorInFilter = YES;
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
광고 디자인
Buzzvil SDK에서 제공하는 광고는 일반 광고와 쇼핑 광고가 있습니다.
- 일반 광고: 쇼핑 광고를 제외한 나머지 유형의 광고입니다.
- 쇼핑 광고: 유저가 광고를 통해 물건 구매를 달성하는 경우 유저에게 구매 금액의 일정 비율을 포인트로 돌려주는 광고입니다.
두 유형 모두 광고를 표현할 수 있는 다양한 정보로 구성됩니다. 일반 광고와 쇼핑 광고를 구성하는 요소와 UI에 대해서는 아래의 표를 참고하세요.
광고 유형 | 구성 요소 | 설명 |
---|---|---|
공통(일반, 쇼핑) | 광고 제목 (필수) | 광고의 제목입니다. 최대 10자까지 권장하며, 필요에 따라 글자 수에 상관 없이 일정 부분은 생략 부호로 대체할 수 있습니다. |
광고 소재 (필수) |
| |
광고 설명 (필수) | 광고에 대한 상세 설명입니다. 최대 40자까지 권장하며, 필요에 따라 글자 수에 상관 없이 일정 부분은 생략 부호로 대체할 수 있습니다. | |
광고주 아이콘 (필수) |
| |
CTA 버튼 (필수) |
✏️ 참고 CTA 버튼의 디자인을 변경하려면 CTA 버튼 자체 구현하기 토픽을 참고하세요. | |
클릭 가능한 영역 설정 (필수) | 광고의 클릭 가능한 영역을 설정하는 기능합니다. | |
광고 알림 문구 (권장) | 광고임을 명시하는 문구입니다. (예: 광고 , ad , 스폰서 , Sponsored ) | |
쇼핑 적립 | OriginalPrice View (권장) | 상품의 원가를 표시합니다. |
Price View (권장) | 상품의 할인된 가격을 표시합니다. | |
DiscountRate View (권장) | 상품 가격의 할인율을 표시합니다. 할인율은 원가와 할인가로 비교하여 산출해서 표시해야 합니다. |
일반 광고 디자인 자체 구현하기
일반 광고의 디자인을 변경하려면 다음의 절차를 따르세요.
- 일반 광고용
BZVFeedAdView
의 상속 클래스를 구현하세요.
- 하위 뷰로
BZVNativeAdView
,BZVMediaView
,BZVDefaultCtaView
클래스를 추가하세요. renderAd
에서BZVNativeAdViewBinder
를 이용하여 광고 데이터(NativeAd
)를 앞서 생성한CustomFeedAdView
에 바인딩하세요.
- Swift
- Objective-C
import UIKit
import BuzzvilSDK
final class CustomFeedAdView: BZVFeedAdView {
let nativeAdView = BZVNativeAdView(frame: .zero)
let mediaView = BZVMediaView(frame: .zero)
let iconImageView = UIImageView(frame: .zero)
let titleLabel = UILabel(frame: .zero)
let descriptionLabel = UILabel(frame: .zero)
let ctaView = BZVDefaultCtaView(frame: .zero)
lazy var viewBinder = BZVNativeAdViewBinder { builder in
builder.nativeAdView = self.nativeAdView
builder.mediaView = self.mediaView
builder.iconImageView = self.iconImageView
builder.titleLabel = self.titleLabel
builder.descriptionLabel = self.descriptionLabel
builder.ctaView = self.ctaView
builder.clickableViews = [
self.mediaView,
self.ctaView
]
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
override class func desiredHeight(_ width: CGFloat) -> CGFloat {
return width * 0.8
}
func setupView() {
addSubview(nativeAdView)
nativeAdView.addSubview(mediaView)
nativeAdView.addSubview(iconImageView)
nativeAdView.addSubview(titleLabel)
nativeAdView.addSubview(descriptionLabel)
nativeAdView.addSubview(ctaView)
// LayoutConstraint 설정
// ...
}
override func renderAd(_ ad: BZVNativeAd) {
viewBinder.bind(with: ad)
}
}
@import UIKit;
@import BuzzvilSDK;
@interface CustomFeedAdView : BZVFeedAdView
@end
@interface CustomFeedAdView ()
@property (nonatomic, strong, readonly) BZVNativeAdView *nativeAdView;
@property (nonatomic, strong, readonly) BZVMediaView *mediaView;
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
@property (nonatomic, strong, readonly) UILabel *titleLabel;
@property (nonatomic, strong, readonly) UILabel *descriptionLabel;
@property (nonatomic, strong, readonly) BZVDefaultCtaView *ctaView;
@property (nonatomic, strong, readonly) BZVNativeAdViewBinder *viewBinder;
@end
@implementation CustomFeedAdView
+ (CGFloat)desiredHeight:(CGFloat)width {
return width * 0.8;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (void)setupView {
_nativeAdView = [[BZVNativeAdView alloc] initWithFrame:CGRectZero];
[self addSubview:_nativeAdView];
_mediaView = [[BZVMediaView alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_mediaView];
_iconImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_iconImageView];
_titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_titleLabel];
_descriptionLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_descriptionLabel];
_ctaView = [[BZVDefaultCtaView alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_ctaView];
_viewBinder = [BZVNativeAdViewBinder viewBinderWithBlock:^(BZVNativeAdViewBinderBuilder * _Nonnull builder) {
builder.nativeAdView = self.nativeAdView;
builder.mediaView = self.mediaView;
builder.iconImageView = self.iconImageView;
builder.titleLabel = self.titleLabel;
builder.descriptionLabel = self.descriptionLabel;
builder.ctaView = self.ctaView;
builder.clickableViews = @[
self.mediaView,
self.ctaView
];
}];
// LayoutConstraint 설정
// ...
}
- (void)renderAd:(BZVNativeAd *)ad {
[_viewBinder bindWithNativeAd:ad];
}
@end
BZVNativeAdEventDelegate
을 통해 광고 콜백 이벤트 수신 기능을 부가적으로 추가할 수도 있습니다.
- Swift
- Objective-C
import UIKit
import BuzzvilSDK
final class CustomFeedAdView: BZVFeedAdView, BZVNativeAdEventDelegate {
override func renderAd(_ ad: BZVNativeAd) {
viewBinder.bind(with: ad)
ad.delegate = self
}
// MARK: BZVNativeAdEventDelegate
func didImpress(_ nativeAd: BZVNativeAd) {
}
func didClick(_ nativeAd: BZVNativeAd) {
}
func didRequestReward(for nativeAd: BZVNativeAd) {
}
func didReward(for nativeAd: BZVNativeAd, with result: BZVRewardResult) {
}
func didParticipateAd(_ nativeAd: BZVNativeAd) {
}
}
@import UIKit;
@import BuzzvilSDK;
// 부가 기능: 광고 콜백 이벤트 수신 기능을 추가합니다.
@interface CustomFeedAdView () <BZVNativeAdEventDelegate>
@end
@implementation CustomFeedAdView
- (void)renderAd:(BZVNativeAd *)ad {
[_viewBinder bindWithNativeAd:ad];
ad.delegate = self;
}
#pragma mark - BZVNativeAdEventDelegate
- (void)didImpressAd:(BZVNativeAd *)nativeAd {
}
- (void)didClickAd:(BZVNativeAd *)nativeAd {
}
- (void)didRequestRewardForAd:(BZVNativeAd *)nativeAd {
}
- (void)didRewardForAd:(BZVNativeAd *)nativeAd withResult:(BZVRewardResult)result {
}
- (void)didParticipateAd:(BZVNativeAd *)nativeAd {
}
@end
BZVFeedConfig
에 위에서 작성한CustomFeedAdView
를 광고 뷰 홀더로 설정하세요.
- Swift
- Objective-C
let feedConfig = BZVFeedConfig { builder in
builder.unitId = "YOUR_FEED_UNIT_ID"
builder.adViewClass = CustomFeedAdView.self
}
BZVFeedConfig *config = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
builder.unitId = @"YOUR_FEED_UNIT_ID";
builder.adViewClass = [CustomFeedAdView class];
}];
쇼핑 적립 광고 디자인 자체 구현하기
쇼핑 적립 광고의 디자인을 변경하려면 다음의 절차를 따르세요.
- 일반 광고 디자인 자체 구현하기 토픽을 참고해
BZVFeedAdView
의 상속 클래스를 구현하세요.
- 일반 광고용 레이아웃에서
priceLabel
,originalPriceLabel
,discountPercentageLabel
을 추가해야 합니다.
- Swift
- Objective-C
import UIKit
import BuzzvilSDK
final class CustomFeedCpsAdView: BZVFeedAdView {
let nativeAdView = BZVNativeAdView(frame: .zero)
let mediaView = BZVMediaView(frame: .zero)
let iconImageView = UIImageView(frame: .zero)
let titleLabel = UILabel(frame: .zero)
let descriptionLabel = UILabel(frame: .zero)
let ctaView = BZVDefaultCtaView(frame: .zero)
let priceLabel = UILabel(frame: .zero)
let originalPriceLabel = UILabel(frame: .zero)
let discountRateLabel = UILabel(frame: .zero)
lazy var viewBinder = BZVNativeAdViewBinder { builder in
builder.nativeAdView = self.nativeAdView
builder.mediaView = self.mediaView
builder.iconImageView = self.iconImageView
builder.titleLabel = self.titleLabel
builder.descriptionLabel = self.descriptionLabel
builder.ctaView = self.ctaView
builder.clickableViews = [
self.mediaView,
self.ctaView,
self.priceLabel,
self.originalPriceLabel,
self.discountRateLabel,
]
}
override class func desiredHeight(_ width: CGFloat) -> CGFloat {
return 350
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUpView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setUpView()
}
private func setUpView() {
// 광고 레이아웃 컴포넌트를 생성합니다.
// ...생략...
nativeAdView.addSubview(priceLabel)
nativeAdView.addSubview(originalPriceLabel)
nativeAdView.addSubview(discountRateLabel)
// LayoutConstraint 설정
// ...생략...
}
override func renderAd(_ ad: BZVNativeAd) {
viewBinder.bind(with: ad)
let product = ad.product
if product.discountedPrice != 0 {
// 할인이 있는 쇼핑 광고
priceLabel.text = NSNumber(value: product.discountedPrice).formattedString()
originalPriceLabel.text = NSNumber(value: product.price).formattedString()
let discountRate = (1 - product.discountedPrice / product.price) * 100
discountRateLabel.text = String(format: "%d%%", Int(discountRate))
} else {
// 할인이 없는 쇼핑 광고
priceLabel.text = NSNumber(value: product.discountedPrice).formattedString()
originalPriceLabel.text = NSNumber(value: product.price).formattedString()
discountRateLabel.text = "0%%"
}
}
}
extension NSNumber {
func formattedString() -> String? {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
return numberFormatter.string(from: self)
}
}
@import UIKit;
@import BuzzvilSDK;
@interface CustomFeedCpsAdView : BZVFeedAdView
@end
@interface CustomFeedCpsAdView ()
@property (nonatomic, strong, readonly) BZVNativeAdView *nativeAdView;
@property (nonatomic, strong, readonly) BZVMediaView *mediaView;
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
@property (nonatomic, strong, readonly) UILabel *titleLabel;
@property (nonatomic, strong, readonly) UILabel *descriptionLabel;
@property (nonatomic, strong, readonly) BZVDefaultCtaView *ctaView;
@property (nonatomic, strong, readonly) UILabel *priceLabel;
@property (nonatomic, strong, readonly) UILabel *originalPriceLabel;
@property (nonatomic, strong, readonly) UILabel *discountRateLabel;
@property (nonatomic, strong, readonly) BZVNativeAdViewBinder *viewBinder;
@end
@implementation CustomFeedCpsAdView
+ (CGFloat)desiredHeight:(CGFloat)width {
return 350;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (void)setupView {
// 광고 레이아웃 컴포넌트를 생성합니다.
// ...생략...
_priceLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_priceLabel];
_originalPriceLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_originalPriceLabel];
_discountRateLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[_nativeAdView addSubview:_discountRateLabel];
_viewBinder = [BZVNativeAdViewBinder viewBinderWithBlock:^(BZVNativeAdViewBinderBuilder * _Nonnull builder) {
builder.nativeAdView = self.nativeAdView;
builder.mediaView = self.mediaView;
builder.titleLabel = self.titleLabel;
builder.ctaView = self.ctaView;
builder.clickableViews = @[
self.mediaView,
self.priceLabel,
self.originalPriceLabel,
self.discountRateLabel,
self.ctaView,
];
}];
// LayoutConstraint 설정
// ...생략...
}
- (void)renderAd:(BZVNativeAd *)ad {
[_viewBinder bindWithNativeAd:ad];
BZVNativeAdProduct *product = ad.product;
if (product.discountedPrice != 0) {
// 할인이 있는 쇼핑 광고
_priceLabel.text = [self formattedStringFromNumber:@(product.discountedPrice)];
_originalPriceLabel.text = [self formattedStringFromNumber:@(product.price)];
CGFloat discountRate = (1 - product.discountedPrice / product.price) * 100;
_discountRateLabel.text = [NSString stringWithFormat:@"%.f%%", discountRate];
} else {
// 할인이 없는 쇼핑 광고
_priceLabel.text = [self formattedStringFromNumber:@(product.price)];
_originalPriceLabel.text = [self formattedStringFromNumber:@(product.price)];
_discountRateLabel.hidden = YES;
}
}
- (NSString *)formattedStringFromNumber:(NSNumber *)number {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
return [formatter stringFromNumber:number];
}
@end
- 이전 단계에서 작성한
CustomFeedAdView
를BZVFeedConfig
에 쇼핑 광고 뷰 홀더로 설정하세요.
- Swift
- Objective-C
let config = BZVFeedConfig { builder in
builder.unitId = "YOUR_FEED_UNIT_ID"
builder.cpsAdViewClass = CustomFeedCpsAdView.self
}
BZVFeedConfig *config = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
builder.unitId = @"YOUR_FEED_UNIT_ID";
builder.cpsAdViewClass = [CustomFeedCpsAdView class];
}];
광고 미할당 안내 UI
광고 미할당 시 이탈을 막기 위해 유저는 3번까지 재시도하는 UX로 설계되어 있습니다. 광고 미할당 안내 UI에서는 각 재시도 회차별 UI 스트링과 이미지를 변경할 수 있습니다.
재시도 회차 | 제목 | 내용 | 버튼 |
---|---|---|---|
0회차 | 미션을 준비 중이에요 | 다시 미션을 불러와서 포인트를 모아보시겠어요? | 미션 불러오기 |
1회차 | 미션을 준비 중이에요 | 미션을 로딩 중이에요. 잠시 후 다시 시도해주세요. | 다시 불러오기 |
2회차 | 미션을 준비 중이에요 | 미션 준비에 시간이 걸리고 있습니다. 잠시 후 다시 시도해주세요. | 한번 더 불러오기 |
3회차(마지막) | 미션을 준비 중이에요 | 전체 필터: 지금은 참여 가능한 미션이 없습니다. 잠시 후 다시 방문해주세요. 그 외 필터: 지금은 참여 가능한 미션이 없습니다. 다른 미션에 참여해서 포인트를 모아보세요! | 전체 필터: 나중에 다시 올게요 그 외 필터: 다른 미션 참여하기 |
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.noFillErrorImage = ...
builder.noFillErrorTitle = ...
builder.noFillErrorDescription1st = ...
builder.noFillErrorDescription2nd = ...
builder.noFillErrorDescription3rd = ...
builder.noFillErrorDescriptionFinalAllFilter = ...
builder.noFillErrorDescriptionFinalOtherFilters = ...
builder.noFillErrorButton1st = ...
builder.noFillErrorButton2nd = ...
builder.noFillErrorButton3rd = ...
builder.noFillErrorButtonFinalAllFilter = ...
builder.noFillErrorButtonFinalOtherFilters = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.noFillErrorImage = ...;
builder.noFillErrorTitle = ...;
builder.noFillErrorDescription1st = ...;
builder.noFillErrorDescription2nd = ...;
builder.noFillErrorDescription3rd = ...;
builder.noFillErrorDescriptionFinalAllFilter = ...;
builder.noFillErrorDescriptionFinalOtherFilters = ...;
builder.noFillErrorButton1st = ...;
builder.noFillErrorButton2nd = ...;
builder.noFillErrorButton3rd = ...;
builder.noFillErrorButtonFinalAllFilter = ...;
builder.noFillErrorButtonFinalOtherFilters = ...;
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
유저 프로필 오류 안내 UI
유저 프로필이 설정되지 않았을 때 유저에게 노출되는 화면의 UI 스트링과 이미지를 변경할 수 있습니다.
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.userProfileErrorImage = ...
builder.userProfileErrorTitle = ...
builder.userProfileErrorDescription = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.userProfileErrorImage = ...;
builder.userProfileErrorTitle = ...;
builder.userProfileErrorDescription = ...;
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
기타 오류 화면 UI
기타 오류 화면별 이미지를 변경할 수 있습니다.
속성 | 설명 |
---|---|
privacyPolicyErrorIcon | 개인정보 제3자 제공 동의를 받아야 하는 경우 노출되는 이미지를 변경합니다. |
agePolicyErrorIcon | 네트워크 에러 발생 시 노출되는 이미지를 변경합니다. |
networkErrorIcon | 네트워크 에러 발생 시 노출되는 이미지를 변경합니다. |
unknownErrorIcon | 알 수 없는 오류 발생 시 노출되는 이미지를 변경합니다. |
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.privacyPolicyErrorImage = ...
builder.agePolicyErrorImage = ...
builder.networkErrorImage = ...
builder.unknownErrorImage = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.privacyPolicyErrorImage = ...;
builder.agePolicyErrorImage = ...;
builder.networkErrorImage = ...;
builder.unknownErrorImage = ...;
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
ATT 허용 유도 모달
iOS 14 이상에서 앱 활동 추적 권한을 허용하지 않은 유저에게 권한 허용을 유도하는 모달의 이미지를 변경할 수 있습니다.
- Swift
- Objective C
let feedTheme = BZVFeedTheme { builder in
builder.appTrackingTransparencyGuideModalImage = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)
BZVFeedTheme *feedTheme = [BZVFeedTheme themeWithBlock:^(BZVFeedThemeBuilder * _Nonnull builder) {
builder.appTrackingTransparencyGuideModalImage = ...;
}];
[BZVBuzzAdFeed setDefaultTheme:feedTheme];
인터스티셜
주요 UI의 색상(Primary color)을 변경할 수 있는 GlobalTheme
을 사용해 진입 경로 레이아웃의 베네핏허브 진입 유도 문구 색상, CTA 버튼 배경 색상과 리워드 아이콘이 함께 변경됩니다. 자세한 내용은 전체 테마 토픽을 참고하세요.