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

出自TAMedia
跳至導覽 跳至搜尋
imported>Wikiuser
(新頁面: 官方教學:[https://developers.mopub.com/networks/integrate/build-adapters-ios/#quick-start-for-native-ads 連結]<br> NativeAd 需要建立4個客製化class來串接廣告,其...)
 
imported>Wikiuser
行 6: 行 6:
== TAMediaCustomNativeAdEventAdapter(必要) ==
== TAMediaCustomNativeAdEventAdapter(必要) ==
此 class 是作為 TADNativeAd 與 MPNativeAd 的橋樑,將 TADNativeAd 轉換為 MPNativeAd 所需要的 Dictionary <br>
此 class 是作為 TADNativeAd 與 MPNativeAd 的橋樑,將 TADNativeAd 轉換為 MPNativeAd 所需要的 Dictionary <br>
1.建立一class實做 MPNativeAdAdapter protocol,protocol 有兩必須實作 property:properties 及 defaultActionURL<br>
#建立一class實做 MPNativeAdAdapter protocol,protocol 有兩必須實作 property:properties 及 defaultActionURL<br>
2.建立初始化方法,將TAMedia native ad作為參數帶入,將由 TAMeida native ad 拿到的 dictionary 與 MPNativeAdConstants.h 提供的 key 值建立相對應的 dictionary 後賦予給 proerties <br>
#建立初始化方法,將TADNativeAd 及 TADNativeAdView 作為參數帶入,將由 TADNativeAd 拿到的 TADNativeAdContent 與 MPNativeAdConstants.h 提供的 key 值建立相對應的 dictionary 後賦予給 proerties <br>
3.defaultActionURL 則為 TAmedia 拿到的 nurl<br>
#defaultActionURL 則回傳 nil,點擊的部分將交由 TADNativeAdView 處理<br>
4.實作<code>displayContentForURL:rootViewController:completion:</code>當 user 點擊時觸發<br>
#實作<code>displayContentForURL:rootViewController:completion:</code>當 user 點擊時觸發<br>
參考以下代碼<br>
參考以下代碼<br>
  //  TAMediaCustomNativeAdEventAdapter.h
<source>
  #import <Foundation/Foundation.h>
#import <Foundation/Foundation.h>
  #import <MoPub/MoPub.h>
#import <MoPub/MoPub.h>
  #import <TAMediaAdsFramework/TAMediaAdsFramework.h>
#import <TAMediaAdsFramework/TAMediaAdsFramework.h>
 
  @interface TAMediaCustomNativeAdEventAdapter : NSObject <MPNativeAdAdapter>
 
  - (instancetype)initWithTADNativeAd:(TADNativeAd *)nativeAd;
 
  @property (nonatomic, readonly) NSDictionary *properties;
  @property (nonatomic, readonly) NSURL *defaultActionURL;
  @property (nonatomic, weak) id<MPNativeAdAdapterDelegate> delegate;
  @end


  //  TAMediaCustomNativeAdEventAdapter.m
@interface TAMediaCustomNativeAdEventAdapter : NSObject <MPNativeAdAdapter>
  #import "TAMediaCustomNativeAdEventAdapter.h"
 
 
- (instancetype)initTADNativeAd:(TADNativeAd *)nativeAd withNativeView: (TADNativeAdView *)nativeAdView;
  @interface TAMediaCustomNativeAdEventAdapter () <TADNativeAdDelegate>
 
  @property (nonatomic,strong) TADNativeAd *nativeAd;
@property (nonatomic, readonly) NSDictionary *properties;
  @end
@property (nonatomic, readonly) NSURL *defaultActionURL;
 
@property (nonatomic,strong) TADNativeAdView *nativeAdView;
  @implementation TAMediaCustomNativeAdEventAdapter  
@property (nonatomic, weak) id<MPNativeAdAdapterDelegate> delegate;
   
 
  - (instancetype)initWithTADNativeAd:(TADNativeAd *)nativeAd {
@end
</source>
 
<source>
#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];
     self = [super init];
     NSDictionary *tadDic = [nativeAd getNativeAdContent];
     TADNativeAdContent *adContent = nativeAd.adContent;
     nativeAd.delegate = self;
     nativeAd.delegate = self;
     self.nativeAd = nativeAd;
     self.nativeAd = nativeAd;
     self = [self initWithTADic:tadDic];
     self.nativeAdView = nativeAdView;
    _properties = @{kAdTitleKey: adContent.longSubject,
                    kAdTextKey: adContent.body,
                    kAdCTATextKey: adContent.callToAction,
                    kAdIconImageKey: adContent.iconSquare.image,
                    kAdMainMediaViewKey: nativeAdView.mediaView};
     return self;
     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];
     }
     }
  - (instancetype)initWithTADic:(NSDictionary *)taDic {
     MPLogAdEvent([MPLogEvent adWillLeaveApplicationForAdapter:NSStringFromClass(self.class)], nil);
      self = [super init];
}
      NSDictionary *taMeidaDicMapping = @{@"LONGSUBJECT":kAdTitleKey,
 
                                        @"BODY":kAdTextKey,
@end
                                        @"ICONSQUARE":kAdIconImageKey,
                                        @"IMAGE1200X627":kAdMainImageKey,
                                        @"VIDEO":kVASTVideoKey,
                                        @"nurl":kDefaultActionURLKey,
                                        @"CTA":kAdCTATextKey
                                        };
   
    NSMutableDictionary *dic = [NSMutableDictionary new];
    for (NSString *key in taDic.allKeys) {
        NSString *newKey = taMeidaDicMapping[key];
        if (newKey == nil) {
            newKey = key;
        }
        [dic setObject:taDic[key] forKey:newKey];
    }
      _properties = dic;
      _defaultActionURL = [NSURL URLWithString:taDic[@"nurl"]];
      return self;
  }
 
     - (void)displayContentForURL:(NSURL *)URL rootViewController:(UIViewController *)controller {   
        [self.nativeAd handleClick];
        if ([self.delegate respondsToSelector:@selector(nativeAdDidClick:)]) {
          [self.delegate nativeAdDidClick:self];
        }   
    }
    - (void)adViewWillLeaveApplication:(TADNativeAd *)adView {
        if ([self.delegate respondsToSelector:@selector(nativeAdWillLeaveApplicationFromAdapter:)]) {
            [self.delegate nativeAdWillLeaveApplicationFromAdapter:self];
        }  
    }
  @end


