1. Create a custom Native Adapter class that can inherit NSObject. And follow the ATAdAdapter protocol, it is recommended to end with NativeAdapter, and the class name needs to be configured to the custom advertising platform in the TopOn backend;
2. The custom adapter class must implement the method description As follows:
The specific method is explained as follows:
3. The callback method is described as follows: You need to customize a xxxCustomEvent class, inherit the ATBannerCustomEvent class, and add custom events through this class. Define the callback agent corresponding to the advertising platform. When the advertising platform has a callback, the method of calling ATBannerCustomEvent for the corresponding event will be passed back to TopOn SDK.
The specific callback method is described as follows:
Callback method | Parameter description | Description |
---|---|---|
-(void) trackNativeAdLoaded:(NSDictionary* ) assets | assets: native creative | Execute a callback to the developer when the ad is loaded successfully |
-(void) trackNativeAdLoadFailed:(NSError* )error | error: Error message | Ad loading failed Execute callback to the developer |
-(void) trackNativeAdImpression | - | Execute a callback to the developer when the advertising page is opened |
-(void) trackNativeAdClick | - | Callback to the developer when the ad is clicked |
-(void) trackNativeAdClosed | - | Execute a callback to the developer when the ad is clicked to close |
1. Create a custom Native Adapter class, which can inherit NSObject. It is recommended to end with NativeAdapter. The class name needs to be configured to the custom advertising platform in the TopOn backend.
2. The custom adapter class must implement the following methods:
The following is an integration example. For specific projects, please refer to demo Sample code in CustomAdapter:
Create and implement the TouTiaoNativeCustomAdapter class
//TouTiaoNativeCustomAdapter.h
#import <AnyThinkNative/AnyThinkNative.h>
@interface TouTiaoNativeCustomAdapter()<ATAdAdapter>
@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<NSDictionary *> *, 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];
}
TopOn SDK internally encapsulates the rendering of native ads. Therefore, when implementing a custom Adapter, you need to implement the Renderer class. The native parameters returned by the advertising platform are mapped to TopOn internal objects.
1. Implement the Renderer class that inherits ATNativeRenderer, as follows:
@interface TouTiaoNativeRenderer : ATNativeRenderer
@property(nonatomic, readonly) TouTiaoNativeCustomEvent *customEvent;
@end
2. Implement the renderOffer method, which can perform functions required after rendering according to the requirements of the advertising platform, such as registering click events. , the reference is as follows:
-(void) renderOffer:(ATNativeADCache *)offer {
[super renderOffer:offer];
_customEvent = offer.assets[kAdAssetsCustomEventKey];
_customEvent.adView = self.ADView;
self.ADView.customEvent = _customEvent;
// Since the Pangolin setup AD agency requires the BunativeExpress Manager, a custom key is passed in here for use.
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 . If there is a MediaView in the advertising form, you need to implement createMediaView to return the mediaview object to TopOn. The reference is as follows:
-(__kindof UIView*)createMediaView {
ATVideoView *videoView = [[ATVideoView alloc] initWithFrame:self.ADView.bounds URL:nil];
videoView.autoPlay = ((ATNativeADCache*)self.ADView.nativeAd).placementModel.wifiAutoSwitch;
return videoView;
}
You need to customize a xxxCustomEvent class, inherit the ATNativeCustomEvent class, and pass this class Add the callback agent corresponding to the custom advertising platform. When the advertising platform has a callback, the corresponding event method of calling ATNativeCustomEvent is passed back to the TopOn SDK.
The following is an integration example. For specific projects, please refer to demo:
Create and implement the TouTiaoNativeCustomEvent class:
The following is an example of pangolin Native advertising callback:
- (void)nativeExpressAdSuccessToLoad:(BUNativeExpressAdManager *)nativeExpressAd views:(NSArray<__kindof BUNativeExpressAdView *> *)views {
NSLog(@"TTNative::nativeExpressAdSuccessToLoad:nativeAds:");
if (views.count) {
NSMutableArray<NSDictionary*>* assets = [NSMutableArray<NSDictionary*> 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];
// Native template advertising
[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<BUDislikeWords *> *)filterWords {
NSLog(@"TTNative::nativeAd:dislikeWithReason:");
[self trackNativeAdClosed];
}
- (void)nativeExpressAdViewPlayerDidPlayFinish:(BUNativeExpressAdView *)nativeExpressAdView error:(NSError *)error {
NSLog(@"TTNative::nativeAd:nativeExpressAdViewPlayerDidPlayFinish:");
[self trackNativeAdVideoEnd];
}
Note: In this class, the native creative returned by the advertising platform needs to be mapped to the corresponding asset dictionary of TopOn in the callback. The specific key field description is as follows:
Key | Required | Type | Description |
---|---|---|---|
kATAdAssetsCustomEventKey | YES | NSObject | After the ad is displayed, the object that receives the ad agency event |
kATNativeADAssetsUnitIDKey | NO | NSString | Code ID of the third-party advertising platform |
kATAdAssetsCustomObjectKey | YES | id | Advertising objects (data) returned by third-party platforms |
Native template information flow also requires mapping key:
key | required | type | description |
---|---|---|---|
kATNativeADAssetsIsExpressAdKey | YES | BOOL | Type of native information flow ad, template ad must be set |
kATNativeADAssetsNativeExpressAdViewWidthKey | NO | NSNumber | The width of the template ad view |
kATNativeADAssetsNativeExpressAdViewHeightKey | NO | NSNumber | The height of the template ad view |
Native self-rendering information flow also needs a mapped key, which can be obtained after mapping The corresponding value of the advertising offer is obtained. If the value is not needed or does not exist, you do not need to pass it in, as follows:
key | required | type | description |
---|---|---|---|
kATNativeADAssetsIsExpressAdKey | NO | BOOL | The type of native information flow ad, the default is self-rendering ad type |
kATNativeADAssetsMainTitleKey | NO | NSString | Title of the ad |
kATNativeADAssetsMainTextKey | NO | NSString | Description of the ad |
kATNativeADAssetsIconURLKey | NO | NSString | Advertising icon image URL address |
kATNativeADAssetsIconImageKey | NO | UIImage | Advertising icon image |
kATNativeADAssetsImageURLKey | NO | NSString | URL address of the large image of the advertisement |
kATNativeADAssetsMainImageKey | NO | UIImage | Large image of ad |
kATNativeADAssetsCTATextKey | NO | NSString | cta copy of advertisement |
kATNativeADAssetsRatingKey | NO | NSString | Ad's rating score |
kATNativeADAssetsAdvertiserKey | NO | NSString | Advertiser |
kATNativeADAssetsContainsVideoFlag | NO | BOOL | Whether it is a video ad |
kATNativeADAssetsLogoURLKey | NO | NSString | URL address of the logo image of the advertisement |
kATNativeADAssetsLogoImageKey | NO | UIImage | Advertising logo image |
If the platform does not provide an image download method, you can use TopOn's internal encapsulation method. The specific reference is as follows:
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);
}];