Build your custom adapter for iOS

This document covers the steps to build a custom adapter and provide your publishers the resources required to integrate your network with Unity LevelPlay.

Important! If you’re upgrading your adapter to be compatible with ironSource SDK 7.2.0, make sure to follow the steps here.
Before you start
  1. Complete the custom adapter registration form 
  2. Make sure you have the following information available:
    • Adapter class names 
    • Network configuration keys
  3. Download latest ironSource SDK here

Important 

  • Make sure to handle main-thread requirements as part of your code
  • Make sure to add code protections and exception handling to protect apps from unexpected failures 

How to create an adapter for your network

Your network adapter will manage the network ads logic and allow publishers to display your networks ads as part of their Unity LevelPlay configuration. 

As part of this process, you will need to create an adapter class (referred as BaseAdapter) and an additional class for each ad unit you intend to support.

The BaseAdapter will back your network management, including the network initialization process, and allow you to define variables and constants that will be available throughout the session, for all ad units.

The ad unit classes will manage the ad unit logic for loading, showing, and managing the ad, and will be instantiated per each ad appearance in the waterfall.

Currently, custom adapters support interstitial ads.  

Create your network base adapter

To implement your network adapter, create a new class and import ironSource ISBaseNetworkAdapter class. 

Use the Base adapter name you received from your network registration confirmation email when creating your adapter. 

#import "IronSource/IronSource.h"
@interface IS<YourNetworkName>CustomAdapter : ISBaseNetworkAdapter
@objc(IS<YourNetworkName>CustomAdapter)
public class IS<YourNetworkName>CustomAdapter:ISBaseNetworkAdapter {
   ...
}

Initialize network SDK

Unity LevelPlay will call the init method of the base adapter as part of any initialization process in the mediation. As a result, this method can be called several times. 

As part of your init implementation, make sure to call the initialization callbacks defined in the NetworkInitializationListener each time; upon success (onInitSuccess) and/or upon failure (onInitFailed). 

The adData param will include the configuration data as provided by the publisher in the Unity LevelPlay platform. Learn more on ISAdData class here.  

(void)init:(ISAdData *)adData
  delegate:(id<ISNetworkInitializationDelegate>)delegate { 
   ... 
   // handle errors 
   if (error-handling) { 
      [delegate onInitDidFailWithErrorCode:ISAdapterErrorMissingParams 
                              errorMessage:error]; 
   } 
   // init success 
   [delegate onInitDidSucceed]; 
}
public override func `init` (_ adData: ISAdData, delegate: ISNetworkInitializationDelegate) {
   ... 
   // handle errors 
   if (error-handling) { 
      delegate.onInitDidFailWithErrorCode(ISAdapterErrors.missingParams.rawValue, errorMessage: "Fail to init SDK")
      return
   } 
   // init success 
   delegate.onInitDidSucceed()
   return        
}

Provide SDK and adapter versions

This information will indicate which SDK and adapter versions are currently implemented on the publisher’s app. When implementing getNetworkSDKVersion, we recommend using a method rather than a hard-coded value, to allow more flexibility in terms of adapter updates and SDK support.

- (NSString *) networkSDKVersion {
   return [ALSdk version];
}
- (NSString *) adapterVersion {
   return kAdapterVersion;
}
public override func networkSDKVersion() -> String {
   return  yourNetworkSDKVersion()
}
public override func adapterVersion() -> String {
   return self.customAdapterVersion;
}

Add support for interstitial ad unit

Create interstitial ad unit class

Create a class that will manage your interstitial ad unit. Import ironSource ISBaseAdAdapter, and make sure to add relevant delegates to your main adapter file. This class will be activated whenever the publisher triggers a new interstitial ad in the app by the Load method.

Important! Use the interstitial class names you received from ironSource as part of the registration process
#import "IronSource/IronSource.h"
@interface IS<YourNetworkName>CustomInterstitial : ISBaseInterstitial
@objc(IS<YourNetworkName>CustomInterstitial)
public class IS<YourNetworkName>CustomInterstitial  : ISBaseInterstitial {
   ...
}

Request an interstitial ad

Override the loadAdWithAdData method to allow publishers to request interstitial ads from your network. The ISAdData will allow you to access the publisher input and to receive the ad identifiers that are required for this process.

Make sure to implement the ISInterstitialAdDelegate callbacks for successful load of an ad (adDidLoad) and for any kind of failure (adDidFailToLoadWithErrorType). In case the listener callback is not triggered after a pre-defined amount of time, the meditation will stop the load process due to a timeout, and the network will not be able to provide an ad.

