This section mainly describes how to implement Client Bidding with a Custom Adapter.
The Client Bidding loading process is shown below:

| Abstract Method | Parameter Description | Return Value | Purpose | Required |
|---|---|---|---|---|
| + (void)bidRequestWithPlacementModel:(ATPlacementModel *)placementModel unitGroupModel:(ATUnitGroupModel *)unitGroupModel info:(NSDictionary *)info completion:(void(^)(ATBidInfo *bidInfo, NSError *error))completion | completion: After header bidding is completed, this callback must be executed to pass the bidding data or error back to the TopOn SDK | void | To implement custom header bidding, this class method must be implemented | Yes |
| + (void)sendWinnerNotifyWithCustomObject:(id)customObject secondPrice:(NSString*)price userInfo:(NSDictionary *)userInfo; | customObject is the ad object. price: the second price of the bid win | void | To implement custom header bidding, this class method must be implemented | No |
| + (void)sendLossNotifyWithCustomObject:(nonnull id)customObject lossType:(ATBiddingLossType)lossType winPrice:(nonnull NSString *)price userInfo:(NSDictionary *)userInfo; | customObject is the ad object. lossType is the bid loss reason. price: the win price of the bid | void | To implement custom header bidding, this class method must be implemented | No |
Implement the above methods, using Baidu as an example.
//Import header file
#import
Add the following method, which is a required protocol method, and implement the following logical steps within it:
Initiate the Ad Source C2S header bidding request.
Obtain the price returned by the Ad Source C2S header bidding and construct an ATBidInfo object.
Call the completion block and pass in the ATBidInfo object.
- (void)bidRequestWithPlacementModel:(ATPlacementModel\*)placementModel unitGroupModel:(ATUnitGroupModel\*)unitGroupModel info:(NSDictionary\*)info completion:(void(^)(ATBidInfo \*bidInfo, NSError \*error))completion {
// 1. Check whether to initialize the ad platform SDK
// 2. Initiate the Ad Source C2S header bidding request.
...
// If bidding fails, execute the callback and pass in the error
NSError \*error = ...;
if (error) {
completion(nil, error);
return;
}
// 3. Obtain the price returned by the Ad Source C2S header bidding and construct an ATBidInfo object.
NSString \*price = ...;
// Confirm the currency unit to be passed in: currencyType
ATBidInfo \*info = \[ATBidInfo bidInfoC2SWithPlacementID:placementModel.placementID
unitGroupUnitID:unitGroupModel.unitID
adapterClassString:request.unitGroup.adapterClassString
price:price
currencyType:ATBiddingCurrencyTypeCNY
expirationInterval:unitGroupModel.networkTimeout
customObject:nil];
// Then pass it back to the TopOn SDK
**Note: In version 5.9.90, by implementing the following methods, you can skip overriding the loadADWithInfo method.**
// bidInfo.isC2SNotNeedLoad = YES;
// bidInfo.c2SCustomEvent = customEvent;
// bidInfo.c2sCustomObject = customObject;
// 4. Call the completion block and pass in the ATBidInfo object
completion(info, nil);
}
Adjust the logic of the loadAdWithInfo method in the Adapter class. Refer to the following:
- (void)loadWithServerInfo:(NSDictionary \*)serverInfo localInfo:(NSDictionary \*)localInfo {
NSString \*bidId = serverInfo\[kATAdapterCustomInfoBuyeruIdKey];
//If there is a bidId, it means this is a header bidding Ad Source
if (bidId) {
//Check if the Ad Source has already been loaded
if (\_rewardedVideo.isReady) {
\[\_customEvent trackRewardedVideoAdLoaded:\_rewardedVideo adExtra:nil];
}
}
.....
}
At this point, based on your business logic, you can already develop C2S requests. Below is a more complete example for your reference.
Import header file
#import
In practice, most ad platforms return data through delegate callbacks. Therefore, you need to create a class to receive callbacks. Below is a simple example in ATBaiduRewardedVideoCustomEvent.
#import "ATRewardedVideoCustomEvent.h"
#import "ATBaiduRewardedVideoAdapter.h"
#import
@interface ATBaiduRewardedVideoCustomEvent : ATRewardedVideoCustomEvent
@property (nonatomic, assign) BOOL isC2SBiding;
@end
@interface ATBaiduRewardedVideoCustomEvent()
@end
@implementation ATBaiduRewardedVideoCustomEvent
- (void)rewardedVideoAdLoaded:(BaiduMobAdRewardVideo *)video {
if (self.isC2SBiding) {
NSString *price = @"替换成你的广告平台获取到的价格"
//Price used for sorting
NSString *sortPrice = @"替换成你需要";
//Construct ATBidInfo object to return to the SDK
ATBidInfo *bidInfo = [ATBidInfo bidInfoC2SWithPlacementID:request.placementID unitGroupUnitID:request.unitGroup.unitID adapterClassString:request.unitGroup.adapterClassString price:priceStr sortPrice:sortPrice currencyType:ATBiddingCurrencyTypeUS expirationInterval:request.unitGroup.bidTokenTime customObject:customObject];
bidInfo.networkFirmID = request.unitGroup.networkFirmID;
//Call bidCompletion to return bidInfo to the SDK
if (request.bidCompletion) {
request.bidCompletion(bidInfo, nil);
}
self.isC2SBiding = NO;
}
......
}
- (void)rewardedVideoAdLoadFailed:(BaiduMobAdRewardVideo *)video withError:(BaiduMobFailReason)reason {
if (self.isC2SBiding) {
[self trackRewardedVideoAdLoadFailed:[NSError errorWithDomain:@"com.anythink.BaiduRewardedVideo" code:reason userInfo:@{NSLocalizedDescriptionKey:kATSDKFailedToLoadRewardedVideoADMsg, NSLocalizedFailureReasonErrorKey:@"BaiduSDK has failed to load rewarded video."}]];
}
.....
}
@end
Use a BiddingRequest to save C2S request data.
@interface ATBaiduBiddingRequest : NSObject
@property(nonatomic, strong) id customObject;
@property(nonatomic, strong) ATUnitGroupModel *unitGroup;
@property(nonatomic, strong) ATAdCustomEvent *customEvent;
@property(nonatomic, copy) NSString *unitID;
@property(nonatomic, copy) NSString *placementID;
@property(nonatomic, copy) NSString *publisherID;
@property(nonatomic, copy) NSDictionary *extraInfo;
@end
Create an ATBaiduC2SBiddingRequestManager class to store the request in memory.
#import
#import "ATBaiduBiddingRequest.h"
#import "ATC2SBiddingParameterManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface ATBaiduC2SBiddingRequestManager : NSObject
+ (instancetype)sharedInstance;
- (void)startWithRequestItem:(ATBaiduBiddingRequest *)request;
@end
@implementation ATBaiduC2SBiddingRequestManager
+ (instancetype)sharedInstance {
static ATBaiduC2SBiddingRequestManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ATBaiduC2SBiddingRequestManager alloc] init];
});
return sharedInstance;
}
- (void)startWithRequestItem:(ATBaiduBiddingRequest *)request {
NSString *adplaceidStr = request.unitGroup.content[@"ad_place_id"];
[[ATC2SBiddingParameterManager sharedInstance] saveRequestItem:request withUnitId:adplaceidStr];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *appidStr = request.unitGroup.content[@"app_id"];
NSString *adplaceidStr = request.unitGroup.content[@"ad_place_id"];
BaiduMobAdRewardVideo *rewardedVideo = [[BaiduMobAdRewardVideo alloc] init];
rewardedVideo.delegate = request.customEvent;
rewardedVideo.AdUnitTag = adplaceidStr;
rewardedVideo.publisherId = appidStr;
request.customObject = rewardedVideo;
[rewardedVideo load];
});
}
NS_ASSUME_NONNULL_END
Add the following logic for the required methods:
+ (void)bidRequestWithPlacementModel:(ATPlacementModel*)placementModel unitGroupModel:(ATUnitGroupModel*)unitGroupModel info:(NSDictionary*)info completion:(void(^)(ATBidInfo *bidInfo, NSError *error))completion {
ATBaiduRewardedVideoCustomEvent *customEvent = [[ATBaiduRewardedVideoCustomEvent alloc] initWithInfo:info localInfo:info];
customEvent.isC2SBiding = YES;
//Create an ATBaiduBiddingRequest to store the information needed for the request
ATBaiduBiddingRequest *request = [ATBaiduBiddingRequest new];
request.unitGroup = unitGroupModel;
request.placementID = placementModel.placementID;
request.bidCompletion = completion;
request.unitID = info[@"ad_place_id"];
request.extraInfo = info;
request.adType = ATAdFormatRewardedVideo;
//Ad Source callback to the customEvent object
request.customEvent = customEvent;
//Create an ATBaiduC2SBiddingRequestManager to store the request in memory
[[ATBaiduC2SBiddingRequestManager sharedInstance] startWithRequestItem:request];
}
Finally, adjust the methods in the BaiduRewardedVideoAdapter class.
- (void)loadWithServerInfo:(NSDictionary *)serverInfo localInfo:(NSDictionary *)localInfo {
NSString *bidId = serverInfo[kATAdapterCustomInfoBuyeruIdKey];
if (bidId) {
ATBaiduBiddingRequest *request = [[ATC2SBiddingParameterManager sharedInstance] getRequestItemWithUnitID:serverInfo[@"ad_place_id"]];
if (request != nil) {
if (request.customObject) {
_rewardedVideo = request.customObject;
_rewardedVideo.delegate = _customEvent;
if (_rewardedVideo.isReady) {
[_customEvent trackRewardedVideoAdLoaded:_rewardedVideo adExtra:nil];
} else {
[_rewardedVideo load];
}
}
// remove requestItem
[[ATC2SBiddingParameterManager sharedInstance] removeRequestItemWithUnitID:serverInfo[@"ad_place_id"]];
}
}
}
Parameter description:
| Parameter Name | Parameter Description |
|---|---|
| AdapterName | Custom Adapter class name |
| networkCacheTime | Cache time at the Ad Source level (unit: ms) |
| bidRealTimeLoadSW | Real-time bidding on every Load switch at the Ad Source level |
NSMutableArray *array = [NSMutableArray array];
ATCustomNetworkMode *splshMode = [[ATCustomNetworkMode alloc]initWithAdapterName:@"AdapterName" networkCacheTime:1800 bidRealTimeLoadSW:YES];
[array addObject:splshMode];
[[ATSDKGlobalSetting sharedManager] addCustomAdapterConfigArray:array];