Native Ad

1. 기본 요건

  • ADX iOS SDK를 프로젝트에 추가합니다.

  • Native Ad용으로 발급받은 Ad Unit ID를 사용합니다.

  • 광고를 요청하기 전에 SDK 초기화를 먼저 진행합니다.

    • SDK 초기화는 앱 실행 시 한 번만 호출하여 주시고, 광고 요청은 초기화가 완료된 후에 이뤄져야 합니다.

    • iOS 14 이상 지원하는 경우, ATT(App Tracking Transparency) 권한 요청 완료 후 광고를 요청해주세요.

2. 레이아웃 설정

Native Ad의 경우, 광고에 사용 될 레이아웃을 직접 구성해야 합니다. 필수 구성 요소들은 다음과 같습니다.

  • Title : UILabel

  • Main Text : UILabel

  • Call-To-Action : UIButton

  • Icon Image : UIImageView

  • Main Image : UIImageView

  • Privacy Icon : UIImageView

  • Ad Tag : UIView (UILabel 또는 UIImageView)

Ad Tag 요소는 "Ad" 또는 "Advertisement" 문자열을 보여주는 UI 구성 요소를 포함하여, 광고라는 것을 명확하게 사용자에게 인식을 시켜야 합니다. 이 요소가 포함되지 않으면, 일부 광고 네트워크의 광고 송출이 중단될 수 있습니다.

2.1.0 버전부터 Native Ad의 CTA (Call-To-Action)가 UILabel에서 UIButton으로 변경 되었습니다.

이 요소들은 반드시 포함하여 구성하여 주시고, 광고 컨텐츠를 덮는 View가 없어야 합니다. 또한 텍스트 변경, 이미지 변경, 터치 시 액션 변경 등 광고 컨텐츠에 관련된 부분을 가공하거나 변경하지 않도록 주의 부탁드립니다.

// NativeAdView.h

#import <ADXLibrary/ADXNativeAdRendering.h>

@interface NativeAdView : UIView <ADXNativeAdRendering>
        
@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@property (nonatomic, weak) IBOutlet UILabel *mainTextLabel;
@property (nonatomic, weak) IBOutlet UIButton *callToActionButton;
@property (nonatomic, weak) IBOutlet UIImageView *iconImageView;
@property (nonatomic, weak) IBOutlet UIImageView *mainImageView;
@property (nonatomic, weak) IBOutlet UIImageView *privacyInformationIconImageView;
        
@end

// NativeAdView.m

@implementation NativeAdView

- (void)layoutSubviews {
    [super layoutSubviews];
}

- (UILabel *)nativeMainTextLabel {
    return self.mainTextLabel;
}

- (UILabel *)nativeTitleTextLabel {
    return self.titleLabel;
}

- (UIButton *)nativeCallToActionButton {
    return self.callToActionButton;
}

- (UILabel *)nativeSponsoredByCompanyTextLabel {
    return self.sponsoredByLabel;
}

- (UIImageView *)nativeIconImageView {
    return self.iconImageView;
}

- (UIImageView *)nativeMainImageView {
    return self.mainImageView;
}

- (UIImageView *)nativePrivacyInformationIconImageView {
    return self.privacyInformationIconImageView;
}

@end

3. 구현

Native Ad는 다음 2가지 방법 중 하나로 광고를 로드할 수 있습니다.

Case 1: 하나의 View를 사용하는 경우

  1. ADXNativeAdFactorysetRenderingViewClass:renderingViewClass:메서드를 사용하여 RenderingViewClass를 구성합니다.

  2. ADXNativeAdFactoryDelegate callback을 등록합니다.

  3. ADXNativeAdFactoryDelegateloadAd를 호출하여 광고를 로드합니다.

  4. 광고 로드가 완료되면 ADXNativeAdFactoryDelegateonSuccess:nativeAd:가 호출됩니다.

#import "NativeAdViewController"
#import "NativeAdView.h"

#import <ADXLibrary/ADXNativeAdFactory.h>

@interface NativeAdViewController () <ADXNativeAdFactoryDelegate, ADXNativeAdDelegate>

@property (strong) ADXNativeAd *nativeAd;

@end

