「SDK 8 Mopub Mediation Native」修訂間的差異

出自TAMedia
跳至導覽 跳至搜尋
imported>Wikiuser
imported>Wikiuser
行 93: 行 93:


== TAMediaCustomNativeAdRenderer(必要) ==
== TAMediaCustomNativeAdRenderer(必要) ==
此 class 需實做 MPNativeAdRenderer protocol,用於設置客製化事件處理的 class (TAMediaCustomNativeAdEvent) 以及將由 adapter 取得的 Dictionary 呈現到所需的 adView 內並回傳<br>
此 class 需實做 MPNativeAdRenderer protocol,用於提供實際所要呈現的廣告視圖的 class<br>
#實作<code>+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings</code>建立 MPNativeAdRendererConfiguration物件<br>
#實作<code>+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings</code>建立 MPNativeAdRendererConfiguration物件<br>
#設置 rendering class 為本身class<br>
#設置 rendering class 為本身class<br>

於 2021年8月24日 (二) 01:44 的修訂

官方教學:連結
NativeAd 需要建立4個客製化class來串接廣告,其中 TAMediaCustomNativeAdEventSetting 為非必要,其他三個都必須加入專案內。

回MoPub教學

TAMediaCustomNativeAdEventAdapter(必要)

此 class 是作為 TADNativeAd 與 MPNativeAd 的橋樑,將 TAmdia 得到的 TADNativeAd 提供給 mopub 建立 MPNativeAd

  1. 建立一class實做 MPNativeAdAdapter protocol,protocol 有兩必須實作 property:properties 及 defaultActionURL
  2. 建立初始化方法,將TADNativeAd 及 TADNativeAdView 作為參數帶入,將由 TADNativeAd 拿到的 TADNativeAdContent 與 MPNativeAdConstants.h 提供的 key 值建立相對應的 dictionary 後賦予給 proerties
  3. defaultActionURL 則回傳 nil,點擊的部分將交由 TADNativeAdView 處理
  4. 實作displayContentForURL:rootViewController:completion:當 user 點擊時觸發

參考以下代碼

#import <Foundation/Foundation.h>
#import <MoPub/MoPub.h>
#import <TAMediaAdsFramework/TAMediaAdsFramework.h>

@interface TAMediaCustomNativeAdEventAdapter : NSObject <MPNativeAdAdapter>

- (instancetype)initTADNativeAd:(TADNativeAd *)nativeAd withNativeView: (TADNativeAdView *)nativeAdView;

@property (nonatomic, readonly) NSDictionary *properties;
@property (nonatomic, readonly) NSURL *defaultActionURL;
@property (nonatomic, strong) TADNativeAdView *nativeAdView;
@property (nonatomic, weak) id<MPNativeAdAdapterDelegate> delegate;

@end
#import "TAMediaCustomNativeAdEventAdapter.h"
#import <MoPub/MoPub.h>

@interface TAMediaCustomNativeAdEventAdapter () <TADNativeAdDelegate>

@property (nonatomic,strong) TADNativeAd *nativeAd;

@end

@implementation TAMediaCustomNativeAdEventAdapter 

- (instancetype)initTADNativeAd:(TADNativeAd *)nativeAd withNativeView: (TADNativeAdView *)nativeAdView {
    self = [super init];
    TADNativeAdContent *adContent = nativeAd.adContent;
    nativeAd.delegate = self;
    self.nativeAd = nativeAd;
    self.nativeAdView = nativeAdView;
    _properties = @{kAdTitleKey: adContent.longSubject,
                    kAdTextKey: adContent.body,
                    kAdCTATextKey: adContent.callToAction,
                    kAdIconImageKey: adContent.iconSquare.image,
                    kAdMainMediaViewKey: nativeAdView.mediaView};
    return self;
}


#pragma mark - MPNativeAdAdapter
- (BOOL)enableThirdPartyClickTracking {
    return YES;
}

- (UIView *)mainMediaView {
    return self.nativeAdView.mediaView;
}

- (NSURL *)defaultActionURL {
    return nil;
}

#pragma mark - TADNativeAdDelegate
- (void)nativeAdDidClick:(TADNativeAd *)ad {
    [self.delegate nativeAdDidClick:self];
    MPLogAdEvent([MPLogEvent adTappedForAdapter:NSStringFromClass(self.class)], nil);
    [self.delegate nativeAdWillPresentModalForAdapter:self];
}