- (void)loadAdWithAdData:(nonnull ISAdData *)adData
                delegate:(nonnull id<ISInterstitialAdDelegate>)delegate {
  
   // Load your ad 
}
public override func loadAd(with adData: ISAdData, delegate: ISInterstitialAdDelegate) {

   // Load your ad
}

Check if ad is available

Override the isAdAvailableWithAdData method to allow publishers to check each ad’s readiness before trying to present it to the user. The method should return YES if an ad is loaded successfully, or NO if no ad is currently loaded. This can be done by using the network’s is-ad-available indication, if it exists, or by managing the ad’s status manually as part of loadAdWithAdData and showAdWithViewController methods.

- (BOOL)isAdAvailableWithAdData:(nonnull ISAdData *)adData {
   return _renderedAd != nil;
}
public override func isAdAvailable(with adData: ISAdData) -> Bool {
   ...
   return false
}

Show an interstitial ad

Once an ad is loaded successfully, the publisher should be able to show it. You can override the showAdWithViewController method after verifying that isAdAvailableWithAdData is true, to provide a better experience for publishers. Part of the information you receive in this method is ISAdData. Using this object, you will be allowed to show the relevant ad. The adDidFailToShowWithErrorCode callback should be returned if the show could not be performed.

- (void)showAdWithViewController:(nonnull UIViewController *)viewController
                          adData:(nonnull ISAdData *)adData
                        delegate:(nonnull id<ISInterstitialAdDelegate>)delegate {
   // check if ad can be displayed
   if (CannotShowsAd) {
      [delegate adDidFailToShowWithErrorCode:ISAdapterErrorInternal
                                 errorMessage:nil];
      return;
   }
   // show ad 
   [_ad showAd:_renderedAd];
}
public override func showAd(with viewController: UIViewController, adData: ISAdData, delegate: ISInterstitialAdDelegate) {
   //save the delegate
   self.adDelegate = delegate
        
   // verify you have an ad to show for this configuration
   if isAdReady(withInstanceData: instanceData)) else {
      // return show failed callback
      delegate.adDidFailToShowWithErrorCode(ISAdapterErrors.internal.rawValue, errorMessage: "ad is not ready to show for the current instanceData")
      return
   }

   // show your network interstitial ad
   showInterstitialAd(withInstanceData: instanceData, adDelegate: self)
}

Report the ISInterstitialAdDelegate callbacks

Make sure to override ISInterstitialAdDelegate callbacks according to the network’s functionality. Reporting the delegates correctly will ensure Unity LevelPlay’s best practice flow, and will enable the network’s performance data to be reflected correctly in the ironSource platform. 

Mandatory callbacks:

// Indicates that interstitial ad was loaded successfully 
- (void)adDidLoad;

// The interstitial ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
- (void)adDidFailToLoadWithErrorType:(ISAdapterErrorType)errorType
                           errorCode:(NSInteger)errorCode
                        errorMessage:(NSString*)errorMessage;

// The interstitial ad was displayed successfully to the user. This indicates an impression.  
- (void)adDidOpen;

// User closed the interstitial ad
- (void)adDidClose;

// The ad could not be displayed 
- (void)adDidFailToShowWithErrorCode:(NSInteger)errorCode
                        errorMessage:(NSString*)errorMessage;
// Indicates that the interstitial ad was loaded successfully 
public func adDidLoad()

// The interstitial ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
public func adDidFailToLoadWith(_ errorType: ISAdapterErrorType, errorCode: Int, errorMessage: String!)

// The interstitial ad was displayed successfully to the user. This indicates an impression. 
public func adDidOpen()

// User closed the interstitial ad 
public func adDidClose()

// The ad could not be displayed 
public func adDidFailToShowWithErrorCode(_ errorCode: Int, errorMessage: String!)

Optional callbacks: 

// Implement if in addition to ad-open (impression), your ad network reports also show success indication 
- (void)adDidShowSucceed;

// Indicates the ad was clicked
- (void)adDidClick;
// Implement if in addition to ad-open (impression), your ad network reports also show success indication 
public func adDidShowSucceed()

// Indicates the ad was clicked
public func adDidClick()

How to get data from your base adapter (optional)

Use the getNetworkAdapter API if your base adapter manages states or params that are relevant for your ad units through the session. This includes any objects defined as part of your base adapter that should be used in your ad-unit APIs.