</source>


== TAMediaCustomNativeAdRenderer ==
== TAMediaCustomNativeAdRenderer(必要) ==
此 class 需實做 MPNativeAdRenderer protocol,用於設置客製化事件處理的 class (TAMediaCustomNativeAdEvent) 以及將由 adapter 取得的 Dictionary 呈現到所需的 adView 內並回傳<br>
此 class 需實做 MPNativeAdRenderer protocol,用於設置客製化事件處理的 class (TAMediaCustomNativeAdEvent) 以及將由 adapter 取得的 Dictionary 呈現到所需的 adView 內並回傳<br>
1.實作<code>+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings</code>建立 MPNativeAdRendererConfiguration物件<br>
#實作<code>+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings</code>建立 MPNativeAdRendererConfiguration物件<br>
2.設置 rendering class 為本身class<br>
#設置 rendering class 為本身class<br>
3.設置 rendererSettings 為參數傳入 的rendererSettings<br>
#設置 rendererSettings 為參數傳入 的rendererSettings<br>
4.設置 supportedCustomEvents 為 TAMediaCustomNativeAdEvent class<br>
#設置 supportedCustomEvents 為 TAMediaCustomNativeAdEvent class<br>
5.實作<code>initWithRendererSettings:</code>設置物件viewSizeHandler,以及任何客製化設定<br>
#實作<code>initWithRendererSettings:</code>設置物件viewSizeHandler,以及任何客製化設定<br>
6.實作<code>retrieveViewWithAdapter:</code>回傳要來呈顯在畫面上的 View<br>
#實作<code>retrieveViewWithAdapter:</code>回傳要來呈顯在畫面上的 View<br>
參考以下代碼<br>
參考以下代碼<br>
<source>
#import <Foundation/Foundation.h>
#import <MoPub/MoPub.h>
@interface TAMediaCustomNativeAdRenderer : NSObject <MPNativeAdRenderer>
@property (nonatomic, readonly) MPNativeViewSizeHandler viewSizeHandler;
@end
</source>
<source>
#import "TAMediaCustomNativeAdRenderer.h"
#import "TAMediaCustomNativeAdEventAdapter.h"
#import <MoPub/MoPub.h>
#import "MPNativeAdView.h"
@interface TAMediaCustomNativeAdRenderer()


  //  TAMediaCustomNativeAdRenderer.h