- (void)nativeAdDidImpression:(TADNativeAd *)ad {
    [self.delegate nativeAdWillLogImpression:self];
    MPLogAdEvent([MPLogEvent adShowSuccessForAdapter:NSStringFromClass(self.class)], nil);
    MPLogAdEvent([MPLogEvent adDidAppearForAdapter:NSStringFromClass(self.class)], nil);
}

- (void)adViewWillLeaveApplication:(TADNativeAd *)adView {
    if ([self.delegate respondsToSelector:@selector(nativeAdWillLeaveApplicationFromAdapter:)]) {
        [self.delegate nativeAdWillLeaveApplicationFromAdapter:self];
    }
    MPLogAdEvent([MPLogEvent adWillLeaveApplicationForAdapter:NSStringFromClass(self.class)], nil);
}

@end

TAMediaCustomNativeAdRenderer(必要)

此 class 需實做 MPNativeAdRenderer protocol,用於提供實際所要呈現的廣告視圖的 class

  1. 實作+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings建立 MPNativeAdRendererConfiguration物件
  2. 設置 rendering class 為本身class
  3. 設置 rendererSettings 為參數傳入 的rendererSettings
  4. 設置 supportedCustomEvents 為 TAMediaCustomNativeAdEvent class
  5. 實作initWithRendererSettings:設置物件viewSizeHandler,以及任何客製化設定
  6. 實作retrieveViewWithAdapter:回傳要來呈顯在畫面上的 View

參考以下代碼

#import <Foundation/Foundation.h>
#import <MoPub/MoPub.h>

@interface TAMediaCustomNativeAdRenderer : NSObject <MPNativeAdRenderer>
@property (nonatomic, readonly) MPNativeViewSizeHandler viewSizeHandler;

@end
#import "TAMediaCustomNativeAdRenderer.h"
#import "TAMediaCustomNativeAdEventAdapter.h"
#import <MoPub/MoPub.h>
#import "MPNativeAdView.h"

@interface TAMediaCustomNativeAdRenderer()

@property (nonatomic,strong) id<MPNativeAdRendererSettings>setting;

@property (nonatomic,strong) MPNativeAdRendererImageHandler *rendererImageHandler;
@property(nonatomic, strong) Class renderingViewClass;

@end

@implementation TAMediaCustomNativeAdRenderer

+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings {
    MPNativeAdRendererConfiguration *config = [[MPNativeAdRendererConfiguration alloc] init];
    config.rendererSettings = rendererSettings;
    config.supportedCustomEvents = @[@"TAMediaCustomNativeAdEvent"];//設置客製化事件處理的class
    config.rendererClass = [self class];
    return config;
}

- (instancetype)initWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings {
    self = [super init];
    MPStaticNativeAdRendererSettings *settings =
        (MPStaticNativeAdRendererSettings *)rendererSettings;
    _viewSizeHandler = [rendererSettings.viewSizeHandler copy];
    self.setting = rendererSettings;
    _renderingViewClass = settings.renderingViewClass;
    return self;
}