// example of data retrieved from your network level adapter
IS<yourNetworkName>CustomAdapter *sampleNetworkAdapter = nil;
id<ISAdapterBaseProtocol> adapter = [self getNetworkAdapter];
if ([adapter isKindOfClass:[IS<yourNetworkName>CustomAdapter class]]) {
   sampleNetworkAdapter = (IS<yourNetworkName>CustomAdapter*) adapter;
}

Add support for rewarded video ad unit

Create rewarded video ad unit class

Create a class that will manage your interstitial ad unit. Import ironSource ISBaseAdAdapter, and make sure to add relevant delegates to your main adapter file. This class will be activated whenever the publisher triggers a new interstitial ad in the app by the Load method.

Important! Use the rewarded video class names you received from ironSource as part of the registration process
#import "IronSource/IronSource.h"
@interface IS<YourNetworkName>CustomRewardedVideo : ISBaseRewardedVideo
@objc(IS<YourNetworkName>CustomRewardedVideo)
public class IS<YourNetworkName>CustomRewardedVideo : ISBaseRewardedVideo {
   ...
}

Request an rewardedVideo ad

Override the loadAdWithAdData method to allow publishers to request interstitial ads from your network. The ISAdData will allow you to access the publisher input and to receive the ad identifiers that are required for this process.

Make sure to implement the ISRewardedVideoAdDelegate callbacks for successful load of an ad (adDidLoad) and for any kind of failure (adDidFailToLoadWithErrorType). In case the listener callback is not triggered after a pre-defined amount of time, the meditation will stop the load process due to a timeout, and the network will not be able to provide an ad.

- (void)loadAdWithAdData:(nonnull ISAdData *)adData
                delegate:(nonnull id<ISRewardedVideoAdDelegate>)delegate {

   // Load your ad
}
public override func loadAd(with adData: ISAdData, delegate: ISRewardedVideoAdDelegate) {

   // Load your ad
}

Check if ad is available

Override the isAdAvailableWithAdData method to allow publishers to check each ad’s readiness before trying to present it to the user. The method should return YES if an ad is loaded successfully, or NO if no ad is currently loaded. This can be done by using the network’s is-ad-available indication, if it exists, or by managing the ad’s status manually as part of loadAdWithAdData and showAdWithViewController methods.

- (BOOL)isAdAvailableWithAdData:(nonnull ISAdData *)adData {
   ... 
   return _renderedAd != nil;
}
public override func isAdAvailable(with adData: ISAdData) -> Bool {
   ...
   return false
}

Show a rewarded video ad

Once an ad is loaded successfully, the publisher should be able to show it. You can override the showAdWithViewController method after verifying that isAdAvailableWithAdData is true, to provide a better experience for publishers. Part of the information you receive in this method is ISAdData. Using this object, you will be allowed to show the relevant ad. The adDidFailToShowWithErrorCode callback should be returned if the show could not be performed.

- (void)showAdWithViewController:(nonnull UIViewController *)viewController
                          adData:(nonnull ISAdData *)adData
                        delegate:(nonnull id<ISRewardedVideoAdDelegate>)delegate {
   // check if ad can be displayed if (CannotShowsAd) {
      [delegate adDidFailToShowWithErrorCode:ISAdapterErrorInternal
                                errorMessage:nil];
   
      return;
   }
   // show ad
   [_ad showAd:_renderedAd];
}
public override func showAd(with viewController: UIViewController, adData: ISAdData, delegate: ISRewardedVideoAdDelegate) {
   //save the delegate
   self.adDelegate = delegate
        
   // verify you have an ad to show for this configuration
   if isAdReady(withInstanceData: instanceData)) else {
      // return show failed callback
      delegate.adDidFailToShowWithErrorCode(ISAdapterErrors.internal.rawValue, errorMessage: "ad is not ready to show for the current instanceData")
      return
   }

   // show rewarded video ad
   showRewardedVideoAd(withInstanceData: instanceData, adDelegate: self)
}

Report the ISRewardedVideoAdDelegate callbacks

Make sure to override ISRewardedVideoAdDelegate callbacks according to the network’s functionality. Reporting the delegates correctly will ensure Unity LevelPlay mediation’s best practice flow, and will enable the network’s performance data to be reflected correctly in the ironSource platform. 

Mandatory callbacks:

// Indicates that rewarded video ad was loaded successfully 
- (void)adDidLoad;