@implementation NativeAdViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[ADXNativeAdFactory sharedInstance] 
        setRenderingViewClass:@"<ADX_NATIVE_AD_UNIT_ID>" 
        renderingViewClass:[NativeAdView class]];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[ADXNativeAdFactory sharedInstance] addDelegate:self];
    [[ADXNativeAdFactory sharedInstance] loadAd:@"<ADX_NATIVE_AD_UNIT_ID>"];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[ADXNativeAdFactory sharedInstance] removeDelegate:self];
}

#pragma mark - ADXNativeAdFactoryDelegate

- (void)onSuccess:(NSString *)adUnitId nativeAd:(ADXNativeAd *)nativeAd {
    NSLog(@"onSuccess : %@", adUnitId);

    if([adUnitId isEqualToString:ADX_NATIVE_AD_UNIT_ID]) {
        self.nativeAd = nativeAd;
        self.nativeAd.delegate = self;

        UIView *nativeAdView = [[ADXNativeAdFactory sharedInstance] 
            getNativeAdView:@"<ADX_NATIVE_AD_UNIT_ID>"];

        nativeAdView.frame = CGRectMake(0.0,
                                        100.0,
                                        320.0,
                                        300.0);
        [self.view addSubview:nativeAdView];
    }
}

- (void)onFailure:(NSString *)adUnitId {
    NSLog(@"onFailure : %@", adUnitId);
}

#pragma mark - ADXNativeAdDelegate

- (UIViewController *)viewControllerForPresentingModalView {
    return self;
}

@end

Case 2: UITableView / UICollectionView에서 AdPlacer를 사용하는 경우

  1. ADXNativeAdFactorysetRenderingViewClass:renderingViewClass: 메서드를 사용하여 RenderingViewClass를 구성합니다.

  2. 로드할 광고의 크기를 설정합니다.

    • 광고의 크기는 xib파일에서 사이즈를 지정하시거나 frame으로 세팅해주셔야 합니다.

  3. ADXAdPositioning을 이용하여 고정 및 반복 위치를 지정합니다.

    • addFixedIndexPath: 고정할 광고 위치

    • enableRepeatingPositionsWithInterval: 광고 반복 위치

  4. loadAdsForAdUnitID: 를 호출하여 광고를 로드합니다.

#import "NativeAdPlacerViewController.h"
#import "NativeAdView.h"

#import <ADXLibrary/ADXNativeAdFactory.h>

@interface NativeAdPlacerViewController () <UICollectionViewDataSource, UICollectionViewDelegate, ADXCollectionViewAdPlacerDelegate>

@property (weak) IBOutlet UICollectionView *colltionView;
@property (strong) ADXCollectionViewAdPlacer *placer;

@end

@implementation NativeAdPlacerViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [[ADXNativeAdFactory sharedInstance] 
        setRenderingViewClass:@"<ADX_NATIVE_AD_UNIT_ID>" 
        renderingViewClass:[NativeAdView class]];
    
    // 광고 고정 및 반복 위치 지정 
    ADXAdPositioning *adPositioning = [ADXAdPositioning positioning];
    [adPositioning addFixedIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [adPositioning enableRepeatingPositionsWithInterval:3];
    
    self.placer = [[ADXNativeAdFactory sharedInstance] 
        getCollectionViewAdPlacer:@"<ADX_NATIVE_AD_UNIT_ID>"
        collectionView:self.colltionView
        viewController:self
        adPositioning:adPositioning];
        
    [self.placer loadAdsForAdUnitID:@"<ADX_NATIVE_AD_UNIT_ID>"];
}

Cell의 position 정보가 달라지기 때문에, UITableViewADXTableViewAdPlacer.h, UICollectionViewADXCollectionViewAdPlacer.h 파일을 참고하시어 대체 메서드를 사용해주시기 바랍니다.

4. Ad Revenue (paidEventHandler)