- (UIView *)retrieveViewWithAdapter:(id<MPNativeAdAdapter>)adapter error:(NSError **)error {
    
    MPLogAdEvent([MPLogEvent adShowAttemptForAdapter:NSStringFromClass(self.class)], nil);
    MPLogAdEvent([MPLogEvent adWillAppearForAdapter:NSStringFromClass(self.class)], nil);  
    
    UIView<MPNativeAdRendering> *mpNativeAdView = [self.renderingViewClass new];
    mpNativeAdView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    
    TAMediaCustomNativeAdEventAdapter *tadAdpater = (TAMediaCustomNativeAdEventAdapter *)adapter;
    TADNativeAdView *tadNativeAdView = tadAdpater.nativeAdView;
    tadNativeAdView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    [tadNativeAdView addSubview:mpNativeAdView];
    [self fillSuperview:mpNativeAdView];
    
    if([mpNativeAdView respondsToSelector:@selector(nativeTitleTextLabel)]) {
        [mpNativeAdView.nativeTitleTextLabel addSubview:tadNativeAdView.longSubjectLabel];
        mpNativeAdView.nativeTitleTextLabel.text = adapter.properties[kAdTitleKey];
        mpNativeAdView.nativeTitleTextLabel.userInteractionEnabled = YES;
        tadNativeAdView.longSubjectLabel.userInteractionEnabled = YES;
        [self fillSuperview:tadNativeAdView.longSubjectLabel];
    }
    
    if([mpNativeAdView respondsToSelector:@selector(nativeMainTextLabel)]) {
        [mpNativeAdView.nativeMainTextLabel addSubview:tadNativeAdView.bodyLabel];
        mpNativeAdView.nativeMainTextLabel.text = adapter.properties[kAdTextKey];
        mpNativeAdView.nativeMainTextLabel.userInteractionEnabled = YES;
        tadNativeAdView.bodyLabel.userInteractionEnabled = YES;
        [self fillSuperview:tadNativeAdView.bodyLabel];
    }
    
    if([mpNativeAdView respondsToSelector:@selector(nativeCallToActionTextLabel)] && mpNativeAdView.nativeCallToActionTextLabel) {
        [mpNativeAdView.nativeCallToActionTextLabel addSubview:tadNativeAdView.callToActionView];
        mpNativeAdView.nativeCallToActionTextLabel.text = adapter.properties[kAdCTATextKey];
        mpNativeAdView.nativeCallToActionTextLabel.userInteractionEnabled = YES;
        tadNativeAdView.callToActionView.userInteractionEnabled = YES;
        [self fillSuperview:tadNativeAdView.callToActionView];
    }
    
    if([mpNativeAdView respondsToSelector:@selector(nativeIconImageView)]) {
        [mpNativeAdView.nativeIconImageView addSubview:tadNativeAdView.squareImgeView];
        mpNativeAdView.nativeIconImageView.image = adapter.properties[kAdIconImageKey];
        mpNativeAdView.nativeIconImageView.userInteractionEnabled = YES;
        tadNativeAdView.squareImgeView.userInteractionEnabled = YES;
        [self fillSuperview:tadNativeAdView.squareImgeView];
    }
    
    if([mpNativeAdView respondsToSelector:@selector((nativeMainImageView))]) {
        tadNativeAdView.mediaView.frame = mpNativeAdView.nativeMainImageView.bounds;
        [mpNativeAdView.nativeMainImageView addSubview:tadNativeAdView.mediaView];
        mpNativeAdView.nativeMainImageView.userInteractionEnabled = YES;
        [self fillSuperview:tadNativeAdView.mediaView];
    }
    
    MPLogAdEvent([MPLogEvent adShowAttemptForAdapter:NSStringFromClass(self.class)], nil);
      MPLogAdEvent([MPLogEvent adWillAppearForAdapter:NSStringFromClass(self.class)], nil);
    return tadNativeAdView;
}

- (void)fillSuperview:(UIView *)view {
    view.frame = view.superview.bounds;
}

@end

TAMediaCustomNativeAdEvent(必要)

此 class 需繼承 MPNativeCustomEvent,用來取得 TAmedia native ad 提供給 MoPub

  1. 建立 class 繼承 MPNativeCustomEvent
  2. 複寫 - (void)requestAdWithCustomEventInfo:(NSDictionary *)info在此用 TADNativeAd 去取得廣告
  3. 取得廣告後用取得的 Dictionary 建立 TAMediaCustomNativeAdEventAdapter 後再用 adapter 建立MPNativeAd
  4. 呈現廣告前先呼叫父類別precacheImagesWithURLs:completionBlock:取得image後,再呼叫customNativeEvent:didLoadAd:
#import <MoPub/MoPub.h>
#import <TAMediaAdsFramework/TAMediaAdsFramework.h>

@interface TAMediaCustomNativeAdEvent : MPNativeCustomEvent <TADNativeAdDelegate>

@property (nonatomic,strong) TADNativeAd *nativeAd;

@end
#import "TAMediaCustomNativeAdEvent.h"
#import "TAMediaCustomNativeAdEventAdapter.h"
#import <MoPub/MoPub.h>


@interface TAMediaCustomNativeAdEvent()
@property (nonatomic,strong) NSString *adUnitId;
@end

@implementation TAMediaCustomNativeAdEvent

