菜单

原生广告

1. 主要开发工作说明

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 - 广告点击关闭时执行回调给开发者

2. 具体集成说明及示例

2.1 实现广告加载的Adapter类

1. 创建一个自定义Native Adapter类,可继承NSObject,建议以NativeAdapter结尾,类名需要配置到Taku后台的自定义广告平台;

2.自定义adapter类必须实现方法如下:

•实现initWithNetworkCustomInfo:实例化adapter对象,可以在这里进行广告SDK的相关初始化;

•实现广告加载时调用的loadADWithInfo:方法,触发广告SDK的广告请求;

•需要设置rendererClass,继承ATNativeRenderer,当广告渲染出来的时候,需要调用这个方法对关键要素按照广告平台SDK进行

以下是集成示例,具体项目可参考 demo 中 CustomAdapter中 的示例代码:

创建并实现TouTiaoNativeCustomAdapter类

swift 复制代码
//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];
}

2.2 实现NativeRenderer 广告渲染的实现

Taku SDK内部针对原生广告的渲染做了一层封装,故实现自定义Adapter时,需要实现Renderer类,广告平台返回的原生参数映射到Taku内部对象。

1.实现继承ATNativeRenderer的Renderer类,参考如下:

swift 复制代码
@interface TouTiaoNativeRenderer : ATNativeRenderer
@property(nonatomic, readonly) TouTiaoNativeCustomEvent *customEvent;
@end

2. 实现renderOffer方法,可以根据广告平台的要求,做渲染之后需要的例如注册点击事件之类的功能,参考如下:

swift 复制代码
-(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,参考如下:

swift 复制代码
-(UIView*)createMediaView {
    ATVideoView *videoView = [[ATVideoView alloc] initWithFrame:self.ADView.bounds URL:nil];
    videoView.autoPlay = ((ATNativeADCache*)self.ADView.nativeAd).placementModel.wifiAutoSwitch;
    return videoView;
}

4.其他原生广告功能可选重写的方法,请前往 Demo 中查看。

2.3 实现广告回调的CustomEvent类

需要自定义实现一个xxxCustomEvent类,继承ATNativeCustomEvent类,并通过这个类添加自定义广告平台对应的回调代理,当广告平台有回调时,将对应事件调用ATNativeCustomEvent的方法回传给Taku SDK。

以下是集成示例,具体项目可参考 Demo 中 CustomAdapter中 的示例代码:

创建并实现TouTiaoNativeCustomEvent类:

以下为穿山甲Native广告回调示例:

swift 复制代码
- (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内部封装的方法,具体参考如下:

swift 复制代码
 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);
        }];
上一个
横幅广告
下一个
自定义高级配置
最近修改: 2026-06-22Powered by