Skip to content

自定义广告平台Adapter实现

简介

本文档将介绍在iOS端如何实现自定义广告平台Adapter,主要包括初始化、加载广告、展示广告以及各广告类型的响应事件回调处理。文档中代码截取来源于Demo

支持广告类型

目前支持的广告类型有五种,如下所示:

  • 原生广告(Native)
  • 开屏广告(Splash)
  • Banner广告
  • 激励视频广告(RewardedVideo)
  • 插屏广告(Interstitial)

核心流程实现

  1. 定义Adapter类名,包括配置Adapter以及各广告类型对应Adapter,并遵循相关协议;
  2. 在ToBid开发者平台配置相关信息,详情参见平台部分文档;
  3. 实现协议方法完成初始化(含隐私合规)、广告加载、展示方法及回调,详见下方说明;

常见问题

  1. 自定义Adapter需要按照示例中相应方法含义调用,否则会影响收益;
  2. 及时更新协议版本号为ToBid支持的最新版本,否则可能无法使用;
  3. 自定义Adapter广告load之前需要确保开发者实现了AWMCustomConfigAdapter协议并初始化network成功,network版本号,Adapter版本号均不能为空;
  4. 自定义Adapter广告load成功或者失败只能调用一次;
  5. 所有调用自定义adapter的方法均在主线程,请勿进行耗时操作;
  6. 自定义Adapter支持广告频次控制、广告间隔控制、AB测试;
  7. 自定义Adapter不支持show时预加载、Service bidding、多阶底价。支持Client bidding;
  8. 自定义Adapter广告对象的show、click等回调需要在load广告回调之后;
  9. ToBid已经处理了Banner的轮播,自定义Banner需要禁用轮播。

初始化配置

协议内容

自定义Adapter必须要有配置类,在配置类中完成Adapter及对应network的信息采集,对应协议为AWMCustomConfigAdapter,接口实现如下所示:

objective-c
@protocol AWMCustomConfigAdapter <NSObject>
/// 构造函数,通过bridge通知初始化成功和失败
/// param bridge 通过Bridge通知初始化成功或初始化失败等事件
///
- (nonnull instancetype)initWithBridge:(id <AWMCustomConfigAdapterBridge> _Nonnull)bridge;
/// adn初始化方法
/// param configuration 初始化配置,包括appid、appkey基本信息和用户自定义参数等
///
- (void)initializeAdapterWithConfiguration:(AWMSdkInitConfig * _Nonnull)configuration;
- (void)didRequestAdPrivacyConfigUpdate:(NSDictionary<NSString *, id> * _Nonnull)config;
/// 用于ToBid获取Adapter的版本号
///
/// returns:
/// Adapter的版本号
- (NSString * _Nonnull)adapterVersion SWIFT_WARN_UNUSED_RESULT;
/// 用于ToBid获取渠道的版本号
///
/// returns:
/// 渠道的版本号
- (NSString * _Nonnull)networkSdkVersion SWIFT_WARN_UNUSED_RESULT;
@optional
/// 支持的最低OS版本号
///
/// returns:
/// 当前渠道最低支持的系统版本号
- (NSString * _Nonnull)minSupportOSVersion SWIFT_WARN_UNUSED_RESULT;
/// 该自定义adapter是基于哪个版本实现的,填写编写时的最新值即可
///
/// returns:
/// AWMCustomAdapterVersion.V2_0
- (AWMCustomAdapterVersion * _Nonnull)basedOnCustomAdapterVersion SWIFT_WARN_UNUSED_RESULT;
@end
Swift
@objc public protocol AWMCustomConfigAdapter: NSObjectProtocol  {
    
    /// 构造函数,通过bridge通知初始化成功和失败
    /// - Parameter bridge: 通过Bridge通知初始化成功或初始化失败等事件
    @objc init(bridge: AWMCustomConfigAdapterBridge)
    
    /// adn初始化方法
    /// - Parameter configuration: 初始化配置,包括appid、appkey基本信息和用户自定义参数等
    @objc func initializeAdapter(configuration: AWMSdkInitConfig)
    
    @objc func didRequestAdPrivacyConfigUpdate(_ config: [String: Any])
    
    /// 用于ToBid获取Adapter的版本号
    /// - Returns: Adapter的版本号
    @objc func adapterVersion() ->String
    
    /// 用于ToBid获取渠道的版本号
    /// - Returns: 渠道的版本号
    @objc func networkSdkVersion() ->String
    
    /// 支持的最低OS版本号
    /// - Returns: 当前渠道最低支持的系统版本号
    @objc optional func minSupportOSVersion() -> String
    
    /// 该自定义adapter是基于哪个版本实现的,填写编写时的最新值即可
    /// - Returns: AWMCustomAdapterVersion.V2_0
    @objc optional func basedOnCustomAdapterVersion()-> AWMCustomAdapterVersion
}

示例代码

Objective-C
@interface XXCustomConfigAdapter ()
@property (nonatomic, weak) id<AWMCustomConfigAdapterBridge> bridge;
@end