- (void)requestAdWithCustomEventInfo:(NSDictionary *)info adMarkup:(NSString *)adMarkup {
    self.adUnitId = info[@"NativeListId"];
    if (self.adUnitId == nil) {
        MPLogAdEvent([MPLogEvent adLoadFailedForAdapter:NSStringFromClass(self.class)
                                                    error:MPNativeAdNSErrorForInvalidAdServerResponse(@"Ad unit ID cannot be nil.")], self.adUnitId);
        [self.delegate nativeCustomEvent:self
                didFailToLoadAdWithError:MPNativeAdNSErrorForInvalidAdServerResponse(
                                             @"Ad unit ID cannot be nil.")];
        return;
      }
    
    TADRequest *request = [TADRequest request];
    request.testing = NO;
    // Type: TADGender
    request.gender = kTADGenderUnknown;
    
    // NAD 物件初始化, 帶入自訂的origin
    if (!self.nativeAd) {
        self.nativeAd = [[TADNativeAd alloc] initWithAdUnitId: self.adUnitId];
    }
    // 必須要設定delegate
    self.nativeAd.delegate = self;
    
    MPLogAdEvent([MPLogEvent adLoadAttemptForAdapter:NSStringFromClass(self.class) dspCreativeId:nil dspName:nil], self.adUnitId);

    // 載入廣告
    [self.nativeAd loadRequest:request];
}

- (void)nativeAdDidReceiveAd:(TADNativeAd *)ad {

    MPLogAdEvent([MPLogEvent adLoadSuccessForAdapter:NSStringFromClass(self.class)], self.adUnitId);
    
    TADNativeAdView *nativeView = [TADNativeAdView new];
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    UILabel *bodyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    UILabel *callToActionView = [[UILabel alloc] initWithFrame: CGRectZero];
    UIImageView *smallImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
    UIImageView *bigImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
    TADNativeMediaView *mediaView = [[TADNativeMediaView alloc] initWithFrame:CGRectZero];
    mediaView.mediaContent = ad.adContent.mediaContent;

    [nativeView addSubview:titleLabel];
    [nativeView addSubview:subTitleLabel];
    [nativeView addSubview:bodyLabel];
    [nativeView addSubview:callToActionView];
    [nativeView addSubview:smallImageView];
    [nativeView addSubview:bigImageView];
    [nativeView addSubview:mediaView];
    
    nativeView.longSubjectLabel = titleLabel;
    nativeView.shortSubjectLabel = subTitleLabel;
    nativeView.bodyLabel = bodyLabel;
    nativeView.callToActionView = callToActionView;
    nativeView.squareImgeView = smallImageView;
    nativeView.rectangleImgeView = bigImageView;
    nativeView.mediaView = mediaView;
    
    nativeView.nativeAd = ad;
    
    // 表示本次請求收到廣告
    TAMediaCustomNativeAdEventAdapter *adapter = [[TAMediaCustomNativeAdEventAdapter alloc] initTADNativeAd:ad withNativeView:nativeView];
    MPNativeAd *mpNativeAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
    [self.delegate nativeCustomEvent:self didLoadAd:mpNativeAd];
}

- (void)nativeAd:(TADNativeAd *)ad didFailToReceiveAdWithError:(TADRequestError *)error {
    MPLogAdEvent([MPLogEvent adLoadFailedForAdapter:NSStringFromClass(self.class) error:error], self.adUnitId);

    if ([self.delegate respondsToSelector:@selector(nativeCustomEvent:didFailToLoadAdWithError:)]) {
        [self.delegate nativeCustomEvent:self didFailToLoadAdWithError:error];
    }


@end

TAMediaCustomNativeAdEventSetting

此class需實做MPNativeAdRendererSettings protocol,用來設定 viewSize,與指定需要來呈現廣告的 View,亦可使用 MPNativeAdRendererSettings 取代

  //  TAMediaCustomNativeAdEventSetting.h
  #import <Foundation/Foundation.h>
  #import <MoPub/MoPub.h>
  @interface TAMediaCustomNativeAdEventSetting : NSObject <MPNativeAdRendererSettings>
  
  @property (nonatomic, assign) Class renderingViewClass;
  
  @property (nonatomic, readwrite, copy) MPNativeViewSizeHandler viewSizeHandler;
  @end
  //  TAMediaCustomNativeAdEventSetting.m
  #import "TAMediaCustomNativeAdEventSetting.h"
  @implementation TAMediaCustomNativeAdEventSetting
  @end