• iOS Ad Mediation

UniAds: A Manageable Native iOS Ad Network Mediation

Eugene Dorfman
4 Mar 2020
15 min
UniAds: A Manageable Native iOS Ad Network Mediation

Having worked with publishers and SSPs for the last few years, we’ve discovered that the most popular objections for integrating another Ad SDK are purely technical: it takes too long, maintenance becomes a burden, etc. At first, we thought it was a problem of smaller publishers not having enough resources, but we quickly realized that this was also the case with larger ones.

When a product is being developed, the architecture of the monetization layer is often an afterthought. This is why developers usually don’t engineer it well enough. SSPs, on the other hand, are interested in quickly getting publishers on board but don’t give recommendations on the architecture of maintaining several Ad SDKs in several apps of a single publisher.

Do you have the same issues and don’t have time to read the whole article? Book a call with us to discuss how we can help you asap.

Book a strategy session

Get actionable insights for your product

    Success!

    We’ll reach out to schedule a call

    Postindustria wants to fill in the gap by offering a simple approach to managing a native client-side ad network mediation set up across all our iOS apps. We will do this by leveraging a package manager. This approach is easily portable to Android as well, and will only require an Android-specific package manager.

    Let’s briefly answer what is ad mediation. Imagine an app that monetizes by showing ads to users. In the ad tech jargon, this is called “selling users’ traffic [to some advertisers].” Advertisers, aka buyers, represent the demand side of the market while app publishers, aka sellers, represent the supply side. To simplify, we will imagine a single ad space represented as a 320×50 banner ad unit on an arbitrary user’s device screen.UniAds: A Manageable Native iOS Ad Network Mediation - photo 1

    The banner view is instantiated by an Ad Network SDK, which is a native library shipped as part of the app. Once instantiated, the code makes a request to the ad server of that ad network and, with luck, downloads the ad creative. The key phrase here is “with luck” and “luck” (in this context) in ad tech jargon means “fill rate.” The fill rate is the ratio of ad impressions (an event when the creative has been successfully downloaded and shown to the user) to ad requests or attempts (an event when the call is made to the server to retrieve an ad).

    If the fill rate is 100%, it means that every request results in an impression. In reality, it is rare for a single network to reach anything above the 70% fill rate. Usually, it is much lower, sometimes as low as 5% or less. The publisher strives to maximize the fill rate and, thus, the revenue. The reason being, we are paid for impressions, not for showing an empty banner. This is where mediation comes to the rescue.

    Instead of one ad network SDK, we integrate several, offering a primary mediation SDK to serve as a dispatcher. In our case, we use MoPub SDK as a mediation platform, and various 3rd party SDKs are connected by providing their implementation of the MPBannerCustomEvent base class. MPBannerCustomEvent specifies the methods which MoPub then knows when and how to call. UniAds: A Manageable Native iOS Ad Network Mediation - photo 2

    MoPub SDK uses dynamic language features to instantiate custom event classes – those of Objective-C and Java. For instance, when MoPub ad server schedules an attempt for the Smaato ad network to request its ad, MoPub SDK receives the name of that custom event class (“SMAMoPubSmaatoBannerAdapter”) in the ad server response and attempts to instantiate that class by its name. If instantiation is successful, the control is passed on. Then, a 3rd party SDK banner adapter (or a custom event in MoPub terms) allows the ad network SDK to make a call to its ad server, instantiate a banner, show an ad, track impression/click events, etc.

    The most important feature of this setup, however, is the failover. In case the ad network SDK fails to load an ad (experiences a no-fill), it calls a delegate method to notify MoPub SDK, and MoPub SDK then asks the server who it should instantiate next. And the dance repeats. This is how the ball is passed to the next ad network until one successfully shows an ad. After the successful impression, the ad banner refresh interval elapses, and MoPub SDK makes another request to its ad server to receive the next custom event class name.

    The order of traversing a list of ad network adapters is ruled by the priorities and CPMs of ad sources set up for this particular ad unit on the MoPub ad server. This list is called the waterfall.

    Here is a sequence diagram to illustrate the waterfall traversal:UniAds: A Manageable Native iOS Ad Network Mediation - photo 3

    Ad Mediation in Practice

    To enable ad mediation in an app with MoPub, follow three basic steps:

    • integrate MoPub SDK 
    • ship 3rd party ad network SDKs together with your app binary
    • ship MoPub adapters for these SDKs (custom event classes)

    MoPub SDK integration is fairly straightforward.

    To make life easier, we decided to package ad network SDKs together with corresponding adapters, forming a custom CocoaPods package (Pod). The package is described using a metadata file called Podspec. Podpsecs are hosted in the global package repository on Github, where you can set up a local Spec repo and host your specs to use within the company. This is how we distribute shared dependencies across several apps.

    The Podspec format allows splitting package metadata into Subspecs. Subspecs can reference other Subspecs as dependencies, and this builds a dependency tree.

    UniAds.podspec contains a Subspec for each ad network SDK and a Subspec for the corresponding MoPub adapters. The adapter Subspec includes the SDK subspec as a dependency. There are also three top-level Subspecs that group-specific networks, being some apps do not need to include all of the ad network SDKs.

    Here is an excerpt from the Podspec code:

    Pod::Spec.new do |s|  
    
     s.name = 'UniAds'
     s.version = '7.24.3'
     s.platform = :ios,'10.0'
     s.license = {:type => 'MIT'}
     s.summary = 'common ad network SDKs, MoPub mediation adapters and various ad helpers'
     s.author = {'Postindustria' => 'support@postindustria.com'}
     s.source = {:git => 'git@gitlab.postindustria.com:ios/uniads.git', :tag => s.version}
     s.homepage = 'http://postindustria.com'
     s.default_subspec = 'All'
     s.public_header_files = 'UniAds/Adapters/Common/*.h' 
    #
    # Create subspecs grouping the networks you need
    #  
    
     s.subspec 'NoFacebookAdMob' do |ss|   
    
      ss.dependency 'mopub-ios-sdk', '~>5.0'
      ss.dependency 'UniAds/Common'
      ss.dependency 'UniAds/AdTargeting'
      ss.dependency 'UniAds/Verizon'
      ss.dependency 'UniAds/Smaato'
      ss.dependency 'UniAds/SmaatoNextGen'
      ss.dependency 'UniAds/ValidMedia'
      ss.dependency 'UniAds/AdMarketplace'
      ss.dependency 'UniAds/InMobi'
      ss.dependency 'UniAds/Amazon'
      ss.dependency 'UniAds/MobFox'
      ss.dependency 'UniAds/Inneractive'
      ss.dependency 'UniAds/Tappx'
      ss.dependency 'UniAds/OpenX'
      ss.pod_target_xcconfig = { 'ENABLE_BITCODE' => false }  
    
     end  
    
     s.subspec 'All' do |ss|   
    
      ss.dependency 'UniAds/NoFacebookAdMob'
      ss.dependency 'UniAds/AdMob'
      ss.dependency 'UniAds/DFP'
      ss.dependency 'UniAds/Facebook'
     end
    An example of a network SDK subspec:
    
    # 
    # SmaatoNextGen
    # 
    
    s.subspec 'SmaatoNextGenSDK' do |ss|
      ss.vendored_frameworks = ['UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKBanner.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKCore.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKInterstitial.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKOpenMeasurement.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKRewardedAds.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKRichMedia.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKUnifiedBidding.framework','UniAds/SDKs/SmaatoNextGenSDK/SmaatoSDKVideo.framework','UniAds/SDKs/SmaatoNextGenSDK/vendor/OMSDK_Smaato.framework']
     end
      
    
     s.subspec 'SmaatoNextGen' do |ss|
      ss.source_files = 'UniAds/Adapters/SmaatoNextGen/*/*.*'
      ss.dependency 'UniAds/Common'
      ss.dependency 'UniAds/SmaatoNextGenSDK'
     end

    The Podfile of any app would refer to the UniAds.podspec:

    pod 'UniAds/NoFacebook'

    Another app, in case it uses all of the SDKs, can specify:

    pod 'UniAds/All'

    Testing application

    There are several areas we test in our ad network mediation setup:

    • Podspec validity. Will this dependency play nicely when integrated as part of other apps?
    • Ad network integration. Will the ad network SDK display ads as intended?
    • Mediation setup. Are the ad units properly targeted on MoPub?

    To achieve these goals, we created the UniAdsTester test application that integrates the UniAds dependency as a Developer Pod. This is a special mode where you specify the path to the Podspec in the Podfile. In our case, UniAdsTester lives in the same repo as UniAds.podspec, where it is developed and maintained. Every ad network has a designated MoPub ad unit, and we set up ad networks on MoPub to target each of them. 

    The app:

    • shows the version of the ad network SDK we are integrating 
    • shows the number of successful and failed attempts for each ad unit
    • allows selecting a subset of the ad networks to test. For example, you can switch off all networks but one, or simply switch on the networks relevant for a particular production app.

    The UI is kinda creepy, but this was a fast app to create:UniAds: A Manageable Native iOS Ad Network Mediation - photo 4

    What is ad network mediation maintenance

    The key maintenance task is to keep the SDKs up to date. Unfortunately, we haven’t fully automated checks for the new versions yet, so this is a semi-manual process. We must open the link to every SDK, compare the fresh version with the current one, and download the new SDK if the version has changed. 

    Updates / New Integrations

    Once the SDK or adapter code is updated in the UniAds repo, or a new SDK is integrated and added to the mix, we increment the version of the UniAds.podspec and publish it to our internal Spec repo. Then, all our apps that depend on UniAds simply run a ‘pod update,’ giving them an updated dependency. This is what makes the setup really shine. Without it, we would’ve duplicated a lot of work: updating the SDK and adapters in each of our apps. With UniAds, it is simple: modify once – update automatically, everywhere. 

    Book a call with us to discuss your monetization architecture.

    Book a strategy session

    Get actionable insights for your product

      Success!

      We’ll reach out to schedule a call