광고 노출에 대한 예상 광고 수익을 확인할 수 있습니다.

  • 이 기능은 iOS ADX SDK 2.6.2 이상 버전을 사용하시는 것이 권장됩니다.

  • 아래 예제와 같이' paidEventHandler' 를 사용하여 예상되는 eCPM 값을 확인할 수 있습니다.

  • 'ADXCollectionViewAdPlacer' 및 'ADXTableViewAdPlacer' 를 사용하는 경우, 이 기능은 지원되지 않습니다.

  • 미디에이션 설정 과정에서 수동적으로 설정한 값과 정확한 값이 섞여 있어서 예상 값으로 사용하시는 것을 권장드립니다.

  • eCPM의 통화(Currency) 단위는 USD입니다.

  • AdJust의 광고 매출 데이터 연동을 지원합니다. 상세한 내용은 AdJust의 AD(X) SDK 연동 가이드를 확인 부탁드립니다.

#import <UIKit/UIKit.h>
#import <ADXLibrary/ADXNativeAdFactory.h>
#import "NativeAdViewController.h"
#import "NativeAdView.h"
#import <FirebaseAnalytics/FirebaseAnalytics.h>
#import <AppsFlyerAdRevenue/AppsFlyerAdRevenue.h>

@interface NativeAdViewController () <ADXNativeAdFactoryDelegate, ADXNativeAdDelegate>
@property (nonatomic, strong) ADXNativeAd *nativeAd;
@end

@implementation NativeAdViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[ADXNativeAdFactory sharedInstance] 
        setRenderingViewClass:@"<ADX_NATIVE_AD_UNIT_ID>" 
        renderingViewClass:[NativeAdView class]];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[ADXNativeAdFactory sharedInstance] addDelegate:self];
    [[ADXNativeAdFactory sharedInstance] loadAd:@"<ADX_NATIVE_AD_UNIT_ID>"];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];    
    [[ADXNativeAdFactory sharedInstance] removeDelegate:self];
}

- (void)handleAdRevenue:(NSNumber *)revenue {
    // 1) Firebase Analytics
    [FIRAnalytics logEventWithName:kFIREventAdImpression
                        parameters: @{
        kFIRParameterAdPlatform: @"AD(X)",
        kFIRParameterAdFormat: @"NativeAd",
        kFIRParameterAdUnitName: @"ADX Native Ad",
        kFIRParameterCurrency: @"USD",
        kFIRParameterValue: revenune
    }];
    
    // 2) AppsFlyer
    NSDictionary * adRevenueParams = @{
        @"AdUnitName" : @"ADX Native Ad",
        @"AdType" : @"NativeAd",
    };
    
    AppsFlyerAdRevenue * appsFlyerAdRevenue = [AppsFlyerAdRevenue shared];
    [appsFlyerAdRevenue 
        logAdRevenueWithMonetizationNetwork:@"AD(X)"
        mediationNetwork:AppsFlyerAdRevenueMediationNetworkTypeCustom
        eventRevenue:revenune
        revenueCurrency:@"USD"
        additionalParameters:adRevenueParams];
}

#pragma mark - ADXNativeAdFactoryDelegate

- (void)onSuccess:(NSString *)adUnitId nativeAd:(ADXNativeAd *)nativeAd {
    NSLog(@"onSuccess : %@", adUnitId);

    if([adUnitId isEqualToString:@"<ADX_NATIVE_AD_UNIT_ID>"]) {
        self.nativeAd = nativeAd;
        self.nativeAd.delegate = self;
        
        __weak typeof(self) weakSelf = self;
        self.nativeAd.paidEventHandler = ^(double eCPM) {
            __strong typeof(self) strongSelf = weakSelf;
            if(!strongSelf) { return; }
            NSNumber * revenue = [NSNumber numberWithDouble:eCPM/1000];
            [strongSelf handleAdRevenue:revenue];
        };

        UIView *nativeAdView = [[ADXNativeAdFactory sharedInstance] 
            getNativeAdView:@"<ADX_NATIVE_AD_UNIT_ID>"];

        nativeAdView.frame = CGRectMake(0.0,
                                        100.0,
                                        320.0,
                                        300.0);
        [self.view addSubview:nativeAdView];
    }
}

- (void)onFailure:(NSString *)adUnitId {
    NSLog(@"onFailure : %@", adUnitId);
}

#pragma mark - ADXNativeAdDelegate

- (UIViewController *)viewControllerForPresentingModalView {
    return self;
}

@end

Last updated