自定义广告平台Adapter实现
简介
本文档将介绍在iOS端如何实现自定义广告平台Adapter,主要包括初始化、加载广告、展示广告以及各广告类型的响应事件回调处理。文档中代码截取来源于Demo。
支持广告类型
目前支持的广告类型有五种,如下所示:
- 原生广告(Native)
- 开屏广告(Splash)
- Banner广告
- 激励视频广告(RewardedVideo)
- 插屏广告(Interstitial)
核心流程实现
- 定义Adapter类名,包括配置Adapter以及各广告类型对应Adapter,并遵循相关协议;
- 在ToBid开发者平台配置相关信息,详情参见平台部分文档;
- 实现协议方法完成初始化(含隐私合规)、广告加载、展示方法及回调,详见下方说明;
常见问题
- 自定义Adapter需要按照示例中相应方法含义调用,否则会影响收益;
- 及时更新协议版本号为ToBid支持的最新版本,否则可能无法使用;
- 自定义Adapter广告load之前需要确保开发者实现了AWMCustomConfigAdapter协议并初始化network成功,network版本号,Adapter版本号均不能为空;
- 自定义Adapter广告load成功或者失败只能调用一次;
- 所有调用自定义adapter的方法均在主线程,请勿进行耗时操作;
- 自定义Adapter支持广告频次控制、广告间隔控制、AB测试;
- 自定义Adapter不支持show时预加载、Service bidding、多阶底价。支持Client bidding;
- 自定义Adapter广告对象的show、click等回调需要在load广告回调之后;
- ToBid已经处理了Banner的轮播,自定义Banner需要禁用轮播。
初始化配置
协议内容
自定义Adapter必须要有配置类,在配置类中完成Adapter及对应network的信息采集,对应协议为AWMCustomConfigAdapter,接口实现如下所示:
@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@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
}示例代码
@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@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,接口实现如下所示:
@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@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文件。
@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;
}
@endimport 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.LinkID | NSString | 聚合请求ID |
| WindMillConstant.MediationRitID | NSString | 聚合广告位ID |
| WindMillConstant.MediaID | NSString | ADN平台ID,平台生成的唯一ID |
| WindMillConstant.BottomView | UIView | 自定义底部视图 |
| WindMillConstant.AdSize | NSValue/CGSize | 期望广告尺寸 |
| WindMillConstant.BottomViewSize | NSValue/CGSize | 自定义底部视图尺寸 |
| WindMillConstant.Timeout | NSNumber/NSInteger | 开屏超时时间 |
广告展示
在Splash广告的adapter中使用如下方法完成广告展示,更完整信息请查看WindMillSDK.h文件。
- (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];
}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协议。
@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@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,接口实现如下所示:
@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@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文件。
@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;
}
@endimport 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
}
} |
加载参数
| 参数名 | 参数类型 | 参数含义 |
|---|---|---|
| AWMAdLoadingParamLinkID | NSString | 聚合请求ID |
| AWMAdLoadingParamMediationRitID | NSString | 聚合广告位ID |
| AWMAdLoadingParamMediaName | NSString | ADN广告位名称,平台配置名称 |
| AWMAdLoadingParamMediaID | NSString | ADN平台ID,平台生成的唯一ID |
| AWMAdLoadingParamCustomJson | NSString | 自定义Adapter扩展参数 |
回调协议
开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomSplashAdapterBridge协议。
@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@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,接口实现如下所示:
@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@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文件。
@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;
}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 | 聚合请求ID | NSString |
| WindMillConstant.MediationRitID | 聚合广告位ID | NSString |
| AWMAdLoadingParamMediaName | ADN广告位名称,平台配置名称 | NSString |
| WindMillConstant.MediaID | ADN平台ID,平台生成的唯一ID | NSString |
| WindMillConstant.ExperimentId | 聚合实验id | NSString |
| WindMillConstant.StrategyId | 聚合策略id | NSString |
广告展示
在激励视频广告的adapter中使用如下方法完成广告展示,更完整信息请查看AWMAdLoadingParam.h文件。
- (BOOL)showAdFromRootViewController:(UIViewController *)viewController parameter:(AWMParameter *)parameter {
return [self.rewardedVideoAd showAdFromRootViewController:viewController];
}func showAdFromRootViewController(_ viewController: UIViewController, parameter: WindMillSDK.AWMParameter) {
rewardedVideoAd?.show(fromRootViewController: viewController)
}回调协议
开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomRewardedVideoAdapterBridge协议。
@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@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,接口实现如下所示:
@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@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文件。
@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;
}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 | 聚合请求ID | NSString |
| WindMillConstant.MediationRitID | 聚合广告位ID | NSString |
| AWMAdLoadingParamMediaName | ADN广告位名称,平台配置名称 | NSString |
| WindMillConstant.MediaID | ADN平台ID,平台生成的唯一ID | NSString |
| WindMillConstant.ExperimentId | 聚合实验id | NSString |
| WindMillConstant.StrategyId | 聚合策略id | NSString |
广告展示
在插屏广告的adapter中使用如下方法完成广告展示,更完整信息请查看AWMAdLoadingParam.h文件。
- (BOOL)showAdFromRootViewController:(UIViewController *)viewController parameter:(AWMParameter *)parameter {
[self.ad showAdFromRootViewController:viewController];
return YES;
}func showAdFromRootViewController(_ viewController: UIViewController, parameter: WindMillSDK.AWMParameter) {
intersititialAd?.show(fromRootViewController: viewController)
}回调协议
开发者需通过回调方式将广告加载/展示/交互情况通知到ToBid,以保证流程的完整性。协议内容详见AWMCustomInterstitialAdapterBridge.h协议。
@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@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,接口实现如下所示:
@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@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接口如下:
@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@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协议内容如下:
@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@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协议内容如下:
@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@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参数包括了本次广告加载的所有数据。
@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];
}
@endclass 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协议。
@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@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类型,单位为分。
注意:
- 如ADN广告为非竞价类型,则WindMillConstant.ECPM回传价格无效;
- 如ADN广告为竞价类型,但WindMillConstant.ECPM值类型或内容错误,则无法参与比价。
- 如ADN广告为竞价类型,此时默认货币类型为CNY,如需美元,请在会传价格的同时,通过WindMillConstant.Currency传货币单位;目前支持CNY、USD。
比价结果通知
各广告Adapter协议中新增协议接口- (void)didReceiveBidResult:(AWMMediaBidResult *)result通知adapter开发者比价结果。
参数为AWMMediaBidResult类对象,该类中包含有竞价的结果信息,详情如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| win | BOOL | 是否在本次竞价中获胜 |
| winnerPrice | NSInteger | 获胜者价格 |
| ext | NSDictionary | 其他补充信息 |
更多信息请参考各广告Adapter协议部分。