1. 创建一个自定义Native Adapter类,可继承NSObject,并遵循ATAdAdapter协议,建议以NativeAdapter结尾,类名需要配置到Taku后台的自定义广告平台;
2. 自定义adapter类必须实现方法说明如下:
•当SDK需要请求到配置自定义广告源时,会调用方法initWithNetworkCustomInfo:实例化adapter对象;
•请求自定义广告源广告会触发adapter的loadADWithInfo:方法调用;
•需要设置rendererClass,继承ATNativeRenderer,当广告渲染出来的时候,需要调用这个方法对关键要素按照广告平台SDK进行转换。
具体方法说明如下:
抽象方法 | 参数说明 | 返回值 | 作用 | 是否必须 |
---|---|---|---|---|
-(instancetype) initWithNetworkCustomInfo:(NSDictionary* )serverInfo localInfo:(NSDictionary* )localInfo | serverInfo: 服务端配置的参数字典 localInfo: 本次加载传入的参数字典 | instancetype | 用于初始化自定义adapter | 是 |
-(void) loadADWithInfo:(NSDictionary* )serverInfo localInfo:(NSDictionary* )localInfo completion:(void (^)(NSArray | serverInfo: 服务端配置的参数字典 localInfo: 本次加载传入的参数字典 | void | 实现展示自定义广告平台加载广告的逻辑 | 是 |
+(Class) rendererClass | - | 自定义Renderer类 | 用于返回自定义Renderer类 | 是 |
3. 回调方法说明如下: 需要自定义实现一个xxxCustomEvent类,继承ATNativeCustomEvent类,并通过这个类添加自定义广告平台对应的回调代理,当广告平台有回调时,将对应事件调用ATNativeCustomEvent的方法回传给Taku SDK。
具体回调方法说明如下:
回调方法 | 参数说明 | 说明 |
---|---|---|
-(void) trackNativeAdLoaded:(NSDictionary* )assets | assets:原生广告素材 | 广告加载成功时执行回调给开发者 |
-(void) trackNativeAdLoadFailed:(NSError* )error | error:错误信息 | 广告加载失败时执行回调给开发者 |
-(void) trackNativeAdImpression | - | 广告页面打开时执行回调给开发者 |
-(void) trackNativeAdClick | - | 广告被点击时执行的回调给开发者 |
-(void) trackNativeAdClosed | - | 广告点击关闭时执行回调给开发者 |
1. 创建一个自定义Native Adapter类,可继承NSObject,建议以NativeAdapter结尾,类名需要配置到Taku后台的自定义广告平台;
2.自定义adapter类必须实现方法如下:
•实现initWithNetworkCustomInfo:实例化adapter对象,可以在这里进行广告SDK的相关初始化;
•实现广告加载时调用的loadADWithInfo:方法,触发广告SDK的广告请求;
•需要设置rendererClass,继承ATNativeRenderer,当广告渲染出来的时候,需要调用这个方法对关键要素按照广告平台SDK进行
以下是集成示例,具体项目可参考 demo 中 CustomAdapter中 的示例代码:
创建并实现TouTiaoNativeCustomAdapter类
//TouTiaoNativeCustomAdapter.h
#import <AnyThinkNative/AnyThinkNative.h>
@interface TouTiaoNativeCustomAdapter()
@property(nonatomic, readonly) TouTiaoNativeCustomEvent *customEvent;
@end
@implementation TouTiaoNativeCustomAdapter
/// Adapter initialization method
/// - Parameters:
/// - serverInfo: Data from the server
/// - localInfo: Data from the local
-(instancetype) initWithNetworkCustomInfo:(NSDictionary*)serverInfo localInfo:(NSDictionary*)localInfo {
self = [super init];
if (self != nil) {
//TODO: add some code for initialize Network SDK
}
return self;
}
/// Adapter sends a load request, means the ad source sends an ad load request
/// - Parameters:
/// - serverInfo: Data from the server
/// - localInfo: Data from the local
/// - completion: completion
-(void) loadADWithInfo:(NSDictionary*)serverInfo localInfo:(NSDictionary*)localInfo completion:(void (^)(NSArray *, NSError *))completion {
_customEvent = [TouTiaoNativeCustomEvent new];
_customEvent.isVideo = [serverInfo[@"is_video"] integerValue] == 1;
//必须赋值
_customEvent.requestCompletionBlock = completion;
NSDictionary *extraInfo = localInfo;
_customEvent.requestExtra = extraInfo;
NSString *sizeKey = [serverInfo[@"media_size"] integerValue] > 0 ? @{@2:kATExtraNativeImageSize228_150, @1:kATExtraNativeImageSize690_388}[serverInfo[@"media_size"]] : extraInfo[kATExtraNativeImageSizeKey];
NSInteger imgSize = [@{kATExtraNativeImageSize228_150:@9, kATExtraNativeImageSize690_388:@10}[sizeKey] integerValue];
BUAdSlot *slot = [[NSClassFromString(@"BUAdSlot") alloc] init];
slot.ID = serverInfo[@"slot_id"];
slot.AdType = [@{@0:@(BUAdSlotAdTypeFeed), @1:@(BUAdSlotAdTypeDrawVideo), @2:@(BUAdSlotAdTypeBanner), @3:@(BUAdSlotAdTypeInterstitial)}[@([serverInfo[@"is_video"] integerValue])] integerValue];
slot.isOriginAd = YES;
slot.position = 1;
slot.imgSize = [NSClassFromString(@"BUSize") sizeBy:imgSize];
slot.isSupportDeepLink = YES;
CGSize size = CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds) - 30.0f, 200.0f);
if ([extraInfo[kExtraInfoNativeAdSizeKey] respondsToSelector:@selector(CGSizeValue)]) { size = [extraInfo[kExtraInfoNativeAdSizeKey] CGSizeValue]; }
_adMgr = [[BUNativeExpressAdManager alloc] initWithSlot:slot adSize:size];
_adMgr.delegate = _customEvent;
_adMgr.adslot = slot;
[_adMgr loadAd:[serverInfo[@"request_num"] integerValue]];
}
+(Class) rendererClass {
return [ATTTNativeRenderer class];
}
Taku SDK内部针对原生广告的渲染做了一层封装,故实现自定义Adapter时,需要实现Renderer类,广告平台返回的原生参数映射到Taku内部对象。
1.实现继承ATNativeRenderer的Renderer类,参考如下:
@interface TouTiaoNativeRenderer : ATNativeRenderer
@property(nonatomic, readonly) TouTiaoNativeCustomEvent *customEvent;
@end
2. 实现renderOffer方法,可以根据广告平台的要求,做渲染之后需要的例如注册点击事件之类的功能,参考如下:
-(void) renderOffer:(ATNativeADCache *)offer {
[super renderOffer:offer];
_customEvent = offer.assets[kAdAssetsCustomEventKey];
_customEvent.adView = self.ADView;
self.ADView.customEvent = _customEvent;
// 由于穿山甲设置广告代理需要 BUNativeExpressAdManager ,所以自定义了一个key传入到这里使用
BUNativeExpressAdManager *nativeExpressAd = (BUNativeExpressAdManager *)offer.assets[@"tt_nativeexpress_manager"];
nativeExpressAd.delegate = _customEvent;
BUNativeExpressAdView *nativeFeed = offer.assets[kAdAssetsCustomObjectKey];
nativeFeed.rootViewController = self.configuration.rootViewController;
[nativeFeed render];
[self.ADView addSubview:(UIView*)nativeFeed];
nativeFeed.center = CGPointMake(CGRectGetMidX(self.ADView.bounds), CGRectGetMidY(self.ADView.bounds));
}
3. 如果广告形式存在MediaView,则需要实现createMediaView,以返回mediaview对象给到Taku,参考如下:
-(UIView*)createMediaView {
ATVideoView *videoView = [[ATVideoView alloc] initWithFrame:self.ADView.bounds URL:nil];
videoView.autoPlay = ((ATNativeADCache*)self.ADView.nativeAd).placementModel.wifiAutoSwitch;
return videoView;
}
4.其他原生广告功能可选重写的方法,请前往 Demo 中查看。
需要自定义实现一个xxxCustomEvent类,继承ATNativeCustomEvent类,并通过这个类添加自定义广告平台对应的回调代理,当广告平台有回调时,将对应事件调用ATNativeCustomEvent的方法回传给Taku SDK。
以下是集成示例,具体项目可参考 Demo 中 CustomAdapter中 的示例代码:
创建并实现TouTiaoNativeCustomEvent类:
以下为穿山甲Native广告回调示例:
- (void)nativeExpressAdSuccessToLoad:(BUNativeExpressAdManager *)nativeExpressAd views:(NSArray<__kindof BUNativeExpressAdView *> *)views {
NSLog(@"TTNative::nativeExpressAdSuccessToLoad:nativeAds:");
if (views.count) {
NSMutableArray* assets = [NSMutableArray array];
[views enumerateObjectsUsingBlock:^(BUNativeExpressAdView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableDictionary *asset = [NSMutableDictionary dictionary];
BUNativeExpressAdView* expressView = obj;
[asset setValue:self forKey:kAdAssetsCustomEventKey];
[asset setValue:expressView forKey:kATAdAssetsCustomObjectKey];
// 原生模板广告
[asset setValue:@(1) forKey:kATNativeADAssetsIsExpressAdKey];
[asset setValue:@(nativeExpressAdView.frame.size.width) forKey:kATNativeADAssetsNativeExpressAdViewWidthKey];
[asset setValue:@(nativeExpressAdView.frame.size.height) forKey:kATNativeADAssetsNativeExpressAdViewHeightKey];
expressView.rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[assets addObject:asset];
}];
self.requestCompletionBlock(assets, nil);
}
}
- (void)nativeExpressAdFailToLoad:(BUNativeExpressAdManager *)nativeExpressAd error:(NSError *_Nullable)error{
NSLog(@"%@",[NSString stringWithFormat:@"TTNative::nativeAdsManager:didFailWithError:%@", error]);
self.requestCompletionBlock(nil, error);
}
- (void)nativeExpressAdViewRenderSuccess:(BUNativeExpressAdView *)nativeExpressAdView {
NSLog(@"TTNative::nativeExpressAdViewRenderSuccess:");
}
- (void)nativeExpressAdViewDidClick:(BUNativeExpressAdView *)nativeExpressAdView {
NSLog(@"TTNative::nativeAdDidClick:withView:");
[self trackNativeAdClick];
}
- (void)nativeExpressAdView:(BUNativeExpressAdView *)nativeExpressAdView dislikeWithReason:(NSArray *)filterWords {
NSLog(@"TTNative::nativeAd:dislikeWithReason:");
[self trackNativeAdClosed];
}
- (void)nativeExpressAdViewPlayerDidPlayFinish:(BUNativeExpressAdView *)nativeExpressAdView error:(NSError *)error {
NSLog(@"TTNative::nativeAd:nativeExpressAdViewPlayerDidPlayFinish:");
[self trackNativeAdVideoEnd];
}
注:此类中,需要在回调中将广告平台返回的原生广告素材映射到Taku的对应的asset字典中,具体key的字段说明如下:
key | required | type | description |
---|---|---|---|
kATAdAssetsCustomEventKey | YES | NSObject | 广告展示后,接收广告代理事件的对象 |
kATNativeADAssetsUnitIDKey | NO | NSString | 三方广告平台的代码位id |
kATAdAssetsCustomObjectKey | YES | id | 三方平台返回的广告对象(数据) |
原生模板信息流还需要映射的key:
key | required | type | description |
---|---|---|---|
kATNativeADAssetsIsExpressAdKey | YES | BOOL | 原生信息流广告的类型,模板广告必须设置 |
kATNativeADAssetsNativeExpressAdViewWidthKey | NO | NSNumber | 模板广告视图的宽度 |
kATNativeADAssetsNativeExpressAdViewHeightKey | NO | NSNumber | 模板广告视图的高度 |
原生自渲染信息流还需要映射的key,映射之后才能在获取到的广告offer拿到相应的值,如果不需要或者没有的值,可以不用传入,如下:
key | required | type | description |
---|---|---|---|
kATNativeADAssetsIsExpressAdKey | NO | BOOL | 原生信息流广告的类型,默认为自渲染广告类型 |
kATNativeADAssetsMainTitleKey | NO | NSString | 广告的标题 |
kATNativeADAssetsMainTextKey | NO | NSString | 广告的描述 |
kATNativeADAssetsIconURLKey | NO | NSString | 广告的icon图片的URL地址 |
kATNativeADAssetsIconImageKey | NO | UIImage | 广告的icon图片 |
kATNativeADAssetsImageURLKey | NO | NSString | 广告的大图片的URL地址 |
kATNativeADAssetsMainImageKey | NO | UIImage | 广告的大图片 |
kATNativeADAssetsCTATextKey | NO | NSString | 广告的cta文案 |
kATNativeADAssetsRatingKey | NO | NSString | 广告的评级分 |
kATNativeADAssetsAdvertiserKey | NO | NSString | 广告的广告主 |
kATNativeADAssetsContainsVideoFlag | NO | BOOL | 是否为视频类广告 |
kATNativeADAssetsLogoURLKey | NO | NSString | 广告的logo图片的URL地址 |
kATNativeADAssetsLogoImageKey | NO | UIImage | 广告的logo图片 |
如果平台没有提供image下载的方法,可以使用Taku内部封装的方法,具体参考如下:
dispatch_group_enter(image_download_group);
[[ATImageLoader shareLoader] loadImageWithURL:[NSURL URLWithString:nativeAd.data.icon.imageURL] completion:^(UIImage *image, NSError *error) {
if ([image isKindOfClass:[UIImage class]]) { asset[kNativeADAssetsIconImageKey] = image; }
dispatch_group_leave(image_download_group);
}];