@implementation XXCustomConfigAdapter
- (instancetype)initWithBridge:(id<AWMCustomConfigAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (AWMCustomAdapterVersion *)basedOnCustomAdapterVersion {
    return AWMCustomAdapterVersion1_0;
}
- (NSString *)adapterVersion {
    return @"1.0.0";
}
- (NSString *)networkSdkVersion {
    return [BUAdSDKManager SDKVersion];
}
- (void)initializeAdapterWithConfiguration:(AWMSdkInitConfig *)initConfig {

}
/// 隐私权限更新,用户更新隐私配置时触发,初始化方法调用前一定会触发一次
- (void)didRequestAdPrivacyConfigUpdate:(NSDictionary *)config {
    //调用三方adn隐私设置接口
}
@end
Swift
@objc public class XXCustomConfigAdapter: NSObject, AWMCustomConfigAdapter {
    
    private weak var bridge: AWMCustomConfigAdapterBridge?
    
    @objc public required init(bridge: AWMCustomConfigAdapterBridge) {
        self.bridge = bridge
    }
    
    @objc public func initializeAdapter(configuration: AWMSdkInitConfig) {
        
    }
    
    @objc public func didRequestAdPrivacyConfigUpdate(_ config: [String: Any]) {
        //调用三方adn隐私设置接口
    }
    
    @objc public func adapterVersion() -> String {
        return "1.0.0"
    }
    
    @objc public func networkSdkVersion() -> String {
        return BUAdSDKManager.SDKVersion()
    }
    
    @objc public optional func minSupportOSVersion() -> String {
        return "11.0"
    }
    
    @objc public optional func basedOnCustomAdapterVersion() -> AWMCustomAdapterVersion {
        return AWMCustomAdapterVersion1_0
    }
}

开屏广告(Splash)

协议内容

自定义Splash adapter中需要实现的协议为AWMCustomSplashAdapter,接口实现如下所示:

Objective-C
@protocol AWMCustomSplashAdapter <AWMCustomAdapter>

/// 构造方法
/// 通过bridge回传广告状态
- (nonnull instancetype)initWithBridge:(id <AWMCustomSplashAdapterBridge> _Nonnull)bridge;

/// 加载广告的方法
/// @param placementId adn的广告位ID
/// @param parameter 广告加载的参数
- (void)loadAdWithPlacementId:(NSString * _Nonnull)placementId parameter:(AWMParameter * _Nonnull)parameter;

/// 展示开屏广告
/// @param window 广告展示窗口
/// @param parameter 广告展示参数
- (void)showSplashAdInWindow:(UIWindow * _Nonnull)window parameter:(AWMParameter * _Nonnull)parameter;

@end
Swift
@objc public protocol AWMCustomSplashAdapter: NSObjectProtocol  {
    
    /// 构造函数,通过bridge通知初始化成功和失败
    /// - Parameter bridge: 通过Bridge通知初始化成功或初始化失败等事件
    @objc init(bridge: AWMCustomSplashAdapterBridge)
    
    /// 加载广告的方法
    /// - Parameters:
    ///   - placementId: adn的广告位ID
    ///   - parameter: 广告加载的参数
    @objc func loadAdWithPlacementId(_ placementId: String, parameter: AWMParameter)
    
    /// 展示开屏广告
    /// - Parameters:
    ///   - window: 广告展示窗口
    ///   - parameter: 广告展示参数
    @objc func showSplashAdInWindow(_ window: UIWindow, parameter: AWMParameter)
}

广告加载

在Splash广告的adapter中使用如下方法完成广告加载,其中parameter参数包括了本次广告加载的所有数据,支持的参数详见下方加载参数部分,更完整信息请查看WindMillSDK.h文件。

Objective-C
@interface XXCSJCustomSplashAdapter ()
@property (nonatomic, weak) id<AWMCustomSplashAdapterBridge> bridge;
@property (nonatomic, strong) BUSplashAd *splashAd;
@end

@implementation XXCSJCustomSplashAdapter
- (instancetype)initWithBridge:(id<AWMCustomSplashAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (BOOL)mediatedAdStatus {
    return YES;
}
- (void)loadAdWithPlacementId:(NSString *)placementId parameter:(AWMParameter *)parameter {
    UIViewController *viewController = [self.bridge viewControllerForPresentingModalView];
    UIView *bottomView = [parameter.extra objectForKey:AWMAdLoadingParamSPCustomBottomView];
    UIView *supView = viewController.navigationController ? viewController.navigationController.view : viewController.view;
    NSValue *sizeValue = [parameter.extra objectForKey:AWMAdLoadingParamSPExpectSize];
    CGSize adSize = [sizeValue CGSizeValue];
    if (adSize.width * adSize.height == 0) {
        CGFloat h = CGRectGetHeight(bottomView.frame);
        adSize = CGSizeMake(supView.frame.size.width, supView.frame.size.height - h);
    }
    NSInteger splashType = [[parameter.customInfo objectForKey:@"splashType"] intValue];
    int fetchDelay = [[parameter.extra objectForKey:AWMAdLoadingParamSPTolerateTimeout] intValue];
    self.splashAd = [[BUSplashAd alloc] initWithSlotID:parameter.placementId adSize:adSize];
    self.splashAd.delegate = self;
    self.splashAd.cardDelegate = self;
    self.splashAd.zoomOutDelegate = self;
    self.splashAd.tolerateTimeout = fetchDelay;
    [self.splashAd loadAdData];
}
- (void)destory {
    [self.splashAd removeSplashView];
    self.splashAd = nil;
}
@end
Swift
import Foundation
import UIKit
import WindMillSDK
import BUAdSDK

class SplashAdAdapter: AWMCustomSplashAdapter {
    
    let bridge: AWMCustomSplashAdapterBridge?
    var listener: SplashAdListener?
    var splashAd: BUSplashAd?
    weak var bottomView: UIView?
    weak var parameter: AWMParameter?

    required init(bridge: any AWMCustomSplashAdapterBridge) {
        self.bridge = bridge
        self.setup()
    }
    
    private func setup() {
        self.listener = SplashAdListener(bridge: self.bridge, adapter: self)
    }
    
    func loadAd(placementId: String, parameter: AWMParameter) {
        self.listener?.parameter = parameter
        let value = parameter.customInfo?["fetchDelay"] as? String ?? "5"
         let fetchDelay = value.nx_toInt(defaultValue: 5)
        var adSize: CGSize = .zero
        if let sizeValue = parameter.extra[WindMillConstant.AdSize] as? NSValue {
            adSize = sizeValue.cgSizeValue
        }
        if let rootViewController = bridge?.viewControllerForPresentingModalView() {
            let bottomView = parameter.extra[WindMillConstant.BottomView] as? UIView
            let supView = rootViewController.navigationController?.view ?? rootViewController.view
            if adSize.width * adSize.height == 0, let supView = supView {
                let bottomHeight = bottomView?.frame.height ?? 0
                adSize = CGSize(width: supView.frame.width, height: supView.frame.height - bottomHeight)
            }
        }
        
        splashAd = BUSplashAd(slotID: placementId, adSize: adSize)
        splashAd?.delegate = self.listener
        splashAd?.cardDelegate = self.listener
        splashAd?.tolerateTimeout = TimeInterval(fetchDelay)
        splashAd?.loadData()
    }
    
    func mediatedAdStatus() -> Bool {
        return self.listener?.mediatedAdStatus() ?? false
    }

    func getMediaExt() -> [String : Any] {
        var options: [String : Any] = [:]
        if let requestId = splashAd?.mediaExt?["request_id"] {
            options[WindMillConstant.RequestID] = requestId
        }
        return options
    }
    
    func didReceiveBidResult(_ result: AWMMediaBidResult) {
        CSJUtil.receivedBidResult(result, for: splashAd)
    }
    
    @objc func getChannelSdkInstance() -> AnyObject? {
        return splashAd
    }
    
    func destory() {
        self.splashAd?.removeSplashView()
        self.splashAd = nil
        self.bottomView?.removeFromSuperview()
        self.bottomView = nil
    }
}

加载参数

参数名参数类型参数含义
WindMillConstant.LinkIDNSString聚合请求ID
WindMillConstant.MediationRitIDNSString聚合广告位ID
WindMillConstant.MediaIDNSStringADN平台ID,平台生成的唯一ID
WindMillConstant.BottomViewUIView自定义底部视图
WindMillConstant.AdSizeNSValue/CGSize期望广告尺寸
WindMillConstant.BottomViewSizeNSValue/CGSize自定义底部视图尺寸
WindMillConstant.TimeoutNSNumber/NSInteger开屏超时时间

广告展示

在Splash广告的adapter中使用如下方法完成广告展示,更完整信息请查看WindMillSDK.h文件。

Objective-C
- (void)showSplashAdInWindow:(UIWindow *)window parameter:(AWMParameter *)parameter {
    UIView *bottomView = [parameter.extra objectForKey:WindMillConstant.BottomView];
    UIViewController *viewController = [self.bridge viewControllerForPresentingModalView];
    UIView *supView = viewController.navigationController ? viewController.navigationController.view : viewController.view;
    CGRect supFrame = supView.bounds;
    CGRect adFrame = CGRectMake(0, 0, supFrame.size.width, supFrame.size.height - bottomView.bounds.size.height);
    if (bottomView) {
        [supView addSubview:bottomView];
        bottomView.frame = CGRectMake(0,
                                      supFrame.size.height - CGRectGetHeight(bottomView.frame),
                                      CGRectGetWidth(bottomView.frame),
                                      CGRectGetHeight(bottomView.frame)
                                      );
    }
    UIView *splashAdView = self.splashAd.splashView;
    CGRect adViewRect = CGRectMake(adFrame.origin.x, adFrame.origin.y, adFrame.size.width, adFrame.size.height);
    splashAdView.frame = adViewRect;
    splashAdView.clipsToBounds = YES;
    [supView addSubview:splashAdView];
}
Swift
func showSplashAdInWindow(_ window: UIWindow, parameter: AWMParameter) {
        let bottomView = parameter.extra[WindMillConstant.BottomView] as? UIView
        self.bottomView = bottomView
        guard let rootViewController = bridge?.viewControllerForPresentingModalView() else {
            return
        }
        let showVC = rootViewController.navigationController ?? rootViewController
        self.splashAd?.showSplashView(inRootViewController:showVC)
        let supView: UIView = showVC.view
        let supFrame = supView.bounds
        if let bottomView = parameter.extra[WindMillConstant.BottomView] as? UIView {
            self.bottomView = bottomView
            supView.addSubview(bottomView)
            bottomView.frame = CGRect(
                x: 0,
                y: supFrame.height - bottomView.frame.height,
                width: bottomView.frame.width,
                height: bottomView.frame.height
            )
        }
        
        if (self.splashAd?.splashView) != nil {
            
        } else {
            let error = NSError(domain: "splash", code: -1, userInfo: nil)
            self.bridge?.splashAdDidShowFailed(self, error: error)
        }
        
    }

回调协议

开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomSplashAdapterBridge协议。

Objective-C
@protocol AWMCustomSplashAdapterBridge <AWMCustomAdapterBridge>

/// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param ext 回传信息
/// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
- (void)splashAd:(id <AWMCustomAdapter> _Nonnull)adapter didAdServerResponseWithExt:(NSDictionary<NSString *, id> * _Nonnull)ext;

/// 在广告加载完成时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdDidLoad:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
/// @param ext 回传信息
- (void)splashAd:(id <AWMCustomAdapter> _Nonnull)adapter didLoadFailWithError:(NSError * _Nonnull)error ext:(NSDictionary<NSString *, id> * _Nullable)ext;

/// 在广告即将展示时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdWillVisible:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)splashAdDidShowFailed:(id <AWMCustomAdapter> _Nonnull)adapter error:(NSError * _Nonnull)error;

/// 广告即将展示广告详情页回调
- (void)splashAdWillPresentFullScreenModal:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdDidClick:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告跳过事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdDidClickSkip:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告即将关闭事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdWillClose:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告关闭事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)splashAdDidClose:(id <AWMCustomAdapter> _Nonnull)adapter;

/// This method is called when splash viewControllr is closed.
/// @Note :  当加载聚合维度广告时,支持该回调的adn有:CSJ
- (void)splashAdViewControllerDidClose:(id <AWMCustomAdapter> _Nonnull)adapter;

- (void)splashDidCloseOtherController:(id <AWMCustomAdapter> _Nonnull)adapter interactionType:(enum WindMillInteractionType)interactionType;

/// 广告点击跳转使用的控制器
- (UIViewController * _Nullable)viewControllerForPresentingModalView;
@end
Swift
@objc public protocol AWMCustomSplashAdapterBridge: AWMCustomAdapterBridge {
    /// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param ext 回传信息
    /// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
    @objc func splashAd(_ adapter: AWMCustomAdapter, didAdServerResponseWithExt ext: [String: Any])
    
    /// 在广告加载完成时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdDidLoad(_ adapter: AWMCustomAdapter)
    /// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    /// @param ext 回传信息
    @objc func splashAd(_ adapter: AWMCustomAdapter, didLoadFailWithError error: Error, ext: [String: Any]?)
    
    /// 在广告即将展示时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdWillVisible(_ adapter: AWMCustomAdapter)
    
    /// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func splashAdDidShowFailed(_ adapter: AWMCustomAdapter,  error:Error)
    
    /// 广告即将展示广告详情页回调
    @objc func splashAdWillPresentFullScreenModal(_ adapter: AWMCustomAdapter)
    
    /// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdDidClick(_ adapter: AWMCustomAdapter)
    
    /// 在广告跳过事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdDidClickSkip(_ adapter: AWMCustomAdapter)
    
    /// 在广告即将关闭事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdWillClose(_ adapter: AWMCustomAdapter)
    
    /// 在广告关闭事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func splashAdDidClose(_ adapter: AWMCustomAdapter)
    
    /// This method is called when splash viewControllr is closed.
    /// @Note :  当加载聚合维度广告时,支持该回调的adn有:CSJ
    @objc func splashAdViewControllerDidClose(_ adapter: AWMCustomAdapter)
    
    
    // 目前仅支持gromore csj
    @objc func splashDidCloseOtherController(_ adapter: AWMCustomAdapter,  interactionType: WindMillInteractionType)
    
    /// 广告点击跳转使用的控制器
    @objc func viewControllerForPresentingModalView() -> UIViewController?
}
                           |

Banner广告

协议内容

自定义Banner adapter中需要实现的协议为AWMCustomBannerAdapter,接口实现如下所示:

Objective-C
@protocol AWMCustomBannerAdapter <AWMCustomAdapter>

/// 构造方法
/// 通过bridge回传广告状态
- (nonnull instancetype)initWithBridge:(id <AWMCustomBannerAdapterBridge> _Nonnull)bridge;

/// 加载广告的方法
/// @param placementId adn的广告位ID
/// @param parameter 广告加载的参数
- (void)loadAdWithPlacementId:(NSString * _Nonnull)placementId parameter:(AWMParameter * _Nonnull)parameter;

@end
Swift
@objc public protocol AWMCustomBannerAdapter: AWMCustomAdapter {
    /// 构造方法
    /// 通过bridge回传广告状态
    @objc init(bridge: AWMCustomBannerAdapterBridge)
    
    /// 加载广告的方法
    /// @param placementId adn的广告位ID
    /// @param parameter 广告加载的参数
    @objc func loadAd(placementId: String, parameter: AWMParameter)
}
                           |

广告加载

在Baner广告的adapter中使用如下方法完成广告加载,其中parameter参数包括了本次广告加载的所有数据,支持的参数详见下方加载参数部分,更完整信息请查看AWMAdLoadingParam.h文件。

Objective-C
@interface  XXCSJCustomBannerAdapter()<BUNativeExpressBannerViewDelegate>
@property (nonatomic, weak) id<AWMCustomBannerAdapterBridge> bridge;
@property (nonatomic, strong) BUNativeExpressBannerView *bannerView;
@end

@implementation XXCSJCustomBannerAdapter
- (instancetype)initWithBridge:(id<AWMCustomBannerAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (void)loadAdWithPlacementId:(NSString *)placementId parameter:(AWMParameter *)parameter {
    CGSize adSize = CGSizeMake(320, 50);
    UIViewController *viewController = [self.bridge viewControllerForPresentingModalView];
    self.bannerView = [[BUNativeExpressBannerView alloc] initWithSlotID:parameter.placementId rootViewController:viewController adSize:adSize];
    self.bannerView.delegate = self;
    self.bannerView.frame = CGRectMake(0, 0, adSize.width, adSize.height);
    [self.bannerView loadAdData];
}
- (BOOL)mediatedAdStatus {
    return YES;
}
- (void)destory {
    [self.bannerView removeFromSuperview];
    self.bannerView = nil;
}
@end
Swift
import Foundation
import WindMillSDK
import BUAdSDK

class BannerAdAdapter: AWMCustomBannerAdapter {
    
    let bridge: AWMCustomBannerAdapterBridge?
    var listener: BannerAdListener?
    var bannerView: BUNativeExpressBannerView?
    var isReady = false
    var parameter: AWMParameter?
    
    required init(bridge: any AWMCustomBannerAdapterBridge) {
        self.bridge = bridge
        self.setup()
    }

    private func setup() {
        self.listener = BannerAdListener(bridge: self.bridge, adapter: self)
    }
    
    func loadAd(placementId: String, parameter: AWMParameter) {
        var adSize = parameter.extra[WindMillConstant.AdSize] as? CGSize ?? .zero
         
        guard let viewController = bridge?.viewControllerForPresentingModalView() else {
            let error = TBError(code: -1, message: "广告加载前未设置UIViewController")
            bridge?.bannerAd(self, didLoadFailWithError: error, ext: [:])
            return
        }
        
        
        if CGSizeEqualToSize(adSize, .zero), let width = parameter.customInfo?["width"] as? Double,let height = parameter.customInfo?["height"] as? Double {
            adSize = CGSize(width: width, height: height)
        }
        guard !CGSizeEqualToSize(adSize, .zero) else {
            let error = TBError(code: -1, message: "not found size")
            bridge?.bannerAd(self, didLoadFailWithError: error, ext: [:])
            return
        }
        bannerView = BUNativeExpressBannerView(slotID: placementId, rootViewController: viewController, adSize: adSize)
        bannerView?.delegate = listener
        bannerView?.loadAdData()
    }
    
    func mediatedAdStatus() -> Bool {
        return listener?.mediatedAdStatus() ?? false
    }
    
    func didReceiveBidResult(_ result: AWMMediaBidResult) {
        // 处理广告竞价结果
    }
    
    func getMediaExt() -> [String : Any] {
        var options: [String : Any] = [:]
        if let requestId = bannerView?.mediaExt?["request_id"] {
            options[WindMillConstant.RequestID] = requestId
        }
        return options
    }
    
    func destory() {
        bannerView?.removeFromSuperview()
        bannerView = nil
        listener = nil
    }
}
                           |

加载参数

参数名参数类型参数含义
AWMAdLoadingParamLinkIDNSString聚合请求ID
AWMAdLoadingParamMediationRitIDNSString聚合广告位ID
AWMAdLoadingParamMediaNameNSStringADN广告位名称,平台配置名称
AWMAdLoadingParamMediaIDNSStringADN平台ID,平台生成的唯一ID
AWMAdLoadingParamCustomJsonNSString自定义Adapter扩展参数

回调协议

开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomSplashAdapterBridge协议。

Objective-C
@protocol AWMCustomBannerAdapterBridge <AWMCustomAdapterBridge>
/// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param bannerView 广告视图
/// @param ext 回传信息
/// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
- (void)bannerAd:(id <AWMCustomAdapter> _Nonnull)adapter didAdServerResponse:(UIView * _Nonnull)bannerView ext:(NSDictionary<NSString *, id> * _Nonnull)ext;
/// 在广告加载成功时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param bannerView 广告视图
- (void)bannerAd:(id <AWMCustomAdapter> _Nonnull)adapter didLoad:(UIView * _Nonnull)bannerView;
/// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
/// @param ext 回传信息
- (void)bannerAd:(id <AWMCustomAdapter> _Nonnull)adapter didLoadFailWithError:(NSError * _Nonnull)error ext:(NSDictionary<NSString *, id> * _Nullable)ext;
/// 在广告已经展示时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)bannerAdDidBecomeVisible:(id <AWMCustomAdapter> _Nonnull)adapter bannerView:(UIView * _Nonnull)bannerView;
/// 在广告弹出详情页或者展示展示appstore时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param bannerView 广告视图
- (void)bannerAdWillPresentFullScreenModal:(id <AWMCustomAdapter> _Nonnull)adapter bannerView:(UIView * _Nonnull)bannerView;
/// 在广告关闭详情页或者appstore时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param bannerView 广告视图
- (void)bannerAdWillDismissFullScreenModal:(id <AWMCustomAdapter> _Nonnull)adapter bannerView:(UIView * _Nonnull)bannerView;
/// 当用户由于点击要离开您的应用程序时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param bannerView 广告视图
- (void)bannerAdWillLeaveApplication:(id <AWMCustomAdapter> _Nonnull)adapter bannerAdView:(UIView * _Nonnull)bannerAdView;
/// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)bannerAdDidClick:(id <AWMCustomAdapter> _Nonnull)adapter bannerView:(UIView * _Nonnull)bannerView;
/// 在广告关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)bannerAdDidClosed:(id <AWMCustomAdapter> _Nonnull)adapter bannerView:(UIView * _Nonnull)bannerView;
- (UIViewController * _Nullable)viewControllerForPresentingModalView SWIFT_WARN_UNUSED_RESULT;
@end
Swift
@objc public protocol AWMCustomBannerAdapterBridge: AWMCustomAdapterBridge {
    /// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param bannerView 广告视图
    /// @param ext 回传信息
    /// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
    @objc func bannerAd(_ adapter: AWMCustomAdapter, didAdServerResponse bannerView: UIView, ext: [String:Any])
    
    /// 在广告加载成功时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param bannerView 广告视图
    @objc func bannerAd(_ adapter: AWMCustomAdapter, didLoad bannerView: UIView)
    
    /// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    /// @param ext 回传信息
    @objc func bannerAd(_ adapter: AWMCustomAdapter,
                        didLoadFailWithError error: Error,
                              ext: [String: Any]?)
    
    /// 在广告已经展示时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func bannerAdDidBecomeVisible(_ adapter: AWMCustomAdapter, bannerView: UIView)
    
    /// 在广告弹出详情页或者展示展示appstore时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param bannerView 广告视图
    @objc func bannerAdWillPresentFullScreenModal(_ adapter: AWMCustomAdapter, bannerView: UIView)
    
    /// 在广告关闭详情页或者appstore时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param bannerView 广告视图
    @objc func bannerAdWillDismissFullScreenModal(_ adapter: AWMCustomAdapter, bannerView: UIView)
    
    /// 当用户由于点击要离开您的应用程序时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param bannerView 广告视图
    @objc func bannerAdWillLeaveApplication(_ adapter: AWMCustomAdapter, bannerAdView: UIView)
    
    /// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func bannerAdDidClick(_ adapter: AWMCustomAdapter, bannerView: UIView)

    
    /// 在广告关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func bannerAdDidClosed(_ adapter: AWMCustomAdapter, bannerView: UIView)
    
    @objc func viewControllerForPresentingModalView() -> UIViewController?
}
                           |

激励视频广告(RewardedVideo)

协议内容

自定义激励视频广告 adapter中需要实现的协议为AWMCustomRewardedVideoAdapter,接口实现如下所示:

Objective-C
@protocol AWMCustomRewardedVideoAdapter <AWMCustomAdapter>

/// 构造方法
/// 通过bridge回传广告状态
- (nonnull instancetype)initWithBridge:(id <AWMCustomRewardedVideoAdapterBridge> _Nonnull)bridge;

/// 加载广告的方法
/// @param placementId adn的广告位ID
/// @param parameter 广告加载的参数
- (void)loadAdWithPlacementId:(NSString * _Nonnull)placementId parameter:(AWMParameter * _Nonnull)parameter;

/// 展示广告的方法
/// @param viewController 控制器对象
/// @param parameter 展示广告的参数,由ToBid接入媒体配置
- (void)showAdFromRootViewController:(UIViewController * _Nonnull)viewController parameter:(AWMParameter * _Nonnull)parameter;
@end
Swift
@objc public protocol AWMCustomRewardedVideoAdapter: AWMCustomAdapter {
    /// 构造方法
    /// 通过bridge回传广告状态
    @objc init(bridge: AWMCustomRewardedVideoAdapterBridge)
    
    /// 加载广告的方法
    /// @param placementId adn的广告位ID
    /// @param parameter 广告加载的参数
    @objc func loadAd(placementId: String, parameter: AWMParameter)
    
    /// 展示广告的方法
    /// @param viewController 控制器对象
    /// @param parameter 展示广告的参数,由ToBid接入媒体配置
    @objc func showAdFromRootViewController(_ viewController: UIViewController, parameter: AWMParameter)
}

广告加载

在激励视频广告的adapter中使用如下方法完成广告加载,其中parameter参数包括了本次广告加载的所有数据,支持的参数详见下方加载参数部分,更完整信息请查看AWMAdLoadingParam.h文件。

Objective-C
@interface XXCSJCustomRewardedVideoAdapter ()
@property (nonatomic, weak) id<AWMCustomRewardedVideoAdapterBridge> bridge;
@property (nonatomic, strong) BUNativeExpressRewardedVideoAd *rewardedVideoAd;
@end

@implementation XXCSJCustomRewardedVideoAdapter
- (instancetype)initWithBridge:(id<AWMCustomRewardedVideoAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (BOOL)mediatedAdStatus {
    return YES;
}
- (void)loadAdWithPlacementId:(NSString *)placementId parameter:(AWMParameter *)parameter {
    BURewardedVideoModel *model = [[BURewardedVideoModel alloc] init];
    WindMillAdRequest *request = [self.bridge adRequest];
    model.userId = request.userId;
    self.rewardedVideoAd = [[BUNativeExpressRewardedVideoAd alloc] initWithSlotID:placementId rewardedVideoModel:model];
    self.rewardedVideoAd.delegate = self;
    [self.rewardedVideoAd loadAdData];
}
- (void)destory {
    self.rewardedVideoAd = nil;
}
Swift
import Foundation
import WindMillSDK
import BUAdSDK

class RewardVideoAdAdapter: AWMCustomRewardedVideoAdapter {
    
    let bridge: AWMCustomRewardedVideoAdapterBridge?
    var listener: RewardVideoAdListener?
    var rewardedVideoAd: BUNativeExpressRewardedVideoAd?
    var parameter: AWMParameter?
    
    required public init(bridge: AWMCustomRewardedVideoAdapterBridge) {
        self.bridge = bridge
        self.setup()
    }
    
    
    private func setup() {
        self.listener = RewardVideoAdListener(bridge: self.bridge, adapter: self)
    }
    
    func mediatedAdStatus() -> Bool {
        return listener?.mediatedAdStatus() ?? false && rewardedVideoAd != nil
    }
    
    func loadAd(placementId: String, parameter: WindMillSDK.AWMParameter) {
        guard let request = bridge?.adRequest?() else { return }
        self.listener?.parameter = parameter
        let model = BURewardedVideoModel()
        model.userId = request.userId
        model.extra = JSONString(from: request.options ?? [:])
        rewardedVideoAd = BUNativeExpressRewardedVideoAd(slotID: placementId, rewardedVideoModel: model)
        rewardedVideoAd?.delegate = self.listener
        rewardedVideoAd?.rewardPlayAgainInteractionDelegate = self.listener
        rewardedVideoAd?.loadData()
    }
    
    func getMediaExt() -> [String : Any] {
        var options: [String : Any] = [:]
        if let requestId = self.rewardedVideoAd?.mediaExt?["request_id"] {
            options[WindMillConstant.RequestID] = requestId
        }
        return options
    }
    
    func didReceiveBidResult(_ result: AWMMediaBidResult) {
        // 处理广告竞价结果
    }
    
    @objc func getChannelSdkInstance() -> AnyObject? {
        return rewardedVideoAd
    }
    
    func destory() {
        self.rewardedVideoAd = nil
    }
}

加载参数

参数名参数含义参数类型
WindMillConstant.LinkID聚合请求IDNSString
WindMillConstant.MediationRitID聚合广告位IDNSString
AWMAdLoadingParamMediaNameADN广告位名称,平台配置名称NSString
WindMillConstant.MediaIDADN平台ID,平台生成的唯一IDNSString
WindMillConstant.ExperimentId聚合实验idNSString
WindMillConstant.StrategyId聚合策略idNSString

广告展示

在激励视频广告的adapter中使用如下方法完成广告展示,更完整信息请查看AWMAdLoadingParam.h文件。

Objective-C
- (BOOL)showAdFromRootViewController:(UIViewController *)viewController parameter:(AWMParameter *)parameter {
    return [self.rewardedVideoAd showAdFromRootViewController:viewController];
}
Swift
func showAdFromRootViewController(_ viewController: UIViewController, parameter: WindMillSDK.AWMParameter) {
    rewardedVideoAd?.show(fromRootViewController: viewController)
}

回调协议

开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomRewardedVideoAdapterBridge协议。

Objective-C
@protocol AWMCustomRewardedVideoAdapterBridge <AWMCustomAdapterBridge>

/// 在广告数据返回时调用该方法,此时广告只是返回还未预加载完成
/// @param adapter 当前适配器
/// @param ext 回传信息
/// @warning 1.客户端竞价时,ext中需要回传Price出价;
/// @warning 2.客户端竞价时,ext中需要回传Currency货币类型, USD或者CNY;
- (void)rewardedVideoAd:(id <AWMCustomAdapter> _Nonnull)adapter didAdServerResponseWithExt:(NSDictionary<NSString *, id> * _Nonnull)ext;

/// 在广告中素材加载完成时调用,此时广告预加载完成
/// @param adapter 当前适配器
- (void)rewardedVideoAdDidLoad:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
/// @param ext 回传信息
- (void)rewardedVideoAd:(id <AWMCustomAdapter> _Nonnull)adapter didLoadFailWithError:(NSError * _Nonnull)error ext:(NSDictionary<NSString *, id> * _Nullable)ext;

/// 在广告已经展示时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)rewardedVideoAdDidVisible:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)rewardedVideoAdDidShowFailed:(id <AWMCustomAdapter> _Nonnull)adapter error:(NSError * _Nonnull)error;

/// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)rewardedVideoAdDidClick:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告被点击跳过时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)rewardedVideoAdDidClickSkip:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告即将关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)rewardedVideoAdWillClose:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)rewardedVideoAdDidClose:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告视频播放完成时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)rewardedVideoAd:(id <AWMCustomAdapter> _Nonnull)adapter didPlayFinishWithError:(NSError * _Nullable)error;

/// 在ADN验证激励成功时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param info 激励信息
- (void)rewardedVideoAd:(id <AWMCustomAdapter> _Nonnull)adapter didRewardSuccessWithInfo:(WindMillRewardInfo * _Nonnull)info;
@end
Swift
@objc public protocol AWMCustomRewardedVideoAdapterBridge: AWMCustomAdapterBridge {
    /// 在广告数据返回时调用该方法,此时广告只是返回还未预加载完成
    /// @param adapter 当前适配器
    /// @param ext 回传信息
    /// @warning 1.客户端竞价时,ext中需要回传Price出价;
    /// @warning 2.客户端竞价时,ext中需要回传Currency货币类型, USD或者CNY;
    @objc func rewardedVideoAd(_ adapter: AWMCustomAdapter, didAdServerResponseWithExt ext:[String: Any])
    
    /// 在广告中素材加载完成时调用,此时广告预加载完成
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdDidLoad(_ adapter: AWMCustomAdapter)
    
    /// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    /// @param ext 回传信息
    @objc func rewardedVideoAd(_ adapter: AWMCustomAdapter,
                               didLoadFailWithError error:Error,
                               ext: [String:Any]?)
    
    /// 在广告已经展示时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdDidVisible(_ adapter: AWMCustomAdapter)
    
    /// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func rewardedVideoAdDidShowFailed(_ adapter: AWMCustomAdapter, error:Error)
    
    /// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdDidClick(_ adapter: AWMCustomAdapter)
    
    /// 在广告被点击跳过时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdDidClickSkip(_ adapter: AWMCustomAdapter)
    
    /// 在广告即将关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdWillClose(_ adapter: AWMCustomAdapter)
    
    /// 在广告关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func rewardedVideoAdDidClose(_ adapter: AWMCustomAdapter)

    /// 在广告视频播放完成时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func rewardedVideoAd(_ adapter: AWMCustomAdapter, didPlayFinishWithError error: Error?)

    /// 在ADN验证激励成功时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param info 激励信息
    @objc func rewardedVideoAd(_ adapter: AWMCustomAdapter, didRewardSuccessWithInfo info: WindMillRewardInfo)
}

插屏广告(Interstitial)

协议内容

自定义全屏视频广告 adapter中需要实现的协议为AWMCustomInterstitialAdapter,接口实现如下所示:

Objective-C
@protocol AWMCustomInterstitialAdapter <AWMCustomAdapter>
/// 构造方法
/// 通过bridge回传广告状态
- (nonnull instancetype)initWithBridge:(id <AWMCustomInterstitialAdapterBridge> _Nonnull)bridge;

/// 加载广告的方法
/// @param placementId adn的广告位ID
/// @param parameter 广告加载的参数
- (void)loadAdWithPlacementId:(NSString * _Nonnull)placementId parameter:(AWMParameter * _Nonnull)parameter;

/// 展示广告的方法
/// @param viewController 控制器对象
/// @param parameter 展示广告的参数,由ToBid接入媒体配置
- (void)showAdFromRootViewController:(UIViewController * _Nonnull)viewController parameter:(AWMParameter * _Nonnull)parameter;
@end
Swift
@objc public protocol AWMCustomInterstitialAdapter: AWMCustomAdapter {
    /// 构造方法
    /// 通过bridge回传广告状态
    @objc init(bridge: AWMCustomInterstitialAdapterBridge)
    
    /// 加载广告的方法
    /// @param placementId adn的广告位ID
    /// @param parameter 广告加载的参数
    @objc func loadAd(placementId: String, parameter: AWMParameter)
    
    /// 展示广告的方法
    /// @param viewController 控制器对象
    /// @param parameter 展示广告的参数,由ToBid接入媒体配置
    @objc func showAdFromRootViewController(_ viewController: UIViewController, parameter: AWMParameter)
}

广告加载

在插屏广告的adapter中使用如下方法完成广告加载,其中parameter参数包括了本次广告加载的所有数据,支持的参数详见下方加载参数部分,更完整信息请查看AWMAdLoadingParam.h文件。

Objective-C
@interface XXCSJCustomInterstitialAdapter : NSObject\<AWMCustomInterstitialAdapter\>
@property (nonatomic, weak) id<AWMCustomInterstitialAdapterBridge> bridge;
@property (nonatomic, strong) BUFullscreenVideoAd *ad;
@end

@implementation XXCSJCustomInterstitialAdapter
- (instancetype)initWithBridge:(id<AWMCustomInterstitialAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (BOOL)mediatedAdStatus {
    return YES;
}
- (void)loadAdWithPlacementId:(NSString *)placementId parameter:(AWMParameter *)parameter {
    self.ad = [[BUFullscreenVideoAd alloc] initWithSlotID:placementId];
    self.ad = self;
    [self.ad loadAdData];
}
- (void)destory {
    self.ad = nil;
}
Swift
class InterstitialAdAdapter: AWMCustomInterstitialAdapter {
    
    weak var bridge: AWMCustomInterstitialAdapterBridge?
    weak var adapter: AWMCustomInterstitialAdapter?
    var intersititialAd: BUNativeExpressFullscreenVideoAd?
    var listener: InterstitialAdListener?
    var parameter: AWMParameter?

    required public init(bridge: AWMCustomInterstitialAdapterBridge) {
        self.bridge = bridge
        self.setup()
    }
    
    private func setup() {
        self.listener = InterstitialAdListener(bridge: self.bridge, adapter: self)
    }
    
    func mediatedAdStatus() -> Bool {
        return listener?.mediatedAdStatus() ?? false && intersititialAd != nil
    }
    
    func loadAd(placementId: String, parameter: WindMillSDK.AWMParameter) {
        intersititialAd = BUNativeExpressFullscreenVideoAd(slotID: placementId)
        intersititialAd?.delegate = self.listener
        intersititialAd?.loadData()
    }

    func didReceiveBidResult(_ result: AWMMediaBidResult) {
        // 回传竞价结果
    }

    func destory() {
        self.intersititialAd = nil
    }
    
}

加载参数

参数名参数含义参数类型
WindMillConstant.LinkID聚合请求IDNSString
WindMillConstant.MediationRitID聚合广告位IDNSString
AWMAdLoadingParamMediaNameADN广告位名称,平台配置名称NSString
WindMillConstant.MediaIDADN平台ID,平台生成的唯一IDNSString
WindMillConstant.ExperimentId聚合实验idNSString
WindMillConstant.StrategyId聚合策略idNSString

广告展示

在插屏广告的adapter中使用如下方法完成广告展示,更完整信息请查看AWMAdLoadingParam.h文件。

Objective-C
- (BOOL)showAdFromRootViewController:(UIViewController *)viewController parameter:(AWMParameter *)parameter {
    [self.ad showAdFromRootViewController:viewController];
    return YES;
}
Swift
func showAdFromRootViewController(_ viewController: UIViewController, parameter: WindMillSDK.AWMParameter) {
    intersititialAd?.show(fromRootViewController: viewController)
}

回调协议

开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomInterstitialAdapterBridge.h协议。

Objective-C
@protocol AWMCustomInterstitialAdapterBridge <AWMCustomAdapterBridge>

/// 在广告数据返回时调用该方法,此时广告只是返回还未预加载完成
/// @param adapter 当前适配器
/// @param ext 回传信息
/// @warning 1.客户端竞价时,ext中需要回传Price出价;
/// @warning 2.客户端竞价时,ext中需要回传Currency货币类型, USD或者CNY;
- (void)interstitialAd:(id <AWMCustomAdapter> _Nonnull)adapter didAdServerResponseWithExt:(NSDictionary<NSString *, id> * _Nonnull)ext;

/// 在广告中素材加载完成时调用,此时广告预加载完成
/// @param adapter 当前适配器
- (void)interstitialAdDidLoad:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
/// @param ext 回传信息
- (void)interstitialAd:(id <AWMCustomAdapter> _Nonnull)adapter didLoadFailWithError:(NSError * _Nonnull)error ext:(NSDictionary<NSString *, id> * _Nullable)ext;

/// 在广告已经展示时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)interstitialAdDidVisible:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)interstitialAdDidShowFailed:(id <AWMCustomAdapter> _Nonnull)adapter error:(NSError * _Nonnull)error;

/// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)interstitialAdDidClick:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告被点击跳过时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)interstitialAdDidClickSkip:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)interstitialAdDidClose:(id <AWMCustomAdapter> _Nonnull)adapter;

/// 在广告关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
- (void)interstitialAdDidCloseOtherController:(id <AWMCustomAdapter> _Nonnull)adapter interactionType:(enum WindMillInteractionType)interactionType;

/// 在广告视频播放完成时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)interstitialAd:(id <AWMCustomAdapter> _Nonnull)adapter didPlayFinishWithError:(NSError * _Nullable)error;
@end
Swift
@objc public protocol AWMCustomInterstitialAdapterBridge: AWMCustomAdapterBridge {
    /// 在广告数据返回时调用该方法,此时广告只是返回还未预加载完成
    /// @param adapter 当前适配器
    /// @param ext 回传信息
    /// @warning 1.客户端竞价时,ext中需要回传price出价;
    /// @warning 2.客户端竞价时,ext中需要回传currency货币类型, USD或者CNY;
    @objc func interstitialAd(_ adapter: AWMCustomAdapter, didAdServerResponseWithExt ext:[String:Any])
    
    /// 在广告中素材加载完成时调用,此时广告预加载完成
    /// @param adapter 当前适配器
    @objc func interstitialAdDidLoad(_ adapter: AWMCustomAdapter)
    
    /// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    /// @param ext 回传信息
    @objc func interstitialAd(_ adapter:AWMCustomAdapter,
                              didLoadFailWithError error:Error,
                              ext: [String:Any]?)
    
    /// 在广告已经展示时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func interstitialAdDidVisible(_ adapter:AWMCustomAdapter)
    
    /// 广告展示失败的时候调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func interstitialAdDidShowFailed(_ adapter:AWMCustomAdapter, error:Error)
    
    /// 在广告点击事件触发时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func interstitialAdDidClick(_ adapter: AWMCustomAdapter)
    
    /// 在广告被点击跳过时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func interstitialAdDidClickSkip(_ adapter: AWMCustomAdapter)
    
    /// 在广告关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func interstitialAdDidClose(_ adapter: AWMCustomAdapter)
    
    /// 在广告关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    @objc func interstitialAdDidCloseOtherController(_ adapter: AWMCustomAdapter, interactionType: WindMillInteractionType)

    /// 在广告视频播放完成时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func interstitialAd(_ adapter: AWMCustomAdapter, didPlayFinishWithError error: Error?)
}

原生广告(Native)

协议内容

自定义Native adapter中需要实现的协议为AWMCustomNativeAdapter,接口实现如下所示:

Objective-C
@protocol AWMCustomNativeAdapter <AWMCustomAdapter>

/// 构造方法
/// 通过bridge回传广告状态
- (nonnull instancetype)initWithBridge:(id <AWMCustomNativeAdapterBridge> _Nonnull)bridge;

/// 加载广告的方法
/// @param placementId adn的广告位ID
/// @param parameter 广告加载的参数
- (void)loadAdWithPlacementId:(NSString * _Nonnull)placementId adSize:(CGSize)adSize parameter:(AWMParameter * _Nonnull)parameter;

@end
Swift
@objc public protocol AWMCustomNativeAdapter: AWMCustomAdapter {
    /// 构造方法
    /// 通过bridge回传广告状态
    @objc init(bridge: AWMCustomNativeAdapterBridge)
    
    /// 加载广告的方法
    /// @param placementId adn的广告位ID
    /// @param parameter 广告加载的参数
    @objc func loadAd(placementId: String, adSize: CGSize,  parameter: AWMParameter)
}

广告对象AWMMediatedNativeAd

收到第三方广告加载成功时,需要将将第三方返回的广告转换为ToBid识别的AWMMediatedNativeAd对象,AWMMediatedNativeAd接口如下:

objective-c
@interface AWMMediatedNativeAd : NSObject

// 广告物料,包含有最全的广告数据 [optional](仅自渲染需要赋值,模版渲染时可设置为nil)
@property (nonatomic, strong) id <AWMMediatedNativeAdData> _Nonnull data;

// 广告视图创建对象,对常用广告展示元素进行创建 [required]
@property (nonatomic, readonly, strong) id <AWMMediatedNativeAdViewCreator> _Nonnull viewCreator;

// 广告视图对象,一般指原生广告的根视图 [optional](部分adn的自渲染可能为空)
@property (nonatomic, weak) UIView * _Nullable view;

// adn获取到的原始广告数据 [required] (adn广告回调的原始数据,通过该数据建立对应关系) 
@property (nonatomic, readonly, strong) id _Nonnull originMediatedNativeAd;

- (nonnull instancetype)initWithData:(id <AWMMediatedNativeAdData> _Nonnull)data viewCreator:(id <AWMMediatedNativeAdViewCreator> _Nonnull)viewCreator originAd:(id _Nonnull)originAd;
@end
Swift
@objc public class AWMMediatedNativeAd: NSObject {
    // 广告物料,包含有最全的广告数据
    @objc public var data: AWMMediatedNativeAdData
    
    // 广告视图创建对象,对常用广告展示元素进行创建 [Required]
    @objc public let viewCreator: AWMMediatedNativeAdViewCreator
    
    // 广告视图对象,一般指原生广告的根视图 [Optional](部分adn的自渲染可能为空)
    @objc public weak var view: UIView?
    
    // adn获取到的原始广告数据
    // 自渲染请设置为渠道返回的NativeAd模型
    // 模版渲染请设置为渠道返回的UIView
    @objc public let originMediatedNativeAd: AnyObject

    @objc public init(data: AWMMediatedNativeAdData, viewCreator: AWMMediatedNativeAdViewCreator, originAd: AnyObject)
}

注意事项:

  • originMediatedNativeAd:这个为必要参数,聚合通过这个参数来识别具体为哪个信息流广告,一般需要设置为adn广告回调中返回的数据,通常对应自渲染广告来说设置为adn返回的返回对象,对应模版渲染的广告来时,通常设置为模版View;
  • view: 针对模版渲染,统一设置为模版View; 针对自渲染,一般为adn提供的信息流的根视图View,某些渠道可能为nil;

自渲染元素

在接入原生自渲染时,AWMMediatedNativeAd对象中data和viewCreator属性为必要属性,其中data需要遵循AWMMediatedNativeAdData协议,viewCreator需要遵循AWMMediatedNativeAdViewCreator协议。

AWMMediatedNativeAdData协议内容如下:

objective-c
@protocol AWMMediatedNativeAdData
/// 广告标题
@property (nonatomic, copy) NSString * _Nullable title;
/// 广告详情描述
@property (nonatomic, copy) NSString * _Nullable desc;
/// app类型广告的广告商app图标,
@property (nonatomic, copy) NSString * _Nullable iconUrl;
/// 按钮文案,例如’下载/安装’
@property (nonatomic, copy) NSString * _Nullable callToAction;
/// app评分,区间为0-5
@property (nonatomic) CGFloat rating;
/// 图片URL列表 【Optional,可能位nil】
/// 大图:列表中只有一个URL
/// 三图:列表中有3个URL
@property (nonatomic, copy) NSArray<NSString *> * _Nullable imageUrlList;
/// 图片/视频模式
@property (nonatomic) enum AWMMediatedNativeAdMode adMode;
/// 广告类型(feed/draw)
@property (nonatomic) enum AWMNativeAdSlotAdType adType;
/// 广告交互类型
@property (nonatomic) enum AWMNativeAdInteractionType interactionType;
/// 渠道ID
@property (nonatomic) enum WindMillAdn networkId;
/// 原生自渲染视频封面图对象,仅支持ks
@property (nonatomic, strong) AWMADImage * _Nullable videoCoverImage;
/// 原生自渲染视频URL,仅支持ks
@property (nonatomic, copy) NSString * _Nullable videoUrl;
/// 图片URL列表 【Optional,可能位nil】
/// 大图:列表中只有一个AWMADImage对象
/// 三图:列表中有3个AWMADImage对象
@property (nonatomic, copy) NSArray<AWMADImage *> * _Nullable imageModelList;
@end
Swift
@objc public protocol AWMMediatedNativeAdData {
    
    /// 广告标题
    @objc var title: String? { get  set }
    
    /// 广告详情描述
    @objc var desc: String? { get  set }
    
    /// app类型广告的广告商app图标,
    @objc var iconUrl: String? { get  set }
    
    /// 按钮文案,例如'下载/安装'
    @objc var callToAction: String? { get  set }
    
    /// app评分,区间为0-5
    @objc var rating: CGFloat { get  set }
    
    /// 图片URL列表 【Optional,可能位nil】
    /// 大图:列表中只有一个URL
    /// 三图:列表中有3个URL
    @objc var imageUrlList: [String]? { get  set }
    
    /// 图片/视频模式
    @objc var adMode: AWMMediatedNativeAdMode  { get  set }
    
    /// 广告类型(feed/draw)
    @objc var adType:AWMNativeAdSlotAdType  { get  set }
    
    /// 广告交互类型
    @objc var interactionType:AWMNativeAdInteractionType  { get  set }
    
    /// 渠道ID
    @objc var networkId:WindMillAdn  { get  set }

        /// 原生自渲染视频封面图对象,仅支持ks
    @objc var videoCoverImage: AWMADImage? { get  set }
    
        ///  原生自渲染视频URL,仅支持ks
    @objc var videoUrl: String? { get  set }
    
        /// 图片URL列表 【Optional,可能位nil】
        /// 大图:列表中只有一个AWMADImage对象
        /// 三图:列表中有3个AWMADImage对象
    @objc var imageModelList: [AWMADImage]? { get set }
}

AWMMediatedNativeAdViewCreator协议内容如下:

objective-c
@protocol AWMMediatedNativeAdViewCreator
/// 视频视图
@property (nonatomic, readonly, strong) UIView * _Nullable mediaView;
/// 广告图标视图
@property (nonatomic, readonly, strong) UIView * _Nullable adLogoView;
/// 不喜欢广告按钮
@property (nonatomic, readonly, strong) UIButton * _Nullable dislikeBtn;
/// 广告图片视图
@property (nonatomic, readonly, strong) UIImageView * _Nullable imageView;
/// 广告图片组合视图
@property (nonatomic, readonly, copy) NSArray<UIImageView *> * _Nullable imageViewArray;
/// 绑定数据
- (void)refreshData;
/// 设置根视图 (不设置可能造成点击无反应)
- (void)setRootViewController:(UIViewController * _Nullable)viewController;
/// 在原生广告视图中注册可点击视图。
- (void)registerContainer:(UIView * _Nonnull)containerView withClickableViews:(NSArray<UIView *> * _Nonnull)clickableViews;
/// 销毁数据
- (void)unregisterDataObject;
@optional
/// 设置图片的占位图
- (void)setPlaceholderImage:(UIImage * _Nonnull)placeholderImage;
/// 美数渠道用于提前设置size
/// 百度渠道用于 resize mediaView
- (void)setMediaViewSize:(CGSize)size;
/// 是否展示播放进度条,默认 YES,目前支持gdt
- (void)setProgressViewEnable:(BOOL)enable;
/// 设置视频是否静音
- (void)setMediaViewMute:(BOOL)isMute;
/// 开始播放原生自渲染视频广告,目前支持gdt,baidu,csj
- (void)play;
/// 继续播放原生自渲染视频广告,目前支持gdt,baidu
- (void)resume;
/// 暂停播放原生自渲染视频广告,目前支持gdt,baidu,csj
- (void)pause;
/// 销毁播放器原生自渲染视频广告,目前支持gdt,baidu
- (void)stop;
/// 摇一摇组件
- (UIView * _Nullable)getShakeView SWIFT_WARN_UNUSED_RESULT;
/// 开启摇动检测
- (void)startShake;
/// 停止摇动检测
- (void)stopShake;
/// 销毁摇一摇组件
- (void)destoryShakeView;
@end
Swift
@objc public protocol AWMMediatedNativeAdViewCreator {
    /// 视频视图
    @objc var mediaView: UIView? { get }

    /// 广告图标视图
    @objc var adLogoView: UIView? { get }

    /// 不喜欢广告按钮
    @objc var dislikeBtn: UIButton? { get }

    /// 广告图片视图
    @objc var imageView: UIImageView?  { get }

    /// 广告图片组合视图
    @objc var imageViewArray: [UIImageView]? { get }

    /// 绑定数据
    @objc func refreshData()
    /// 设置根视图 (不设置可能造成点击无反应)
    @objc func setRootViewController(_ viewController: UIViewController?);
    
    /// 在原生广告视图中注册可点击视图。
    @objc func registerContainer(_ containerView: UIView, withClickableViews clickableViews: [UIView])

    /// 销毁数据
    @objc func unregisterDataObject()

    /// 设置图片的占位图
    @objc optional func setPlaceholderImage(_ placeholderImage: UIImage);

    /// 美数渠道用于提前设置size
    /// 百度渠道用于 resize mediaView
    @objc optional func setMediaViewSize(_ size: CGSize)

    /// 是否展示播放进度条,默认 YES,目前支持gdt
    @objc optional func setProgressViewEnable(_ enable :Bool)
    
    /// 设置视频是否静音
    @objc optional func setMediaViewMute(_ isMute: Bool)

    /// 开始播放原生自渲染视频广告,目前支持gdt,baidu,csj
    @objc optional func play()

    /// 继续播放原生自渲染视频广告,目前支持gdt,baidu
    @objc optional func resume()

    /// 暂停播放原生自渲染视频广告,目前支持gdt,baidu,csj
    @objc optional func pause()

    /// 销毁播放器原生自渲染视频广告,目前支持gdt,baidu
    @objc optional func stop()

    /// 摇一摇组件
    @objc optional func getShakeView() -> UIView?
    /// 开启摇动检测
    @objc optional func startShake()
    /// 停止摇动检测
    @objc optional func stopShake()
    /// 销毁摇一摇组件
    @objc optional func destoryShakeView()
}

加载广告

在原生广告的adapter中使用如下方法完成广告加载,其中parameter参数包括了本次广告加载的所有数据。

objective-c
@interface XXCSJCustomNativeAdapter ()
@property (nonatomic, weak) id<AWMCustomNativeAdapterBridge> bridge;
@property (nonatomic, strong) BUNativeAdsManager *nativeAdsManager;
@end

@implementation XXCSJCustomNativeAdapter
- (instancetype)initWithBridge:(id<AWMCustomNativeAdapterBridge>)bridge {
    self = [super init];
    if (self) {
        _bridge = bridge;
    }
    return self;
}
- (void)loadAdWithPlacementId:(NSString *)placementId adSize:(CGSize)size parameter:(AWMParameter *)parameter {
    BUAdSlot *adSlot = [[BUAdSlot alloc] init];
    adSlot.ID = placementId;
    adSlot.AdType = BUAdSlotAdTypeFeed;
    adSlot.supportRenderControl = YES;
    BUProposalSize propSize = BUProposalSize_Feed690_388;
    NSString *imgType = [parameter.customInfo objectForKey:@"imgType"];
    if ([imgType isEqualToString:@"1"]) {
        propSize = BUProposalSize_Feed228_150;
    }
    BUSize *imgSize = [BUSize sizeBy:propSize];
    adSlot.imgSize = imgSize;
    adSlot.position = BUAdSlotPositionFeed;
    //高度为0是自适应
    adSlot.adSize = size;
    self.nativeAdsManager = [[BUNativeAdsManager alloc] initWithSlot:adSlot];
    self.nativeAdsManager.delegate = self;
    if (parameter.isHeaderBidding) {
        [self.nativeAdsManager loadAdDataWithCount:1];
    }else {
        NSUInteger count = [[parameter.extra objectForKey:AWMAdLoadingParamNALoadAdCount] integerValue];
        [self.nativeAdsManager loadAdDataWithCount:count];
    }
}

/// 穿山甲广告加载成功回调
- (void)nativeAdsManagerSuccessToLoad:(BUNativeAdsManager *)adsManager nativeAds:(NSArray<BUNativeAd *> *)nativeAdDataArray {
    NSMutableArray *adArray = [[NSMutableArray alloc] init];
    for (BUNativeAd *nativeAd in nativeAdDataArray) {
        nativeAd.delegate = self;
        XXCSJNativeAdData *data = [[XXCSJNativeAdData alloc] initWithAd:nativeAd];
        BUNativeAdRelatedView *adView = [[BUNativeAdRelatedView alloc] init];
        XXCSJNativeAdViewCreator *viewCreator = [[XXCSJNativeAdViewCreator alloc] initWithNativeAd:nativeAd adView:adView];
        AWMMediatedNativeAd *mNativeAd = [[AWMMediatedNativeAd alloc] initWithData:data viewCreator:viewCreator];
        mNativeAd.originMediatedNativeAd = nativeAd;
        [adArray addObject:mNativeAd];
    }
    [self.bridge nativeAd:self.adapter didLoadWithNativeAds:adArray];
}
- (void)nativeAdsManager:(BUNativeAdsManager *)adsManager didFailWithError:(NSError *)error {
    [self.bridge nativeAd:self.adapter didLoadFailWithError:error];
}
@end
Swift
class NativeAdAdapter: AWMCustomNativeAdapter {
    
    weak var bridge: AWMCustomNativeAdapterBridge?
    var adManager: NativeAdProtocol?
    
    required init(bridge: any AWMCustomNativeAdapterBridge) {
        self.bridge = bridge
        Log.info(Constant.MTAG, "\(type(of: self))[\(PointerUtil.hashValue(self))].init")
    }
    
    deinit {
        Log.info(Constant.MTAG, "\(type(of: self))[\(PointerUtil.hashValue(self))].deinit")
    }
    
    func loadAd(placementId: String, adSize: CGSize, parameter: AWMParameter) {
        //templateType 0:模板渲染 1:自渲染
        let templateType = parameter.customInfo?["templateType"] as? String ?? "0"
        if templateType == "1" {
            adManager = NativeAdsManager(adapter: self, bridge: bridge)
        }else {
            adManager = NativeExpressAdsManager(adapter: self, bridge: bridge)
        }
        adManager?.loadAd(placementId: placementId, adSize: adSize, parameter: parameter)
    }
    
    func mediatedAdStatus() -> Bool {
        return adManager?.mediatedAdStatus() ?? false
    }
}
/// 模板渲染示例
func nativeExpressAdSuccess(toLoad nativeExpressAdManager: BUNativeExpressAdManager, views: [BUNativeExpressAdView]) {
        guard let bridge = self.bridge, let adapter = self.adapter else { return }
        self.isReady = true
        let expressAdView = views.first
        let dict = expressAdView?.mediation as? [String:Any]
        let price = dict?["price"] ?? 0
        bridge.nativeAd(adapter, didAdServerResponseWithExt: [
            WindMillConstant.ECPM: "\(price)"
        ])
        
        var adArray = [AWMMediatedNativeAd]()
        for feedView in views {
            let data = NativeAdData(feedAd:nativeExpressAdManager.adslot ?? BUAdSlot());
            let viewCreator = ViewCreator(feedAd: feedView)
            viewCreator.obj = self
            let mediatedNativeAd = AWMMediatedNativeAd(data: data, viewCreator: viewCreator, originAd: feedView)
            mediatedNativeAd.view = feedView
            adArray.append(mediatedNativeAd)
        }
        bridge.nativeAd(adapter, didLoadWithNativeAds: adArray)
}
/// 自渲染示例
func nativeAdsManagerSuccess(toLoad adsManager: BUNativeAdsManager, nativeAds nativeAdDataArray: [BUNativeAd]?) {
        guard let bridge = self.bridge, let adapter = self.adapter else { return }
        self.isReady = true
        let ad = nativeAdDataArray?.first
        let mediaExt = ad?.data?.mediaExt as? [AnyHashable : Any]
        let price = mediaExt?["price"] ?? 0
        bridge.nativeAd(adapter, didAdServerResponseWithExt: [
            WindMillConstant.ECPM: "\(price)"
        ])
        
        var adArray = [AWMMediatedNativeAd]()
        if let adObjects = nativeAdDataArray {
            for nativeAd in adObjects {
                nativeAd.delegate = self
                let data = NativeAdData(nativeAd: nativeAd)
                let adView = BUNativeAdRelatedView()
                adView.mediaAdView?.delegate = self
                
                let viewCreator = ViewCreator(nativeAd: nativeAd, adView: adView)
                viewCreator.obj = self
                if let nativeAdData = nativeAd.data {
                    let nativeAd = AWMMediatedNativeAd(data: data, viewCreator: viewCreator, originAd: nativeAdData)
                    adArray.append(nativeAd)
                }
            }
        }
        bridge.nativeAd(adapter, didLoadWithNativeAds: adArray)
}

具体代码可以参考Demo中原生广告模块:CustomAdns/CustomCSJAdapter/CustomCSJAdapter/NativeAd/NativeAdAdapter.swift文件

回调协议

开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomNativeAdapterBridge协议。

objective-c
@protocol AWMCustomNativeAdapterBridge <AWMCustomAdapterBridge>
/// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param ext 回传信息
/// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didAdServerResponseWithExt:(NSDictionary<NSString *, id> * _Nonnull)ext;
/// 在广告加载完成时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param ads 广告数据组
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didLoadWithNativeAds:(NSArray<AWMMediatedNativeAd *> * _Nonnull)ads;
/// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param error 错误信息
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didLoadFailWithError:(NSError * _Nonnull)error;
/// 广告展示失败时候调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd  广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didFailedVisibleWithMediatedNativeAd:(id _Nonnull)nativeAd error:(NSError * _Nonnull)error;
/// 广告展示时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd  广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didVisibleWithMediatedNativeAd:(id _Nonnull)nativeAd;
/// 广告点击事件时调用该方法,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didClickWithMediatedNativeAd:(id _Nonnull)nativeAd;
/// 在广告即将展示详情页时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter willPresentFullScreenModalWithMediatedNativeAd:(id _Nonnull)nativeAd;
/// 在广告落地页关闭时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
/// @param interactionType 广告跳转类型
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didDismissFullScreenModalWithMediatedNativeAd:(id _Nonnull)nativeAd interactionType:(enum WindMillInteractionType)interactionType;
/// 在模板广告关闭的时候调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
/// @param filterWords 用户手动关闭时的关闭原因描述
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter didClose:(id _Nonnull)nativeAd closeReasons:(NSArray<NSString *> * _Nonnull)filterWords;
/// 仅限模板广告,在渲染成功或者模板广告的尺寸更新时调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param expressView 模板广告
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter renderSuccessWithExpressView:(UIView * _Nonnull)expressView;
/// 仅限模板广告,在渲染失败调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param expressView 模板广告
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter renderFailWithExpressView:(UIView * _Nonnull)expressView andError:(NSError * _Nonnull)error;
/// 视频广告中视频播放状态变更的时候调用,直接调用即可,无需做响应判断
/// @param adapter 当前适配器
/// @param state 播放状态
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter videoStateDidChangedWithState:(enum WindMillMediaPlayerStatus)state andNativeAd:(id _Nonnull)nativeAd;
/// 摇一摇销毁(消失)回调
/// @param adapter 当前适配器
/// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd)
- (void)nativeAd:(id <AWMCustomNativeAdapter> _Nonnull)adapter shakeViewDismissWithMediatedNativeAd:(id _Nonnull)nativeAd;
@end
Swift
@objc public protocol AWMCustomNativeAdapterBridge: AWMCustomAdapterBridge {
    /// 在广告数据成功返回时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param ext 回传信息
    /// @warning 如何开启了客户端bidding,则ext中需要回传price和货币类型
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didAdServerResponseWithExt ext: [String: Any])
    
    /// 在广告加载完成时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param ads 广告数据组
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didLoadWithNativeAds ads: [AWMMediatedNativeAd])
    
    /// 在广告加载失败时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param error 错误信息
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didLoadFailWithError error:Error)
    
    
    /// 广告展示失败时候调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd  广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didFailedVisibleWithMediatedNativeAd nativeAd: Any, error: Error)
    
    /// 广告展示时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd  广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didVisibleWithMediatedNativeAd nativeAd: Any)
    
    /// 广告点击事件时调用该方法,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didClickWithMediatedNativeAd nativeAd: Any)
    
    /// 在广告即将展示详情页时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        willPresentFullScreenModalWithMediatedNativeAd nativeAd: Any)
    
    /// 在广告落地页关闭时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    /// @param interactionType 广告跳转类型
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didDismissFullScreenModalWithMediatedNativeAd nativeAd: Any, interactionType: WindMillInteractionType)
    
    /// 在模板广告关闭的时候调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    /// @param filterWords 用户手动关闭时的关闭原因描述
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        didClose nativeAd: Any,
                        closeReasons filterWords: [String])
    
    /// 仅限模板广告,在渲染成功或者模板广告的尺寸更新时调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param expressView 模板广告
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
    renderSuccessWithExpressView expressView: UIView)
    
    /// 仅限模板广告,在渲染失败调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param expressView 模板广告
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
    renderFailWithExpressView  expressView: UIView,
    andError error: Error)
    
    /// 视频广告中视频播放状态变更的时候调用,直接调用即可,无需做响应判断
    /// @param adapter 当前适配器
    /// @param state 播放状态
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd),express广告请传递上报ToBid的UIView
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter,
                        videoStateDidChangedWithState state: WindMillMediaPlayerStatus,
    andNativeAd nativeAd: Any)
    
    /// 摇一摇销毁(消失)回调
    /// @param adapter 当前适配器
    /// @param nativeAd 广告数据,native广告请传递原始数据(即AWMMediatedNativeAd.originMediatedNativeAd)
    @objc func nativeAd(_ adapter: AWMCustomNativeAdapter, shakeViewDismissWithMediatedNativeAd nativeAd: Any)
    
}