@property (nonatomic,strong) id<MPNativeAdRendererSettings>setting;
  #import <Foundation/Foundation.h>
  #import <MoPub/MoPub.h>
  @interface TAMediaCustomNativeAdRenderer : NSObject <MPNativeAdRenderer>
 
  @property (nonatomic, readonly) MPNativeViewSizeHandler viewSizeHandler;
 
  @end


  //  TAMediaCustomNativeAdRenderer.m
@property (nonatomic,strong) MPNativeAdRendererImageHandler *rendererImageHandler;
  #import "TAMediaCustomNativeAdRenderer.h"
@property(nonatomic, strong) Class renderingViewClass;
  #import "MPNativeAdView.h"
 
 
@end
  @interface TAMediaCustomNativeAdRenderer() <MPNativeAdRendererImageHandlerDelegate>
 
 
@implementation TAMediaCustomNativeAdRenderer
  @property (nonatomic,strong) id<MPNativeAdRendererSettings>setting;
 
 
+ (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings {
  @property (nonatomic,strong) MPNativeAdRendererImageHandler *rendererImageHandler;
    MPNativeAdRendererConfiguration *config = [[MPNativeAdRendererConfiguration alloc] init];
 
    config.rendererSettings = rendererSettings;
  @end
    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 {
      
      
  @implementation TAMediaCustomNativeAdRenderer
    MPLogAdEvent([MPLogEvent adShowAttemptForAdapter:NSStringFromClass(self.class)], nil);
 
    MPLogAdEvent([MPLogEvent adWillAppearForAdapter:NSStringFromClass(self.class)], nil); 
  + (MPNativeAdRendererConfiguration *)rendererConfigurationWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings {
   
      MPNativeAdRendererConfiguration *config = [[MPNativeAdRendererConfiguration alloc] init];
    UIView<MPNativeAdRendering> *mpNativeAdView = [self.renderingViewClass new];
      config.rendererSettings = rendererSettings;
    mpNativeAdView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
      config.supportedCustomEvents = @[@"TAMediaCustomNativeAdEvent"];'''//設置客製化事件處理的class'''
   
      config.rendererClass = [self class];
    TAMediaCustomNativeAdEventAdapter *tadAdpater = (TAMediaCustomNativeAdEventAdapter *)adapter;
      return config;
    TADNativeAdView *tadNativeAdView = tadAdpater.nativeAdView;
  }
    tadNativeAdView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
 
    [tadNativeAdView addSubview:mpNativeAdView];
  - (instancetype)initWithRendererSettings:(id<MPNativeAdRendererSettings>)rendererSettings {
    [self fillSuperview:mpNativeAdView];
      self = [super init];
   
      _viewSizeHandler = [rendererSettings.viewSizeHandler copy];
    if([mpNativeAdView respondsToSelector:@selector(nativeTitleTextLabel)]) {
      self.setting = rendererSettings;
        [mpNativeAdView.nativeTitleTextLabel addSubview:tadNativeAdView.longSubjectLabel];
      self.rendererImageHandler = [MPNativeAdRendererImageHandler new];
        mpNativeAdView.nativeTitleTextLabel.text = adapter.properties[kAdTitleKey];
      self.rendererImageHandler.delegate = self;
        mpNativeAdView.nativeTitleTextLabel.userInteractionEnabled = YES;
      return self;
        tadNativeAdView.longSubjectLabel.userInteractionEnabled = YES;
  }
        [self fillSuperview:tadNativeAdView.longSubjectLabel];
 
    }
  - (UIView *)retrieveViewWithAdapter:(id<MPNativeAdAdapter>)adapter error:(NSError **)error {
   
      UIView<MPNativeAdRendering> *adView = [MPNativeAdView new];
    if([mpNativeAdView respondsToSelector:@selector(nativeMainTextLabel)]) {
      '''//MPNativeAdRendering potocol設置的項目'''
        [mpNativeAdView.nativeMainTextLabel addSubview:tadNativeAdView.bodyLabel];
      '''//需依照串接不同的Native廣告,設定不同的值'''
        mpNativeAdView.nativeMainTextLabel.text = adapter.properties[kAdTextKey];
      adView.nativeTitleTextLabel.text = adapter.properties[kAdTitleKey];
        mpNativeAdView.nativeMainTextLabel.userInteractionEnabled = YES;
      adView.nativeMainTextLabel.text = adapter.properties[kAdTextKey];
        tadNativeAdView.bodyLabel.userInteractionEnabled = YES;
      adView.nativeCallToActionTextLabel.text = adapter.properties[kAdCTATextKey];
        [self fillSuperview:tadNativeAdView.bodyLabel];
      [self.rendererImageHandler loadImageForURL:[NSURL URLWithString:[adapter.properties objectForKey:kAdIconImageKey]] intoImageView:adView.nativeIconImageView];
    }
      [self.rendererImageHandler loadImageForURL:[NSURL URLWithString:[adapter.properties objectForKey:kAdMainImageKey]] intoImageView:adView.nativeMainImageView];
   
     
    if([mpNativeAdView respondsToSelector:@selector(nativeCallToActionTextLabel)] && mpNativeAdView.nativeCallToActionTextLabel) {
      '''//MPNativeAdRendering potocol以外的項目用以下方式設置'''
        [mpNativeAdView.nativeCallToActionTextLabel addSubview:tadNativeAdView.callToActionView];
      MPNativeAdRenderingImageLoader *imageLoader = [[MPNativeAdRenderingImageLoader alloc] initWithImageHandler:self.rendererImageHandler];
        mpNativeAdView.nativeCallToActionTextLabel.text = adapter.properties[kAdCTATextKey];
      [adView layoutCustomAssetsWithProperties:adapter.properties imageLoader:imageLoader];
        mpNativeAdView.nativeCallToActionTextLabel.userInteractionEnabled = YES;
      return adView;
        tadNativeAdView.callToActionView.userInteractionEnabled = YES;
  }
        [self fillSuperview:tadNativeAdView.callToActionView];
 
    }
  - (BOOL)nativeAdViewInViewHierarchy
   
  {
    if([mpNativeAdView respondsToSelector:@selector(nativeIconImageView)]) {
      return YES;
        [mpNativeAdView.nativeIconImageView addSubview:tadNativeAdView.squareImgeView];
  }
        mpNativeAdView.nativeIconImageView.image = adapter.properties[kAdIconImageKey];
  @end
        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
</source>


== TAMediaCustomNativeAdEvent(必要) ==
== TAMediaCustomNativeAdEvent(必要) ==
此 class 需繼承 MPNativeCustomEvent,用來取得 TAmedia native ad 提供給 MoPub<br>
此 class 需繼承 MPNativeCustomEvent,用來取得 TAmedia native ad 提供給 MoPub<br>
1.建立 class 繼承 MPNativeCustomEvent<br>
#建立 class 繼承 MPNativeCustomEvent<br>
2.複寫<code> - (void)requestAdWithCustomEventInfo:(NSDictionary *)info</code>在此用 TADNativeAd 去取得廣告<br>
#複寫<code> - (void)requestAdWithCustomEventInfo:(NSDictionary *)info</code>在此用 TADNativeAd 去取得廣告<br>
3.取得廣告後用取得的 Dictionary 建立 TAMediaCustomNativeAdEventAdapter 後再用 adapter 建立MPNativeAd<br>
#取得廣告後用取得的 Dictionary 建立 TAMediaCustomNativeAdEventAdapter 後再用 adapter 建立MPNativeAd<br>
4.呈現廣告前先呼叫父類別<code>precacheImagesWithURLs:completionBlock:<code/>取得image後,再呼叫<code>customNativeEvent:didLoadAd:</code><br>
#呈現廣告前先呼叫父類別<code>precacheImagesWithURLs:completionBlock:<code/>取得image後,再呼叫<code>customNativeEvent:didLoadAd:</code><br>


  #import <MoPub/MoPub.h>
<source>
  #import <TAMediaAdsFramework/TAMediaAdsFramework.h>
#import <MoPub/MoPub.h>
 
#import <TAMediaAdsFramework/TAMediaAdsFramework.h>
  @interface TAMediaCustomNativeAdEvent : MPNativeCustomEvent <TADNativeAdDelegate> {
      TADNativeAd *nativeAd;
  }
 
  @end


  #import "TAMediaCustomNativeAdEvent.h"
@interface TAMediaCustomNativeAdEvent : MPNativeCustomEvent <TADNativeAdDelegate>
  #import "TAMediaCustomNativeAdEventAdapter.h"
 
  #import <MoPub/MoPub.h>
@property (nonatomic,strong) TADNativeAd *nativeAd;
 
 
  @implementation TAMediaCustomNativeAdEvent
@end
 
</source>
  - (void)requestAdWithCustomEventInfo:(NSDictionary *)info adMarkup:(NSString *)adMarkup {
 
       TADRequest *request = [TADRequest request];
<source>
      request.testing = NO;
#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
     // Type: TADGender
      request.gender = kTADGenderUnknown;
    request.gender = kTADGenderUnknown;
     
   
      // NAD 物件初始化, 帶入自訂的origin
    // NAD 物件初始化, 帶入自訂的origin
      if (!nativeAd) {
    if (!self.nativeAd) {
          nativeAd = [[TADNativeAd alloc] initWithAdUnitId:info[@"NativeId"]];      
        self.nativeAd = [[TADNativeAd alloc] initWithAdUnitId: self.adUnitId];
      }
    }
      // 必須要設定delegate
    // 必須要設定delegate
      nativeAd.delegate = self;
    self.nativeAd.delegate = self;
      // 載入廣告
   
      [nativeAd loadRequest:request];
    MPLogAdEvent([MPLogEvent adLoadAttemptForAdapter:NSStringFromClass(self.class) dspCreativeId:nil dspName:nil], self.adUnitId);
 
 
  }
    // 載入廣告
 
    [self.nativeAd loadRequest:request];
  - (void)nativeAdDidReceiveAd:(TADNativeAd *)ad {
}
      // 表示本次請求收到廣告
 
      TAMediaCustomNativeAdEventAdapter *adapter = [[TAMediaCustomNativeAdEventAdapter alloc] initWithTADNativeAd:ad];
- (void)nativeAdDidReceiveAd:(TADNativeAd *)ad {
      MPNativeAd *mpNativeAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
 
      //藉由 getNativeAdContent 取得包含回覆內容的 NSDictionary
    MPLogAdEvent([MPLogEvent adLoadSuccessForAdapter:NSStringFromClass(self.class)], self.adUnitId);
      NSDictionary *nadDic = [nativeAd getNativeAdContent];
   
      NSMutableArray *imageURLs = [NSMutableArray array];
    TADNativeAdView *nativeView = [TADNativeAdView new];
      for (NSString *key in nadDic.allKeys) {
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
          if ([[key lowercaseString] hasPrefix:@"image"] || [key hasPrefix:@"ICON"]) {
    UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
              if (nadDic[key] && ![nadDic[key] isEqualToString:@""]) {
    UILabel *bodyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
                  NSURL *url = [NSURL URLWithString:nadDic[key]];
    UILabel *callToActionView = [[UILabel alloc] initWithFrame: CGRectZero];
                  [imageURLs addObject:url];
    UIImageView *smallImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
              }           
    UIImageView *bigImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
          }
    TADNativeMediaView *mediaView = [[TADNativeMediaView alloc] initWithFrame:CGRectZero];
      }
    mediaView.mediaContent = ad.adContent.mediaContent;
      //在呼叫delegate didloadAd前先將圖片預載
 
      [super precacheImagesWithURLs:imageURLs completionBlock:^(NSArray *errors) {
    [nativeView addSubview:titleLabel];
          if (errors) {           
    [nativeView addSubview:subTitleLabel];
              [self.delegate nativeCustomEvent:self didFailToLoadAdWithError:MPNativeAdNSErrorForImageDownloadFailure()];
    [nativeView addSubview:bodyLabel];
          } else {
    [nativeView addSubview:callToActionView];
              [self.delegate nativeCustomEvent:self didLoadAd:mpNativeAd];
    [nativeView addSubview:smallImageView];
          }
    [nativeView addSubview:bigImageView];
      }];
    [nativeView addSubview:mediaView];
  }
   
 
    nativeView.longSubjectLabel = titleLabel;
  - (void)nativeAd:(TADNativeAd *)ad didFailToReceiveAdWithError:(TADRequestError *)error {
    nativeView.shortSubjectLabel = subTitleLabel;
      if ([self.delegate respondsToSelector:@selector(nativeCustomEvent:didFailToLoadAdWithError:)]) {
    nativeView.bodyLabel = bodyLabel;
          [self.delegate nativeCustomEvent:self didFailToLoadAdWithError:error];
    nativeView.callToActionView = callToActionView;
      }
    nativeView.squareImgeView = smallImageView;
  }
    nativeView.rectangleImgeView = bigImageView;
 
    nativeView.mediaView = mediaView;
  - (void)dealloc {
   
      if (nativeAd != nil) {
    nativeView.nativeAd = ad;
          nativeAd.delegate = nil;
   
          nativeAd = nil;
    // 表示本次請求收到廣告
      }
    TAMediaCustomNativeAdEventAdapter *adapter = [[TAMediaCustomNativeAdEventAdapter alloc] initTADNativeAd:ad withNativeView:nativeView];
  }
    MPNativeAd *mpNativeAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
 
    [self.delegate nativeCustomEvent:self didLoadAd:mpNativeAd];
  @end
}
 
- (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];
    }
}
 
- (void)dealloc {
}
 
@end
</source>


== TAMediaCustomNativeAdEventSetting ==
== TAMediaCustomNativeAdEventSetting ==

於 2021年8月23日 (一) 12:13 的修訂

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

回MoPub教學

TAMediaCustomNativeAdEventAdapter(必要)

此 class 是作為 TADNativeAd 與 MPNativeAd 的橋樑,將 TADNativeAd 轉換為 MPNativeAd 所需要的 Dictionary

  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 (TAMediaCustomNativeAdEvent) 以及將由 adapter 取得的 Dictionary 呈現到所需的 adView 內並回傳

  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];
    }
}

- (void)dealloc {
 
}

@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