# iOS自定义平台适配器
**Repository Path**: admobile/ios-custom-platform-adapter
## Basic Information
- **Project Name**: iOS自定义平台适配器
- **Description**: No description available
- **Primary Language**: Objective-C
- **License**: GPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2021-11-09
- **Last Updated**: 2025-07-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# iOS - 自定义平台适配器对接文档
[TOC]
## 1.1 概述
尊敬的开发者,欢迎您使用Suyi聚合广告SDK自定义适配广告平台。通过本文档,您可以在几分钟之内轻松完成自定义广告平台对接过程。
操作系统及要求:iOS10.0及以上;依赖库中含有5G网络字段,故需Xcode包含最低14.5 SDK
自定义适配器平台支持广告类型:开屏,横幅,插屏,激励视频,信息流等;
## 2.1 采用 cocoapods 进行自定义平台依赖库SDK的导入
推荐使用Pod命令导入自定义平台所需要的依赖库:
```ruby
pod 'ADSuyiSDK', '~> 4.0.1.06132'
pod 'ADSuyiSDK/ADSuyiSDKPlatforms/tianmu' # 天目 #必选
```
## 3.1 在 ADmobile 运营后台增加自定义适配平台
1、**广告平台**:因ADSuyiSDK与运营后台的通信是依赖于双端协定的平台名称来进行逻辑处理(**新增自定义平台尚未开通开发者后台自主添加功能,如有需要请联系ADmobile运营同学协助添加**),故新增自定义平台不能与现有平台名称冲突且SDK端与后台录入平台名称一致;需谨记在运营后台添加的广告平台名称字段,该字段在自定义适配器开发时需要用到且必须与后台所填一致,否则会有广告加载异常问题;在后台添加新平台时需要添加该三方平台的申请的AppId和AppKey,该参数用于SDK端三方平台SDK初始化;
2、**广告类型**:因自定义平台适配器不能增加新的广告类型,故只能使用现有广告类型来进行平台广告的添加,在添加自定义平台广告位时,需严格按照平台的广告类型创建广告位id,现有广告类型(模板,自渲染,模板2.0等),如不清楚平台所示广告为何种类型时,请咨询我们技术同学;自定义平台适配器开发时,需明确该类为何种广告类型的加载器;
3、**平台及广告加载器注册**:自定义适配器平台开发中,需要继承对应的初始化父类及广告类型适配器父类,并应在load方法中调用注册方法来告知主SDK注册的平台及广告类型;
4、**初始化类**:自定义平台初始化类继承自自定义适配平台SDK,应在父类开放方法实现中来初始化三方平台SDK;
5、**广告加载类**:自定义适配平台加载器类中,需要继承自适配平台SDK依赖库对应广告类型父类,并在子类中实现响应加载方法及展示方法(**部分广告类型无展示方法,仅需实现请求方法且务必正确调用相应track方法确保广告正常展示**),方法中有广告请求参数model,根据平台加载广告所需参数从model拿到相应参数;
6、**广告回调**:因ADmobile需要根据平台回调时机来统计广告相关数据,故开发者在适配器开发过程中,需要根据平台广告回调中,调用响应方法,告知主SDK端进行数据统计(如:- (void)trackSplashAdRequest广告请求时调用此方法),需严格按照对应回调调用相应方法;
## 4.1 自定义适配器平台示例
以下自定义广告适配示例采用已适配平台:穿山甲(toutiao),优量汇(gdt)
### 4.1.1 初始化类适配
1. 需继承 `ADSuyiCustomAdapterInitialize`
2. 通过以下方法 & 子类实现完成适配
|
方法 | 参数说明|
|:-----------|:------|
| + (void)registPlatformAdLoaderClass:(id)klass forSdkName:(NSString *)sdkName | 注册初始化类 需要在load方法中调用
kclass: 初始化自定义平台的管理类
sdkName: 平台名称,需与后台配置管理类名一致且不能与现有平台名称冲突,例如:toutiao |
| **需子类实现:** | |
| +(void)initAdSDKWithConfigInfo:(ADSuyiCustomAdapterRequestContext *)config | 初始化方法
config: 初始化参数 |
| +(NSString *)platformSDKVersion | 平台版本号 |
**demo示例:**
`ADSuyiCustomAdapterBUInitialize.h`
```objc
#import
/// 初始化
@interface ADSuyiCustomAdapterBUInitialize : ADSuyiCustomAdapterInitialize
@end
```
`ADSuyiCustomAdapterBUInitialize.m`
```objc
#import "ADSuyiCustomAdapterBUInitialize.h"
#import
#import
#import
@implementation ADSuyiCustomAdapterBUInitialize
+ (void)load {
// 调用注册方法
//以现有广告平台穿山甲作为demo示例
[self registPlatformInitializeClass:self forSdkName:@"toutiao"];
}
// MARK: - Override
+ (void)initAdSDKWithConfigInfo:(ADSuyiCustomAdapterRequestContext *)config {
static NSString *_appid;
if(config.appId && [_appid isEqualToString:config.appId]) {
return;
}
_appid = config.appId.copy;
// 初始化三方SDK
[BUAdSDKManager setAppID:_appid];
BUAdSDKConfiguration *configuration = [BUAdSDKConfiguration configuration];
configuration.territory = BUAdSDKTerritory_CN; // 需要设置
if (![ADSuyiSDK enablePersonalAd]){
NSString *userExtData = @"[{\"name\":\"personal_ads_type\",\"value\":\"0\"}]";
configuration.userExtData = userExtData;
}
configuration.appID = _appid;
configuration.secretKey = config.appKey;
[BUAdSDKManager startWithAsyncCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
// Success
NSLog(@"toutiao sdk init success");
}else{
// Error
NSLog(@"toutiao sdk init error = %@",error);
}
}];
}
// 需要实现改方法 返回三方平台当前版本号
+ (NSString *)platformSDKVersion {
// 12221:可以为当前修改时间去的时间,也可以直接返回版本号
return [NSString stringWithFormat:@"%@.12221",[BUAdSDKManager SDKVersion]];
}
@end
```
### 4.1.2 开屏广告适配
1. 需继承 `ADSuyiCustomAdapterSplashAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackSplashAdSucceed | 三方平台请求成功时子类适配器中调用方法 |
| -(void)trackSplashAdDisplay | 三方平台展示回调回调时子类适配器中调用方法 |
| -(void)trackSplashAdSuccessToPresent | 三方平台展示成功时子类适配器中调用方法 |
| -(void)trackSplashAdFailedWithError:(nullable NSError*)error | 三方平台请求失败回调时子类适配器中调用方法 |
| -(void)trackSplashAdFailedToPresentWithError:(nullable NSError*)error | 三方平台渲染失败回调时子类适配器中调用方法 |
| -(void)trackSplashAdClicked | 三方平台点击时子类适配器中调用方法 |
| -(void)trackSplashAdSkip | 三方平台跳过回调时子类适配器中调用方法 |
| -(void)trackSplashAdClosed | 三方平台关闭回调时子类适配器中调用方法 |
| -(void)trackSplashAdLandingPageClosed | 三方平台关闭落地页回调时子类适配器中调用方法 |
| | |
| -(void)showSplashWithAdView:( UIView * _Nullable )adView customSkipBtn:(BOOL)isCustomBtn | (非必须调用)若平台是以返回 View 为形式,让我们自行添加至 Window, 可将 View 通过该方法添加至 Window, 并管理视图销毁, 并处理屏幕翻转问题 |
| **需子类实现:** | |
| -(void)requestAdWithContext:(ADSuyiCustomAdapterSplashRequestContext *)context | 请求广告方法,必须于子类中实现 |
| -(void)customAdapter_onAdReceive | 聚合告知可进行展示时触发,需要在子类实现并调用展示方法 |
**demo示例:**
`ADSuyiCustomAdapterBUSplashAd.h`
```objc
#import
@interface ADSuyiCustomAdapterBUSplashAd : ADSuyiCustomAdapterSplashAd
@end
```
`ADSuyiCustomAdapterBUSplashAd.m`
```objc
#import "ADSuyiCustomAdapterBUSplashAd.h"
#import
@interface ADSuyiCustomAdapterBUSplashAd ()
@property (nonatomic, strong) BUSplashAd *splashAd;
@property (nonatomic, strong) ADSuyiCustomAdapterSplashRequestContext *context;
@end
@implementation ADSuyiCustomAdapterBUSplashAd
// MARK: - Override
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:ADSuyiAdapterRenderTypeNative];
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:ADSuyiAdapterRenderTypeExpress];
}
/// 请求
- (void)requestAdWithContext:(ADSuyiCustomAdapterSplashRequestContext *)context{
_context = context;
if(!_splashAd) {
CGFloat width = UIScreen.mainScreen.bounds.size.width;
CGFloat height = UIScreen.mainScreen.bounds.size.height - context.bottomView.frame.size.height;
_splashAd = [[BUSplashAd alloc] initWithSlotID:context.posId adSize:CGSizeMake(width, height)];
_splashAd.delegate = self;
_splashAd.tolerateTimeout = 3;
}
[_splashAd loadAdData];
}
/// 展示
-(void)customAdapter_onAdReceive{
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
[_splashAd showSplashViewInRootViewController:keyWindow.rootViewController];
}
// MARK: - BUSplashAdDelegate
/// This method is called when material load successful
- (void)splashAdLoadSuccess:(BUSplashAd *)splashAd{
[self trackSplashAdSucceed];
}
/// This method is called when material load failed
- (void)splashAdLoadFail:(BUSplashAd *)splashAd error:(BUAdError *)error {
[self trackSplashAdFailedWithError:error];
}
/// This method is called when splash view render successful
- (void)splashAdRenderSuccess:(nonnull BUSplashAd *)splashAd {
// 渲染成功再展示视图控制器,目前统一放置需要展示的时候
UIView *bottomView = _context.bottomView;
if(bottomView){
bottomView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height - bottomView.frame.size.height, UIScreen.mainScreen.bounds.size.width, bottomView.frame.size.height);
[splashAd.splashRootViewController.view addSubview:_context.bottomView];
}
}
/// This method is called when splash view render failed
- (void)splashAdRenderFail:(BUSplashAd *)splashAd error:(BUAdError *)error {
[self trackSplashAdFailedToPresentWithError:error];
}
/// This method is called when splash view will show
- (void)splashAdWillShow:(nonnull BUSplashAd *)splashAd {}
/// This method is called when splash view did show
- (void)splashAdDidShow:(BUSplashAd *)splashAd {
[self trackSplashAdSuccessToPresent];
[self trackSplashAdDisplay];
}
/// This method is called when splash view is clicked.
- (void)splashAdDidClick:(BUSplashAd *)splashAd {
[self trackSplashAdClicked];
}
/// This method is called when splash view is closed.
- (void)splashAdDidClose:(BUSplashAd *)splashAd closeType:(BUSplashAdCloseType)closeType {
if(_context.bottomView){
[_context.bottomView removeFromSuperview];
}
if (closeType == BUSplashAdCloseType_ClickSkip) {
[self trackSplashAdSkip];
}
[self trackSplashAdClosed];
}
/// This method is called when splash viewControllr is closed.
- (void)splashAdViewControllerDidClose:(nonnull BUSplashAd *)splashAd {}
/**
This method is called when another controller has been closed.
@param interactionType : open appstore in app or open the webpage or view video ad details page.
*/
- (void)splashDidCloseOtherController:(BUSplashAd *)splashAd interactionType:(BUInteractionType)interactionType {
[self trackSplashAdLandingPageClosed];
}
/// This method is called when when video ad play completed or an error occurred.
- (void)splashVideoAdDidPlayFinish:(nonnull BUSplashAd *)splashAd didFailWithError:(nonnull NSError *)error {}
@end
```
### 4.1.3 横幅广告
1. 需继承 `ADSuyiCustomAdapterBannerAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackBannerAdDidReceived | 三方平台广告请求成功时,子类适配器中调用方法 |
| -(void)trackBannerAdFailToReceivedWithError:(nullable NSError *)error | 三方平台广告请求失败时,子类适配器中调用方法 |
| -(void)trackBannerAdClicked | 三方平台广告点击时,子类适配器中调用方法 |
| -(void)trackBannerAdExposure | 三方平台广告曝光时,子类适配器调用方法 |
| -(void)trackBannerAdClosed | 三方平台广告关闭时,子类适配器中调用方法 |
| -(void)trackBannerAdLandingPageClosed | 三方平台广告落地页关闭时,子类适配器中调用方法 |
| **需子类实现:** | |
| -(UIView *)requestBannerViewWithContext:(ADSuyiCustomAdapterBannerRequestContext *)context | 在子类实现该方法用于请求平台banner广告 |
**demo示例:**
`ADSuyiCustomAdapterBUBanner.h`
```objc
#import
@interface ADSuyiCustomAdapterBUBanner : ADSuyiCustomAdapterBannerAd
@end
```
`ADSuyiCustomAdapterBUBanner.m`
```objc
#import "ADSuyiCustomAdapterBUBanner.h"
#import
@interface ADSuyiCustomAdapterBUBanner ()
{
BUNativeExpressBannerView *_bannerAd;
}
@end
@implementation ADSuyiCustomAdapterBUBanner
// MARK: - Override
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao"];
}
- (UIView *)requestBannerViewWithContext:(ADSuyiCustomAdapterBannerRequestContext *)context{
_bannerAd = [[BUNativeExpressBannerView alloc] initWithSlotID:context.posId rootViewController:context.viewController adSize:context.adSize interval:context.refreshTime];
_bannerAd.delegate = self;
[_bannerAd loadAdData];
return _bannerAd;
}
// MARK: - banner delegate
/**
This method is called when bannerAdView ad slot loaded successfully.
@param bannerAdView : view for bannerAdView
*/
- (void)nativeExpressBannerAdViewDidLoad:(BUNativeExpressBannerView *)bannerAdView {
[self trackBannerAdDidReceived];
}
/**
This method is called when bannerAdView ad slot failed to load.
@param error : the reason of error
*/
- (void)nativeExpressBannerAdView:(BUNativeExpressBannerView *)bannerAdView didLoadFailWithError:(NSError *_Nullable)error {
[self trackBannerAdFailToReceivedWithError:error];
}
/**
This method is called when rendering a nativeExpressAdView successed.
*/
- (void)nativeExpressBannerAdViewRenderSuccess:(BUNativeExpressBannerView *)bannerAdView {}
/**
This method is called when a nativeExpressAdView failed to render.
@param error : the reason of error
*/
- (void)nativeExpressBannerAdViewRenderFail:(BUNativeExpressBannerView *)bannerAdView error:(NSError * __nullable)error {}
/**
This method is called when bannerAdView ad slot showed new ad.
*/
- (void)nativeExpressBannerAdViewWillBecomVisible:(BUNativeExpressBannerView *)bannerAdView {
[self trackBannerAdExposure];
}
/**
This method is called when bannerAdView is clicked.
*/
- (void)nativeExpressBannerAdViewDidClick:(BUNativeExpressBannerView *)bannerAdView {
[self trackBannerAdClicked];
}
/**
This method is called when the user clicked dislike button and chose dislike reasons.
@param filterwords : the array of reasons for dislike.
*/
- (void)nativeExpressBannerAdView:(BUNativeExpressBannerView *)bannerAdView dislikeWithReason:(NSArray *_Nullable)filterwords {
[self trackBannerAdClosed];
}
/**
This method is called when another controller has been closed.
@param interactionType : open appstore in app or open the webpage or view video ad details page.
*/
- (void)nativeExpressBannerAdViewDidCloseOtherController:(BUNativeExpressBannerView *)bannerAdView interactionType:(BUInteractionType)interactionType {
[self trackBannerAdLandingPageClosed];
}
/**
This method is called when the Ad view container is forced to be removed.
@param bannerAdView : Express Banner Ad view container
*/
- (void)nativeExpressBannerAdViewDidRemoved:(BUNativeExpressBannerView *)bannerAdView {}
@end
```
### 4.1.4 插屏广告
1. 需继承 `ADSuyiCustomAdapterInterstitalAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackInterstitialAdSuccessToLoad | 三方平台请求成功时,子类适配器中调用方法 |
| -(void)trackInterstitialAdDidPresent | 三方平台广告展示时,子类适配器中调用方法 |
| -(void)trackInterstitialAdFailToLoadError:(nullable NSError *)error | 三方平台请求失败时,子类适配器中调用方法 |
| -(void)trackInterstitialAdFailToPresentError:(nullable NSError *)error | 三方平台广告展示失败时,子类适配器中调用方法 |
| -(void)trackInterstitialAdDidClick | 三方平台广告点击时,子类适配器中调用方法 |
| -(void)trackInterstitialAdDidClose | 三方平台广告关闭时,子类适配器中调用方法 |
| -(void)trackInterstitialAdDidExposure | 三方平台广告曝光时,子类适配器中调用方法 |
| -(void)trackInterstitialAdLandingPageClosed | 三方平台广告落地页关闭时,子类适配器中调用方法 |
| **需子类实现:** | |
| -(void)requestAdWithContext:(ADSuyiCustomAdapterInterstitalRequestContext *)context | 请求广告方法,必须于子类中实现 |
| -(void)showInterstitalAdFromViewController:(UIViewController * _Nullable )viewController | 展示插屏广告 |
**demo示例:**
`ADSuyiCustomAdapterBUIntertitalAd.h`
```objc
#import
@interface ADSuyiCustomAdapterBUIntertitalAd : ADSuyiCustomAdapterInterstitalAd
@end
```
`ADSuyiCustomAdapterBUIntertitalAd.m`
```objc
#import "ADSuyiCustomAdapterBUIntertitalAd.h"
#import
@interface ADSuyiCustomAdapterBUIntertitalAd ()
{
BUNativeExpressFullscreenVideoAd *_interstitialAd;
ADSuyiCustomAdapterInterstitalRequestContext *_context;
}
@end
@implementation ADSuyiCustomAdapterBUIntertitalAd
// MARK: - Override
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:(ADSuyiAdapterRenderTypeExpress)];
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:(ADSuyiAdapterRenderTypeExpressPro)];
}
- (void)requestAdWithContext:(ADSuyiCustomAdapterInterstitalRequestContext *)context {
_context = context;
if(!_interstitialAd) {
_interstitialAd = [[BUNativeExpressFullscreenVideoAd alloc]initWithSlotID:context.posId];
_interstitialAd.delegate = self;
}
[_interstitialAd loadAdData];
}
- (void)showInterstitalAdFromViewController:(UIViewController *)viewController {
if (!viewController) {
viewController = _context.viewController;
}
[_interstitialAd showAdFromRootViewController:viewController];
}
// MARK: - BUNativeExpressFullscreenVideoAdDelegate
/**
This method is called when video ad material loaded successfully.
*/
- (void)nativeExpressFullscreenVideoAdDidLoad:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd {}
/**
This method is called when video cached successfully.
For a better user experience, it is recommended to display video ads at this time.
And you can call [BUNativeExpressFullscreenVideoAd showAdFromRootViewController:].
*/
- (void)nativeExpressFullscreenVideoAdDidDownLoadVideo:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd {
[self trackInterstitialAdSuccessToLoad];
}
/**
This method is called when video ad materia failed to load.
@param error : the reason of error
*/
- (void)nativeExpressFullscreenVideoAd:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd didFailWithError:(NSError *_Nullable)error {
[self trackInterstitialAdFailToLoadError:error];
}
/**
This method is called when rendering a nativeExpressAdView successed.
It will happen when ad is show.
*/
- (void)nativeExpressFullscreenVideoAdViewRenderSuccess:(BUNativeExpressFullscreenVideoAd *)rewardedVideoAd {}
/**
This method is called when a nativeExpressAdView failed to render.
@param error : the reason of error
*/
- (void)nativeExpressFullscreenVideoAdViewRenderFail:(BUNativeExpressFullscreenVideoAd *)rewardedVideoAd error:(NSError *_Nullable)error {}
- (void)nativeExpressFullscreenVideoAdDidVisible:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd {
[self trackInterstitialAdDidPresent];
[self trackInterstitialAdDidExposure];
}
- (void)nativeExpressFullscreenVideoAdDidClick:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd {
[self trackInterstitialAdDidClick];
}
- (void)nativeExpressFullscreenVideoAdDidClose:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd {
[self trackInterstitialAdDidClose];
}
- (void)nativeExpressFullscreenVideoAdDidCloseOtherController:(BUNativeExpressFullscreenVideoAd *)fullscreenVideoAd interactionType:(BUInteractionType)interactionType {
[self trackInterstitialAdLandingPageClosed];
}
@end
```
### 4.1.5 激励视频
1. 需继承 `ADSuyiCustomAdapterRewardVodAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackRwardvodAdLoadSuccess | 三方平台请求成功时,子类适配器中调用方法 |
| -(void)trackRewardvodAdReadyToPlay | 三方平台视频准备播放时,子类适配器中调用方法 |
| -(void)trackRewardvodAdVideoLoadSuccess | 三方平台视频准备完成时,子类适配器中调用方法 |
| -(void)trackRewardvodAdWillVisible | 三方平台视频即将展示时,子类适配器中调用方法 |
| -(void)trackRewardvodAdDidVisible | 三方平台视频展示时,子类适配器中调用方法 |
| -(void)trackRewardvodAdDidClose | 三方平台视频关闭时,子类适配器中调用方法 |
| -(void)trackRewardvodAdDidClick | 三方平台视频点击时,子类适配器中调用方法 |
| -(void)trackRewardvodAdDidPlayFinish | 三方平台视频播放完成时,子类适配器中调用方法 |
| -(void)trackRewardVodAdDidRewardEffective | 三方平台视频播放达到激励条件时,子类适配器中调用方法 |
| -(void)trackRewardvodAdFailToLoadError:(NSError *)error | 三方平台请求失败时,子类适配器中调用方法 |
| -(void)trackRewardvodAdFailToPresentError:(NSError *)error | 三方平台展示失败时,子类适配器中调用方法 |
| -(void)trackRewardvodAdVideoFailToPlayError:(NSError *)error | 三方平台视频播放错误时,子类适配器中调用方法 |
| -(void)trackRewardvodAdLandingPageClosed | 三方平台关闭落地页时,子类适配器中调用方法 |
| -(void)trackRewardvodAdVideoAdServerRewardDidSucceedWithInfo: | 三方平台广告服务器验证成功(携带激励验证相关参数),子类适配器中调用方法 |
| -(void)trackRewardvodAdVideoAdServerRewardDidFailed: | 广告服务器验证失败 |
| **需子类实现:** | |
| -(void)requestAdWithContext:(ADSuyiCustomAdapterRewardRequestContext *)context | 请求广告方法,必须于子类中实现 |
| -(void)showRewardVodAdFromViewController:(UIViewController * _Nullable)viewController | 展示激励视频方法方法,在该方法实现中调用平台展示方法 |
| -(bool)isReady | 激励视频广告是否准备好 |
| -(bool)isValid | 激励视频广告物料是否有效 |
| -(bool)canServerVerrify | 激励视频广告是否支持服务端验证 |
**demo示例:**
`ADSuyiCustomAdapterBURewardAd.h`
```objc
#import
@interface ADSuyiCustomAdapterBURewardAd : ADSuyiCustomAdapterRewardVodAd
@end
```
`ADSuyiCustomAdapterBURewardAd.m`
```objc
#import "ADSuyiCustomAdapterBURewardAd.h"
#import
#import
@interface ADSuyiCustomAdapterBURewardAd ()
{
BUNativeExpressRewardedVideoAd *_rewardVideoAd;
ADSuyiCustomAdapterRewardRequestContext *_context;
BOOL _isReady;
}
@end
@implementation ADSuyiCustomAdapterBURewardAd
// MARK: - Override
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:(ADSuyiAdapterRenderTypeExpress)];
}
/// 请求
- (void)requestAdWithContext:(ADSuyiCustomAdapterRewardRequestContext *)context {
_context = context;
BURewardedVideoModel *model= [BURewardedVideoModel new];
model.userId = context.userId;
if (context.extra){
model.extra = context.extra;
}
if (context.rewardName){
model.rewardName = context.rewardName;
}
if (context.rewardAmount){
model.rewardAmount = context.rewardAmount.integerValue;
}
_rewardVideoAd = [[BUNativeExpressRewardedVideoAd alloc] initWithSlotID:context.posId rewardedVideoModel:model];
_rewardVideoAd.delegate = self;
_rewardVideoAd.rewardPlayAgainInteractionDelegate = self;
[_rewardVideoAd loadAdData];
}
/// 展示
- (void)showRewardVodAdFromViewController:(UIViewController *)viewController {
if (!viewController) {
viewController = _context.viewController;
}
[_rewardVideoAd showAdFromRootViewController:viewController];
}
- (bool)isReady{
return _isReady;
}
- (bool)isValid{
return _isReady;
}
- (bool)canServerVerrify{
return true;
}
// MARK: - Method
- (void)setIsReady:(BOOL)isReady {
if(_isReady == NO && isReady == YES) {
_isReady = isReady;
[self trackRewardvodAdReadyToPlay];
} else {
_isReady = isReady;
}
}
// MARK: - BUNativeExpressRewardedVideoAdDelegate
/**
This method is called when video ad material loaded successfully.
*/
- (void)nativeExpressRewardedVideoAdDidLoad:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRwardvodAdLoadSuccess];
self.isReady = true;
}
/**
This method is called when video ad materia failed to load.
@param error : the reason of error
*/
- (void)nativeExpressRewardedVideoAd:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd didFailWithError:(NSError *_Nullable)error {
[self trackRewardvodAdFailToLoadError:error];
}
/**
This method is called when cached successfully.
For a better user experience, it is recommended to display video ads at this time.
And you can call [BUNativeExpressRewardedVideoAd showAdFromRootViewController:].
*/
- (void)nativeExpressRewardedVideoAdDidDownLoadVideo:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRewardvodAdVideoLoadSuccess];
_isReady = YES;
}
/**
This method is called when rendering a nativeExpressAdView successed.
It will happen when ad is show.
*/
- (void)nativeExpressRewardedVideoAdViewRenderSuccess:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {}
/**
This method is called when a nativeExpressAdView failed to render.
@param error : the reason of error
*/
- (void)nativeExpressRewardedVideoAdViewRenderFail:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd error:(NSError *_Nullable)error {
[self trackRewardvodAdFailToPresentError:error];
}
/**
This method is called when video ad slot will be showing.
*/
- (void)nativeExpressRewardedVideoAdWillVisible:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRewardvodAdWillVisible];
}
/**
This method is called when video ad slot has been shown.
*/
- (void)nativeExpressRewardedVideoAdDidVisible:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRewardvodAdDidVisible];
}
/**
This method is called when video ad is about to close.
*/
- (void)nativeExpressRewardedVideoAdWillClose:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {}
/**
This method is called when video ad is closed.
*/
- (void)nativeExpressRewardedVideoAdDidClose:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRewardvodAdDidClose];
}
/**
This method is called when video ad is clicked.
*/
- (void)nativeExpressRewardedVideoAdDidClick:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {
[self trackRewardvodAdDidClick];
}
/**
This method is called when the user clicked skip button.
*/
- (void)nativeExpressRewardedVideoAdDidClickSkip:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd {}
/**
This method is called when video ad play completed or an error occurred.
@param error : the reason of error
*/
- (void)nativeExpressRewardedVideoAdDidPlayFinish:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd didFailWithError:(NSError *_Nullable)error {
if(error){
[self trackRewardvodAdVideoFailToPlayError:error];
}else{
[self trackRewardvodAdDidPlayFinish];
}
}
/**
Server verification which is requested asynchronously is succeeded. now include two v erify methods:
1. C2C need server verify 2. S2S don't need server verify
@param verify :return YES when return value is 2000.
*/
- (void)nativeExpressRewardedVideoAdServerRewardDidSucceed:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd verify:(BOOL)verify {
[self trackRewardVodAdDidRewardEffective];
if(verify){
[self trackRewardvodAdVideoAdServerRewardDidSucceedWithInfo:nil];
}else{
// 自定义
NSError *error = [[NSError alloc]initWithDomain:@"custom.adapter.error" code:22052 userInfo:@{NSLocalizedDescriptionKey : @"服务端验证失败,请服务端正确响应穿山甲服务端"}];
[self trackRewardvodAdVideoAdServerRewardDidFailed:error];
}
}
/**
Server verification which is requested asynchronously is failed.
@param rewardedVideoAd express rewardVideo Ad
@param error request error info
*/
- (void)nativeExpressRewardedVideoAdServerRewardDidFail:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd error:(NSError *_Nullable)error {
[self trackRewardvodAdVideoAdServerRewardDidFailed:error];
}
/**
This method is called when another controller has been closed.
@param interactionType : open appstore in app or open the webpage or view video ad details page.
*/
- (void)nativeExpressRewardedVideoAdDidCloseOtherController:(BUNativeExpressRewardedVideoAd *)rewardedVideoAd interactionType:(BUInteractionType)interactionType {
[self trackRewardvodAdLandingPageClosed];
}
@end
```
### 4.1.6 模板信息流
1. 需继承 `ADSuyiCustomAdapterNativeAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackNativeAdSucceedToLoadWithNativeAdViews:(NSArray *)nativeViews | 信息流请求成功 |
| -(void)trackNativeAdFailToLoadWithError:(NSError * _Nullable)error | 信息流请求失败 |
| -(void)trackNativeAdRenderSucceedWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告渲染成功 |
| -(void)trackNativeAdRenderFailedWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告渲染失败 |
| -(void)trackNativeAdExposuredWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告展示 |
| -(void)trackNativeAdClickedWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告点击 |
| -(void)trackNativeAdClosedWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告关闭 |
| -(void)trackNativeAdLandingPageClosedWithNativeView:(ADSuyiCustomAdapterNativeAdView *)nativeView | 信息流广告关闭落地页 |
| **需子类实现:** | |
| -(void)requestAdWithContext:(ADSuyiCustomAdapterNativeRequestContext *)context | 请求广告方法,必须于子类中实现 |
3. 需继承视图父类 `ADSuyiCustomAdapterNativeAdView` , 将模板信息流添加至统一视图中
```objc
@interface ADSuyiCustomAdapterNativeAdView : UIView
@end
```
`ADSuyiAdapterNativeAdViewDelegate`
| 方法 | 参数说明|
|:-----------|:------|
| **需子类实现:** | |
| -(void)adsy_registViews:(NSArray *)clickViews | 注册广告视图 |
| -(void)adsy_unRegistView | 取消注册 |
| -(void)adsy_close | 广告关闭事件,手动调用 |
| -(void)adsy_closeButtonExist | 广告关闭按钮是否存在 |
| -(ADSuyiAdapterRenderType)renderType | 渲染类型 |
| -(ADSuyiAdapterNativeAdData *)data | 自渲染广告数据,模版类型为空 |
| -(nullable UIView *)adsy_mediaViewForWidth:(CGFloat)width | 获取视频视图,如果是模版广告则为nil |
| -(void)adsy_platformLogoImageDarkMode:(BOOL)darkMode loadImageBlock:(void(^)(UIImage * _Nullable))block | 平台logo |
**demo示例:**
`ADSuyiCustomAdapterBUNativeAd.h`
```objc
#import
@interface ADSuyiCustomAdapterBUNativeAd : ADSuyiCustomAdapterNativeAd
@end
```
`ADSuyiCustomAdapterBUNativeAd.m`
```objc
#import "ADSuyiCustomAdapterBUNativeAd.h"
#import
#import "ADSuyiCustomAdapterBUNativeAdView.h"
@interface ADSuyiCustomAdapterBUNativeAd ()
{
BUNativeExpressAdManager *_nativeExpressAd;
NSMapTable *_weakMapTable;
NSHashTable *_hashTable;
ADSuyiCustomAdapterNativeRequestContext *_context;
}
@end
@implementation ADSuyiCustomAdapterBUNativeAd
// MARK: - Override
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"toutiao" renderType:(ADSuyiAdapterRenderTypeExpress)];
}
- (instancetype)init{
self = [super init];
if(self){
_weakMapTable = [NSMapTable weakToWeakObjectsMapTable];
_hashTable = [NSHashTable new];
}
return self;
}
- (void)requestAdWithContext:(ADSuyiCustomAdapterNativeRequestContext *)context {
_context = context;
if(!_nativeExpressAd) {
BUAdSlot *slot = [BUAdSlot new];
slot.ID = context.posId;
slot.AdType = BUAdSlotAdTypeFeed;
slot.position = BUAdSlotPositionFeed;
BUSize *imageSize = [BUSize sizeBy:BUProposalSize_Feed690_388];
slot.imgSize = imageSize;
_nativeExpressAd = [[BUNativeExpressAdManager alloc] initWithSlot:slot
adSize:CGSizeMake(context.adSize.width, 0)];
_nativeExpressAd.delegate = self;
}
[_nativeExpressAd loadAdDataWithCount:context.loadCount];
}
// MARK: - Helper
- (NSArray *)creatNativeViewFrom:(NSArray<__kindof BUNativeExpressAdView *> *)views {
NSMutableArray *dataArray = [NSMutableArray new];
for (BUNativeExpressAdView *view in views) {
ADSuyiCustomAdapterBUNativeAdView *nativeView = [ADSuyiCustomAdapterBUNativeAdView new];
nativeView.buNativeAdView = view;
view.rootViewController = _context.viewController;
[dataArray addObject:nativeView];
nativeView.delegate = self;
[_weakMapTable setObject:nativeView forKey:view];
}
return dataArray.copy;
}
// MARK: - BUNativeExpressAdViewDelegate
/**
* Sent when views successfully load ad
*/
- (void)nativeExpressAdSuccessToLoad:(BUNativeExpressAdManager *)nativeExpressAdManager views:(NSArray<__kindof BUNativeExpressAdView *> *)views {
NSArray *adViewArray = [self creatNativeViewFrom:views];
[self trackNativeAdSucceedToLoadWithNativeAdViews:adViewArray];
}
/**
* Sent when views fail to load ad
*/
- (void)nativeExpressAdFailToLoad:(BUNativeExpressAdManager *)nativeExpressAdManager error:(NSError *_Nullable)error {
[self trackNativeAdFailToLoadWithError:error];
}
/**
* This method is called when rendering a nativeExpressAdView successed, and nativeExpressAdView.size.height has been updated
*/
- (void)nativeExpressAdViewRenderSuccess:(BUNativeExpressAdView *)nativeExpressAdView {
ADSuyiCustomAdapterBUNativeAdView *adView = [_weakMapTable objectForKey:nativeExpressAdView];
if(!adView)return;
[_hashTable removeObject:adView];
adView.frame = nativeExpressAdView.bounds;
[self trackNativeAdRenderSucceedWithNativeView:adView];
}
/**
* This method is called when a nativeExpressAdView failed to render
*/
- (void)nativeExpressAdViewRenderFail:(BUNativeExpressAdView *)nativeExpressAdView error:(NSError *_Nullable)error {
ADSuyiCustomAdapterBUNativeAdView *adView = [_weakMapTable objectForKey:nativeExpressAdView];
if(!adView)return;
[_hashTable removeObject:adView];
[self trackNativeAdRenderFailedWithNativeView:adView];
}
/**
* Sent when an ad view is about to present modal content
*/
- (void)nativeExpressAdViewWillShow:(BUNativeExpressAdView *)nativeExpressAdView {
[self trackNativeAdExposuredWithNativeView:[_weakMapTable objectForKey:nativeExpressAdView]];
}
/**
* Sent when an ad view is clicked
*
*/
- (void)nativeExpressAdViewDidClick:(BUNativeExpressAdView *)nativeExpressAdView {
[self trackNativeAdClickedWithNativeView:[_weakMapTable objectForKey:nativeExpressAdView]];
}
/**
Sent when a playerw playback status changed.
@param playerState : player state after changed
*/
- (void)nativeExpressAdView:(BUNativeExpressAdView *)nativeExpressAdView stateDidChanged:(BUPlayerPlayState)playerState {
}
/**
* Sent when a player finished
* @param error : error of player
*/
- (void)nativeExpressAdViewPlayerDidPlayFinish:(BUNativeExpressAdView *)nativeExpressAdView error:(NSError *)error {
}
/**
* Sent when a user clicked dislike reasons.
* @param filterWords : the array of reasons why the user dislikes the ad
*/
- (void)nativeExpressAdView:(BUNativeExpressAdView *)nativeExpressAdView dislikeWithReason:(NSArray *)filterWords {
[self trackNativeAdClosedWithNativeView:[_weakMapTable objectForKey:nativeExpressAdView]];
}
/**
* Sent after an ad view is clicked, a ad landscape view will present modal content
*/
- (void)nativeExpressAdViewWillPresentScreen:(BUNativeExpressAdView *)nativeExpressAdView {
}
/**
This method is called when another controller has been closed.
@param interactionType : open appstore in app or open the webpage or view video ad details page.
*/
- (void)nativeExpressAdViewDidCloseOtherController:(BUNativeExpressAdView *)nativeExpressAdView interactionType:(BUInteractionType)interactionType {
[self trackNativeAdLandingPageClosedWithNativeView:[_weakMapTable objectForKey:nativeExpressAdView]];
}
/**
This method is called when the Ad view container is forced to be removed.
@param nativeExpressAdView : Ad view container
*/
- (void)nativeExpressAdViewDidRemoved:(BUNativeExpressAdView *)nativeExpressAdView {
}
-(void)adsyCustomNativeViewRenderSuccess:(ADSuyiCustomAdapterBUNativeAdView *)nativeView{
[_hashTable addObject:nativeView];
}
@end
```
`ADSuyiCustomAdapterBUNativeAdView.h`
```objc
#import
#import
@class ADSuyiCustomAdapterBUNativeAdView;
@protocol ADSuyiCustomAdapterBUNativeViewDelegate
- (void)adsyCustomNativeViewRenderSuccess:(ADSuyiCustomAdapterBUNativeAdView *)nativeView;
@end
@interface ADSuyiCustomAdapterBUNativeAdView : ADSuyiCustomAdapterNativeAdView
/// 平台信息流广告视图
@property (nonatomic, strong) BUNativeExpressAdView *buNativeAdView;
@property (nonatomic, weak) id delegate;
@end
```
`ADSuyiCustomAdapterBUNativeAdView.m`
```objc
#import "ADSuyiCustomAdapterBUNativeAdView.h"
@interface ADSuyiCustomAdapterBUNativeAdView ()
@end
@implementation ADSuyiCustomAdapterBUNativeAdView
#pragma mark - setter
- (void)setBuNativeAdView:(BUNativeExpressAdView *)buNativeAdView{
_buNativeAdView = buNativeAdView;
[self addSubview:buNativeAdView];
}
#pragma mark - ADSuyiAdapterNativeAdViewDelegate
- (void)adsy_registViews:(NSArray *)clickViews {
[self.buNativeAdView render];
[self.delegate adsyCustomNativeViewRenderSuccess:self];
}
- (void)adsy_unRegistView {
}
- (ADSuyiAdapterRenderType)renderType {
return ADSuyiAdapterRenderTypeExpress;
}
- (ADSuyiAdapterNativeAdData *)data {
return nil;
}
- (nullable UIView *)adsy_mediaViewForWidth:(CGFloat)width {
return nil;
}
- (BOOL)adsy_closeButtonExist {
// 是否存在关闭按钮
return YES;
}
#pragma mark - ADSuyiAdViewInfoProtocol
- (ADSuyiAdapterPlatform)adsy_platform {
return @"toutiao";
}
@end
```
### 4.1.7 自渲染信息流
1. 需继承 `ADSuyiCustomAdapterUnifiedNativeAd`
2. 通过以下方法子类进行调用 & 子类进行实现来完成适配
| 方法 | 参数说明|
|:-----------|:------|
| -(void)trackNativeAdSucceedToLoadWithNativeAdViews:(NSArray *>*)nativeViews | 信息流请求成功 |
| -(void)trackNativeAdFailToLoadWithError:(NSError * _Nullable)error | 信息流请求失败 |
| -(void)trackNativeAdRenderSucceedWithNativeView:(UIView *)nativeView | 信息流广告渲染成功 |
| -(void)trackNativeAdRenderFailedWithNativeView:(UIView *)nativeView | 信息流广告渲染失败 |
| -(void)trackNativeAdExposuredWithNativeView:(UIView *)nativeView | 信息流广告展示 |
| -(void)trackNativeAdClickedWithNativeView:(UIView *)nativeView | 信息流广告点击 |
| -(void)trackNativeAdClosedWithNativeView:(UIView *)nativeView | 信息流广告关闭 |
| -(void)trackNativeAdLandingPageClosedWithNativeView:(UIView *)nativeView | 信息流广告关闭落地页 |
| **需子类实现:** | |
| -(void)requestAdWithContext:(ADSuyiCustomAdapterNativeRequestContext *)context | 请求广告方法,必须于子类中实现 |
3. 视图需遵循协议,并实现协议方法 `ADSuyiAdapterNativeAdViewDelegate` , 将模板信息流添加至统一视图中
**demo示例:**
> 不同的平台实现方式不同,需根据平台进行适配,适配过程中有疑问,请联系技术同学提供支持
`ADSuyiCustomAdapterGDTUnifiedNativeAd.h`
```objc
#import
@interface ADSuyiCustomAdapterGDTUnifiedNativeAd : ADSuyiCustomAdapterUnifiedNativeAd
@end
```
`ADSuyiCustomAdapterGDTUnifiedNativeAd.m`
```objc
#import "ADSuyiCustomAdapterGDTUnifiedNativeAd.h"
#import
#import
#import
#import "ADSuyiCustomAdapterGDTUnifiedNativeAdView.h"
@interface ADSuyiCustomAdapterGDTUnifiedNativeAd ()
{
ADSuyiCustomAdapterNativeRequestContext *_context;
GDTUnifiedNativeAd *_unifiedNativeAdAd;
NSMapTable *_weakMap;
}
@end
@implementation ADSuyiCustomAdapterGDTUnifiedNativeAd
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:@"gdt" renderType:(ADSuyiAdapterRenderTypeNative)];
}
- (instancetype)init
{
self = [super init];
if (self) {
_weakMap = [NSMapTable weakToWeakObjectsMapTable];
}
return self;
}
// MARK: - Override
- (void)requestAdWithContext:(ADSuyiCustomAdapterNativeRequestContext *)context {
_context = context;
[self.unifiedNativeAdAd loadAdWithAdCount:_context.loadCount];
}
// MARK: - GDTUnifiedNativeAdDelegate
- (void)gdt_unifiedNativeAdLoaded:(NSArray * _Nullable)unifiedNativeAdDataObjects error:(NSError * _Nullable)error {
if(error) {
[self trackNativeAdFailToLoadWithError:error];
return;
}
NSMutableArray *> *adViewArray = [NSMutableArray new];
for (GDTUnifiedNativeAdDataObject *dataObj in unifiedNativeAdDataObjects) {
ADSuyiCustomAdapterGDTUnifiedNativeAdView *adView = [ADSuyiCustomAdapterGDTUnifiedNativeAdView new];
adView.adData = dataObj;
adView.delegate = self;
adView.unifiedNativeAdDelegate = self;
adView.viewController = _context.viewController;
[adViewArray addObject:adView];
[_weakMap setObject:adView forKey:dataObj];
adView.adData.videoConfig.videoMuted = YES;
}
[self trackNativeAdSucceedToLoadWithNativeAdViews:adViewArray];
}
// MARK: - GDTUnifiedNativeAdViewDelegate
- (void)gdt_unifiedNativeAdViewWillExpose:(GDTUnifiedNativeAdView *)unifiedNativeAdView {
ADSuyiCustomAdapterGDTUnifiedNativeAdView *adView = [_weakMap objectForKey:unifiedNativeAdView.dataObject];
[self trackNativeAdExposuredWithNativeView:adView];
}
- (void)gdt_unifiedNativeAdViewDidClick:(GDTUnifiedNativeAdView *)unifiedNativeAdView {
ADSuyiCustomAdapterGDTUnifiedNativeAdView *adView = [_weakMap objectForKey:unifiedNativeAdView.dataObject];
[self trackNativeAdClickedWithNativeView:adView];
}
- (void)gdt_unifiedNativeAdDetailViewClosed:(GDTUnifiedNativeAdView *)unifiedNativeAdView {
ADSuyiCustomAdapterGDTUnifiedNativeAdView *adView = [_weakMap objectForKey:unifiedNativeAdView.dataObject];
[self trackNativeAdLandingPageClosedWithNativeView:adView];
}
// MARK: - ADSuyiCustomAdapterUnifiedNativeAdViewDelegate
- (void)adsyCustomUnifiedNativeAdViewRender:(ADSuyiCustomAdapterGDTUnifiedNativeAdView *)adView {
[self trackNativeAdRenderSucceedWithNativeView:adView];
}
- (void)adsyCustomUnifiedNativeAdViewClose:(ADSuyiCustomAdapterGDTUnifiedNativeAdView *)adView {
[self trackNativeAdClosedWithNativeView:adView];
}
// MARK: - Lazy load
- (GDTUnifiedNativeAd *)unifiedNativeAdAd {
if(!_unifiedNativeAdAd) {
_unifiedNativeAdAd = [[GDTUnifiedNativeAd alloc] initWithPlacementId:_context.posId];
_unifiedNativeAdAd.delegate = self;
}
return _unifiedNativeAdAd;
}
@end
```
`ADSuyiCustomAdapterGDTUnifiedNativeAdView.h`
```objc
#import
#import
#import
#import
@class ADSuyiCustomAdapterGDTUnifiedNativeAdView;
@protocol ADSuyiCustomAdapterGDTUnifiedNativeAdViewDelegate
- (void)adsyCustomUnifiedNativeAdViewRender:(ADSuyiCustomAdapterGDTUnifiedNativeAdView *)adView;
- (void)adsyCustomUnifiedNativeAdViewClose:(ADSuyiCustomAdapterGDTUnifiedNativeAdView *)adView;
@end
@interface ADSuyiCustomAdapterGDTUnifiedNativeAdView : GDTUnifiedNativeAdView
@property (nonatomic, strong) GDTUnifiedNativeAdDataObject *adData;
@property (nonatomic, weak) id unifiedNativeAdDelegate;
@end
```
`ADSuyiCustomAdapterGDTUnifiedNativeAdView.m`
```objc
#import "ADSuyiCustomAdapterGDTUnifiedNativeAdView.h"
@interface ADSuyiAdapterNativeAdData()
- (instancetype)initWithTitle:(NSString *)title
content:(NSString *)content
imageUrlStringArray:(NSArray *)imageUrlStringArray
iconImage:(nullable UIImage *)iconImage
iconImageUrl:(nullable NSString *)iconImageUrl
shouldShowMediaView:(BOOL)shouldShowMediaView;
@end
@interface ADSuyiCustomAdapterGDTUnifiedNativeAdView ()
{
ADSuyiAdapterNativeAdData *_data;
CGFloat _width;
}
@end
@implementation ADSuyiCustomAdapterGDTUnifiedNativeAdView
#pragma mark - ADSuyiAdapterNativeAdViewDelegate
- (void)adsy_registViews:(NSArray *)clickViews {
[self registerDataObject:_adData clickableViews:clickViews];
if([self.delegate respondsToSelector:@selector(adsyCustomUnifiedNativeAdViewRender:)]) {
[self.unifiedNativeAdDelegate adsyCustomUnifiedNativeAdViewRender:self];
}
}
- (ADSuyiAdapterNativeAdData *)data {
return _data;
}
- (nullable UIView *)adsy_mediaViewForWidth:(CGFloat)width {
[self.mediaView muteEnable:YES];
return self.mediaView;
}
- (void)adsy_platformLogoImageDarkMode:(BOOL)darkMode loadImageBlock:(void (^)(UIImage * _Nullable))block {
if (!block) {
return;
}
block(nil);
}
- (ADSuyiAdapterRenderType)renderType {
return ADSuyiAdapterRenderTypeNative;
}
- (void)adsy_unRegistView {
[self unregisterDataObject];
}
- (void)adsy_close {
[self.unifiedNativeAdDelegate adsyCustomUnifiedNativeAdViewClose:self];
}
- (BOOL)adsy_closeButtonExist {
return NO;
}
#pragma mark - Set
- (void)setAdData:(GDTUnifiedNativeAdDataObject *)adData {
_adData = adData;
NSArray *imageUrlStringArray = @[];
if(_adData.imageUrl) {
imageUrlStringArray = @[_adData.imageUrl];
}
_data = [[ADSuyiAdapterNativeAdData alloc] initWithTitle:_adData.title
content:_adData.desc
imageUrlStringArray:imageUrlStringArray
iconImage:nil
iconImageUrl:_adData.iconUrl
shouldShowMediaView:_adData.isVideoAd];
}
#pragma mark - ADSuyiAdViewInfoProtocol
- (ADSuyiAdapterPlatform)adsy_platform {
return @"gdt";
}
@end
```
### 4.1.8 竞价
> 已 gdt 开屏为例子
| 方法 | 参数说明|
|:-----------|:------|
| -(void)splashAdViewBiddingByPrice:(double)eCPM | 三方平台竞价广告询价请求成功时,子类适配器中调用方法
eCPM: 分 |
| -(void)splashAdViewBiddingByError:(NSError *)error | 三方平台竞价广告询价请求失败时,子类适配器中调用方法 |
| **需子类实现:** | |
| -(void)biddingRequestWithContext:(ADSuyiCustomAdapterSplashRequestContext *)context | 竞价询价请求 |
| -(void)biddingResult:(ADSuyiSDKSourceBiddingResult)result AllPrice:(NSArray *)allPrices | 竞价结果,该方法内实现仅处理三方竞价结果上报即可
allPrices: 分 |
**demo示例:**
`ADSuyiCustomAdapterGDTBiddingSplashAd.h`
```objc
#import
/// GDT 支持 Bidding 的写法
@interface ADSuyiCustomAdapterGDTBiddingSplashAd : ADSuyiCustomAdapterSplashAd
@end
```
`ADSuyiCustomAdapterGDTBiddingSplashAd.m`
```objc
#import "ADSuyiCustomAdapterGDTBiddingSplashAd.h"
#import
@interface ADSuyiCustomAdapterGDTBiddingSplashAd()
@property (nonatomic, assign) bool isLoadSuccess;/**< 加载是否成功,该字段是为了处理gdt的失败回调 */
@property (nonatomic, strong) ADSuyiCustomAdapterSplashRequestContext *context;
@property (nonatomic, strong) GDTSplashAd *splashAd;
@end
@implementation ADSuyiCustomAdapterGDTBiddingSplashAd
+ (void)load {
[self registPlatformAdLoaderClass:self forSdkName:ADSuyiAdapterPlatformGDT renderType:ADSuyiAdapterRenderTypeExpress];
}
/// 请求
- (void)requestAdWithContext:(ADSuyiCustomAdapterSplashRequestContext *)context{
_context = context;
[self request:context];
}
/// !!!: 竞价:询价请求
- (void)biddingRequestWithContext:(ADSuyiCustomAdapterSplashRequestContext *)context{
_context = context;
[self request:context];
}
/// !!!: 竞价:竞价结果,该方法内实现仅处理三方广告竞价结果上报即可
- (void)biddingResult:(ADSuyiSDKSourceBiddingResult)result AllPrice:(NSArray *)allPrices{
// 获取一价二价
NSNumber *winnerPrice = 0;
NSNumber *secondPrice = 0;
if (allPrices.count > 0) {
NSNumber *firstPrice = allPrices.firstObject;
// 聚合平台存储为单位为:分,GDT 是以元返回,同时也需要已元上报
winnerPrice = [NSNumber numberWithFloat:firstPrice.floatValue * 100];
}
if (allPrices.count > 1) {
NSNumber *tempSecondPrice = allPrices[1];
secondPrice = [NSNumber numberWithFloat:tempSecondPrice.floatValue * 100];
}
switch (result) {
case ADSuyiSDKSourceBiddingResult_Sucess:
[self sendWinNotificationWithWinnerPrice:[NSNumber numberWithInteger:_splashAd.eCPM] withSecondPrice:secondPrice];
break;
case ADSuyiSDKSourceBiddingResult_Failed:
[self sendLossNotificationWithPrice:winnerPrice withRease:GDTAdBiddingLossReasonLowPrice withWinnerAdnID:@""];
break;
case ADSuyiSDKSourceBiddingResult_Timeout:
[self sendLossNotificationWithPrice:0 withRease:GDTAdBiddingLossReasonNoAd withWinnerAdnID:@""];
break;
default:
[self sendLossNotificationWithPrice:0 withRease:GDTAdBiddingLossReasonOther withWinnerAdnID:@""];
break;
}
}
/// 展示
- (void)customAdapter_onAdReceive{
[_splashAd showAdInWindow:_context.window withBottomView:_context.bottomView skipView:_context.skipView];
}
// MARK: - Method
- (void)request:(ADSuyiCustomAdapterSplashRequestContext *)context{
_splashAd = [[GDTSplashAd alloc] initWithPlacementId:context.posId];
_splashAd.delegate = self;
_splashAd.serverSideVerificationOptions = [[GDTServerSideVerificationOptions alloc]init];
if (context.userId){
_splashAd.serverSideVerificationOptions.userIdentifier = context.userId;
}
if (context.extra){
_splashAd.serverSideVerificationOptions.customRewardString = context.extra;
}
[_splashAd loadAd];
}
/** 竞赢上报
* infoDic 字典类型,支持的key有
* GDT_M_W_E_COST_PRICE:竞胜价格 (单位: 分),值类型为NSNumber *
* GDT_M_W_H_LOSS_PRICE:最高失败出价,值类型为NSNumber *
*/
- (void)sendWinNotificationWithWinnerPrice:(NSNumber *)winnerPrice withSecondPrice:(NSNumber *)secondPrice{
if(winnerPrice == nil){
return ;
}
NSMutableDictionary *infoDic = [NSMutableDictionary dictionary];
[infoDic setValue:winnerPrice forKey:GDT_M_W_E_COST_PRICE];
if (secondPrice != nil) {
[infoDic setValue:secondPrice forKey:GDT_M_W_H_LOSS_PRICE];
}else{
[infoDic setValue:@(0) forKey:GDT_M_W_H_LOSS_PRICE];
}
[_splashAd sendWinNotificationWithInfo:infoDic.copy];
}
/**
* 竞败之后或未参竞调用
*
* infoDic 竞败信息,字典类型,支持的key有
* GDT_M_L_WIN_PRICE :竞胜价格 (单位: 分),值类型为NSNumber *,选填
* GDT_M_L_LOSS_REASON :优量汇广告竞败原因,竞败原因参考枚举GDTAdBiddingLossReason中的定义,值类型为NSNumber *,必填
* GDT_M_ADNID :竞胜方渠道ID,值类型为NSString *,必填
*/
- (void)sendLossNotificationWithPrice:(NSNumber *)price withRease:(GDTAdBiddingLossReason)reason withWinnerAdnID:(NSString *)winnerAdnID{
NSMutableDictionary *infoDic = [NSMutableDictionary dictionary];
[infoDic setValue:price forKey:GDT_M_L_WIN_PRICE];
[infoDic setValue:@(reason) forKey:GDT_M_L_LOSS_REASON];
[infoDic setValue:winnerAdnID forKey:GDT_M_ADNID];
[_splashAd sendLossNotificationWithInfo:infoDic.copy];
}
// MARK: - GDTSplashAdDelegate
- (void)splashAdSuccessPresentScreen:(GDTSplashAd *)splashAd {
[self trackSplashAdSuccessToPresent];
}
- (void)splashAdDidLoad:(GDTSplashAd *)splashAd {
_isLoadSuccess = YES;
NSInteger price = _splashAd.eCPM;
[self trackSplashAdSucceed:price/100.00];
}
- (void)splashAdFailToPresent:(GDTSplashAd *)splashAd withError:(NSError *)error {
// gdt 的失败回调特殊处理,加载成功之后调用失败,则说明广告数据加载成功,可能是present失败,所以属于展示失败,展示失败直接返回失败
if(_isLoadSuccess) {
[self trackSplashAdFailedToPresentWithError:error];
// 直接失败,说明广告数据加载失败,属于请求失败么,请求失败轮询下一个平台
} else {
[self trackSplashAdFailedWithError:error];
}
}
// 跳转其他页面也当作关闭处理
- (void)splashAdApplicationWillEnterBackground:(GDTSplashAd *)splashAd {
[self splashAdClosed:splashAd];
}
- (void)splashAdExposured:(GDTSplashAd *)splashAd {
[self trackSplashAdDisplay];
}
- (void)splashAdClicked:(GDTSplashAd *)splashAd {
[self trackSplashAdClicked];
}
- (void)splashAdClosed:(GDTSplashAd *)splashAd {
[self trackSplashAdClosed];
}
- (void)splashAdDidDismissFullScreenModal:(GDTSplashAd *)splashAd {
[self trackSplashAdLandingPageClosed];
}
-(void)splashAdDidRewardEffective:(GDTSplashAd *)splashAd info:(NSDictionary *)info{
[self trackSplashAdDidRewardEffective:info];
}
@end
```