// The rewarded video ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
- (void)adDidFailToLoadWithErrorType:(ISAdapterErrorType)errorType
                           errorCode:(NSInteger)errorCode
                        errorMessage:(NSString*)errorMessage;
// The rewarded video ad was displayed successfully to the user. This indicates an impression. 
- (void)adDidOpen;

// User closed the rewarded video ad 
- (void)adDidClose;

// The ad could not be displayed 
- (void)adDidFailToShowWithErrorCode:(NSInteger)errorCode 
                        errorMessage:(NSString*)errorMessage;

// User clicked the rewarded video ad 
- (void)adDidClick;

// User received a reward after watching the ad
- (void)adRewarded;
// Indicates that rewarded video ad was loaded successfully 
public func adDidLoad()

// The rewarded video ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
public func adDidFailToLoadWith(_ errorType: ISAdapterErrorType, errorCode: Int, errorMessage: String!)

// The rewarded video ad was displayed successfully to the user. This indicates an impression. 
public func adDidOpen()

// User closed the rewarded video ad 
public func adDidClose()

// The ad could not be displayed 
public func adDidFailToShowWithErrorCode(_ errorCode: Int, errorMessage: String!)

// User clicked the rewarded video ad 
public func adDidClick()

// User received a reward after watching the ad
public func adRewarded()

Optional callbacks: 

// Indicates the video ad started 
- (void)adDidStart;

// Indicates the video ad ended 
- (void)adDidEnd

// indicates that ad is displayed on foreground 
- (void)adDidBecomeVisible

// Implement if in addition to ad-open (impression), your ad network reports also show success indication 
- (void)adDidShowSucceed
// Indicates the video ad started 
public func adDidStart()

// Indicates the video ad ended 
public func adDidEnd()

// Indicates that ad is displayed on foreground 
public func adDidBecomeVisible()

// Implement if in addition to ad-open (impression), your ad network reports also show success indication 
public func adDidShowSucceed()

How to get data from your base adapter (optional)

Use the getNetworkAdapter API if your base adapter manages states or params that are relevant for your ad units through the session. This includes any objects defined as part of your base adapter that should be used in your ad-unit APIs.

// example of data retrieved from your network level adapter
IS<yourNetworkName>CustomAdapter *sampleNetworkAdapter = nil;
id<ISAdapterBaseProtocol> adapter = [self getNetworkAdapter];
if ([adapter isKindOfClass:[IS<yourNetworkName>CustomAdapter class]]) {
   sampleNetworkAdapter = (IS<yourNetworkName>CustomAdapter*) adapter;
}

Add support for banner ad unit

Step 1. Create banner ad unit class

Create a class that will manage your banner ad unit.  This class will be activated whenever the publisher triggers a new banner ad in the app by the Load method.

Important! Use the banner class names you received from ironSource as part of the registration process.

#import "IronSource/IronSource.h"
@interface IS<YourNetworkName>CustomBanner : ISBaseBanner
@objc(IS<YourNetworkName>CustomBanner)
public class IS<YourNetworkName>CustomBanner : ISBaseBanner {

}

Banner Sizes

See the table below for details about our supported banner sizes. Custom networks may support any combination of these sizes. The banner size will be received as a param as part of the loadAdWithAdData API. 

When the banner size received is SMART, make sure to change the size either to BANNER or LEADERBOARD, according to the device screen sizes (see instructions below).

ISBannerSize Description Dimensions in points (WxH)
ISBannerSize_BANNER Standard Banner 320 x 50
ISBannerSize_LARGE Large Banner 320 x 90
ISBannerSize_RECTANGLE Medium Rectangular (MREC) 300 x 250
ISBannerSize_SMART
Smart Banner
(Automatically renders ads to adjust size and orientation for iPhone & iPad)
If (iPhone ≤ 720) 320 x 50
If (iPad > 720) 728 x 90

Step 2. Request a banner ad

Override the loadAdWithAdData method to allow publishers to request banner ads from your network. The ISAdData will allow you to access the publisher input and to receive the ad identifiers that are required for this process, and the ISBannerSize will indicate the requested banner size.

- (void)loadAdWithAdData:(nonnull ISAdData *)adData
     viewController:(UIViewController *)viewController
          size:(ISBannerSize *)size
        delegate:(nonnull id<ISBannerAdDelegate>)delegate{
}
public override func loadAd(with adData: ISAdData, viewController : UIViewController, size : ISBannerSize, delegate: ISBannerAdDelegate){
}

Step 3. Destroy banner

