Menu

Implementing Bidding for Custom Ads

1. Custom Adapter Implementing Header Bidding

This section mainly describes how to implement Client Bidding with a Custom Adapter.

The Client Bidding loading process is shown below:

  • When the developer calls the [[ATAdManager sharedManager] loadADWithPlacementID:self.placementID extra:dict delegate:self]; API, it will call the Custom Adapter's bidRequestWithPlacementModel method.
  • Developers need to override +(void)bidRequestWithPlacementModel:(ATPlacementModel *)placementModel unitGroupModel:(ATUnitGroupModel *)unitGroupModel info:(NSDictionary *)info completion:(void(^)(ATBidInfo *bidInfo, NSError *error))completion. In this method, call the custom ad platform's API to initiate initialization (skip if already initialized) and ad bidding.

1.1 Implement the following methods

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

1.2 Code Implementation

Implement the above methods, using Baidu as an example.

Copy
//Import header file
#import 

Add the following method, which is a required protocol method, and implement the following logical steps within it:

  1. Initiate the Ad Source C2S header bidding request.

  2. Obtain the price returned by the Ad Source C2S header bidding and construct an ATBidInfo object.

  3. Call the completion block and pass in the ATBidInfo object.

    Copy
    - (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);
      }
  4. Adjust the logic of the loadAdWithInfo method in the Adapter class. Refer to the following:

    Copy
    - (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.

2. Complete Code Implementation


2.1 Using Rewarded Video as an example, inherit the ATRewardedVideoCustomEvent object

Import header file

Copy
#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.

Copy
#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.

Copy
@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:

Copy
+ (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.

Copy
- (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"]];
        }
    }
}

3. Custom Adapter Supports Developer-Set Waterfall Request Strategy


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
Copy
NSMutableArray *array = [NSMutableArray array];
ATCustomNetworkMode *splshMode = [[ATCustomNetworkMode alloc]initWithAdapterName:@"AdapterName" networkCacheTime:1800 bidRealTimeLoadSW:YES];
[array addObject:splshMode];
[[ATSDKGlobalSetting sharedManager] addCustomAdapterConfigArray:array];
Previous
Custom advertising platform SDK version <6.4.94
Next
Rewarded video
Last modified: 2026-07-09Powered by