综合比价支持

介绍

使自定义ADN的广告加载提供实时价格反馈渠道,参与到ToBid的竞价逻辑中。在一定程度上实现开发者收益最大化。

参数下发

所有广告类型中,AWMParameter参数中isHeaderBidding参数,该参数声明开发者在ToBid平台配置的ADN广告竞价类型:

isHeaderBidding为NO:表示普通广告位; isHeaderBidding为YES:表示客户端竞价广告位;

价格回调

参与比价的价格应通过对应广告类型回调协议中的ext设置WindMillConstant.ECPM回调字段回传到ToBid参与比价,该值为NSString类型,单位为分。

注意:

  1. 如ADN广告为非竞价类型,则WindMillConstant.ECPM回传价格无效;
  2. 如ADN广告为竞价类型,但WindMillConstant.ECPM值类型或内容错误,则无法参与比价。
  3. 如ADN广告为竞价类型,此时默认货币类型为CNY,如需美元,请在会传价格的同时,通过WindMillConstant.Currency传货币单位;目前支持CNY、USD。

比价结果通知

各广告Adapter协议中新增协议接口- (void)didReceiveBidResult:(AWMMediaBidResult *)result通知adapter开发者比价结果。

参数为AWMMediaBidResult类对象,该类中包含有竞价的结果信息,详情如下:

字段类型说明
winBOOL是否在本次竞价中获胜
winnerPriceNSInteger获胜者价格
extNSDictionary其他补充信息

更多信息请参考各广告Adapter协议部分。