ironSource requires app developers to destroy a banner ad by implementing the following destroyAdWithAdData method.

 public void destroyAdWithAdData:(nonnull ISAdData *)adData {
    }
public override func destroyAd(with adData: ISAdData){
}

Note: If your network SDK does not support this kind of API, you should add an empty implementation.

Step 4. Report the ISBannerAdDelegate callbacks

Report the ISBannerAdDelegate callbacks according to the network’s functionality. This will ensure the network’s performance data to be reflected correctly in the ironSource platform. 

Mandatory callbacks:

// Indicates that a banner ad was loaded successfully 
- (void)adDidLoadWithView:(UIView *) view
// The banner ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
-(void)adDidFailToLoadWithErrorType:(ISAdapterErrorType)errorType
             errorCode:(NSInteger)errorCode
            errorMessage:(nullable NSString*)errorMessage
// The banner ad is displayed successfully to the user. This indicates an impression on the ironSource platform. 
-(void)adDidOpen
// Indicates an ad was clicked 
-(void)adDidClick
// Indicates that a banner ad was loaded successfully 
public func adDidLoad(_ bannerView: UIView)
// The banner ad failed to load. Use ironSource ErrorTypes (No Fill / Other) 
public func adDidFailToLoadWith(_ errorType: ISAdapterErrorType, errorCode: Int, errorMessage: String!)
// The banner ad is displayed successfully to the user. This indicates an impression on the ironSource platform. 
public func adDidOpen()
// Indicates an ad was clicked 
public func adDidClick()

Note: Make sure to pass the banner view returned by the network.

Optional callbacks: 

//Should be invoked after a click, and before the user is taken out of the app 
- (void)adWillLeaveApplication
// Should be invoked after the ad view presents fullscreen content- (void)adWillPresentScreen;
- (void)adWillPresentScreen
// Should be invoked after the fullscreen content is dismissed
- (void)adDidDismissScreen
//Should be invoked after a click, and before the user is taken out of the app 
- (void)adWillLeaveApplication
// Should be invoked after the ad view presents fullscreen content- (void)adWillPresentScreen;
- (void)adWillPresentScreen
// Should be invoked after the fullscreen content is dismissed
- (void)adDidDismissScreen

Access publisher’s input via the adapter

As part of the custom adapter registration process, you provided App and Instance level keys. 

The value of these keys will be defined by the publisher on the Unity LevelPlay platform configuration. These values will be available for you in run-time via the ISAdData object. 

The ISAdData object contains a map with the configuration values, and is part of the adapter and the ad unit classes APIs. This parameter is available in the init, loadAdWithAdData, showAdWithViewController and isAdAvailableWithAdData methods.

You can access the values from the ISAdData map structure using the names you received as part of the registration confirmation email. 

// Get Publisher setup parameters 
NSString *appLevelParam1 = ISAdData.configuration[<YourAppLevelParam1>];
NSString *instanceLevelParam1 = ISAdData.configuration[<YourInstanceLevelParam1>];
NSString *instanceLevelParam2 = ISAdData.configuration[<YourInstanceLevelParam2>];
// Get Publisher setup parameters 
self.appData = adData.getString(IS<YourNetworkName>CustomAdapter.<YourAppLevelParam>);
self.instanceData1 = adData.getString(IS<YourNetworkName>CustomAdapter.<YourInstanceLevelParam1>);
self.instanceData2 = adData.getString(IS<YourNetworkName>CustomAdapter.<YourInstanceLevelParam2>);

Use ironSource error codes and error types

Error type

This is relevant for adDidFailToLoadWithErrorType delegates. 

Error type Description
ISAdapterErrorTypeNoFill Used when there is no available ad to show
ISAdapterErrorTypeInternal Used for any other reason reported by the network

Error codes

These error codes are relevant for adDidFailToLoadWithErrorType and adDidFailToShowWithErrorCode delegates. 

Error code Description
ISAdapterErrorMissingParams The action failed because some required information was not available when API was called
ISAdapterErrorAdExpired Use to indicate if the ad was expired
ISAdapterErrorInternal Used for any other error reported by the network

Debug your adapter (optional)

If you choose to support debug logs, implement and call the setAdapterDebug method from your app. This should be done as part of the ISBaseNetworkAdapter

- (void) setAdapterDebug:(BOOL) adapterDebug {
   _adapterDebug = adapterDebug;
}
public override func setAdapterDebug(_ adapterDebug: Bool) {
  self.adapterDebug = adapterDebug
}