Skip to main content

LiftoffAds iOS SDK

This repository describes the LiftoffAds iOS SDK technical integration. For help configuring and testing ad units or setting up reporting, please contact your Liftoff POC.

For any other questions, please email sdk@liftoff.io.

Overview​

Latest Releases​

Supported Devices​

  • iPhone
  • iPad

Supported Ad Sizes​

  • 320x480 (iPhone portrait interstitial)
  • 480x320 (iPhone landscape interstitial)
  • 768x1024 (iPad portrait interstitial)
  • 1024x768 (iPad landscape interstitial)
  • 320x50 (iPhone banner)
  • 728x90 (iPad banner)
  • 300x250 (medium rectangle)
  • 0x0 (native)

Supported Ad Types​

  • HTML and HTML video
  • VAST video
  • Rewarded
  • Native

Development Requirements​

The LiftoffAds display SDK is written in Swift, compiled with the Swift 5.3 compiler, and distributed as a binary xcframework. Mediation adapter SDKs provided by Liftoff are written in Objective-C and distributed as static libraries.

To integrate the latest version of the LiftoffAds display SDK, you will need at minimum:

  • macOS >= 11 (Big Sur)
  • XCode >= 12.5

SKAdNetwork​

LiftoffAds uses SKAdNetwork in iOS 14+. To enable SKAdNetwork for the LiftoffAds network, add the following to your app's plist:

<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7UG5ZH24HU.skadnetwork</string>
</dict>
</array>

NOTE: SKAdNetwork is likely to be required for the LiftoffAds network in the near future. When this requirement is added, your fill rate may drop substantially if you do not include the plist entry above.

Integrating the SDK​

If you use ironSource mediation, skip this section and follow ironSource's Liftoff Integration Guide.

Downloading the SDK​

You can download the SDK through CocoaPods or directly.

CocoaPods​

Only CocoaPods versions >= 1.10 are supported since the SDK is packaged as an xcframework.

The easiest way to add the LiftoffAds SDK to your project is via CocoaPods.

Include LiftoffAds as a dependency in your PodFile:

source "https://github.com/CocoaPods/Specs.git"

target "MyApp" do
pod "LiftoffAds"
pod "LiftoffMoPubAdapter" # Only if you are using MoPub mediation.
end

Direct Download​

If you aren't using CocoaPods as described above, you can download the SDK and manually add it to your project:

  1. Download and unzip the LiftoffAds SDK.
  2. Add LiftoffAds.xcframework to your app's project.
  3. In General > Frameworks, Libraries, and Embedded Content, select Embed & Sign for LiftoffAds.xcframework.

Only if you are using MoPub mediation, download the Liftoff MoPub Adapter SDK and add it to your project:

  1. Download and unzip the Liftoff MoPub Adapter SDK.
  2. In General > Frameworks, Libraries, and Embedded Content, select Do Not Embed for LiftoffMoPubAdapter.xcframework.
  3. In Build Settings, add -ObjC to Other Linker Flags for your build target.

Code Changes​

We currently support MoPub mediation and self-mediated setups. If you are using a self-mediated setup, skip the section below and continue with Self Mediation.

MoPub Mediation​

Only MoPub SDK versions >= 5.13 are supported. The latest Liftoff MoPub adapter requires MoPub SDK >= 5.16.

LiftoffAds can be added as a MoPub custom SDK network.

Instructions for requesting and displaying ads through MoPub can be found in the MoPub documentation.

The following code samples may be used as reference for initializing the LiftoffAds iOS SDK through MoPub. Adjust the logic as necessary to meet the requirements of your app.

Bridging-Header.h
#if __has_include("LiftoffMoPubAdapter.h")
#import <LiftoffMoPubAdapter.h>
#else
#import <LiftoffMoPubAdapter/LiftoffMoPubAdapter.h>
#endif
AppDelegate.swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let sdkConfig = MPMoPubConfiguration(adUnitIdForAppInitialization: "MOPUB_AD_UNIT_ID")

// BEGIN: Required for Liftoff custom SDK network.
sdkConfig.additionalNetworks = [LiftoffAdapterConfiguration.self]
sdkConfig.setNetwork(
// Contact your Liftoff POC to retrieve your API key. Define this constant
// elsewhere or replace with a hardcoded string.
["apiKey": LIFTOFF_API_KEY],
forMediationAdapter: "LiftoffAdapterConfiguration"
)
// END

MoPub.sharedInstance().initializeSdk(with: sdkConfig)

return true
}

// Native Ads

func setUpNativeAds() {
// Liftoff native ad renderer
let liftoffConfig = LiftoffNativeAdRenderer.rendererConfiguration(with: settings)

// Required if manually integrating with MPNativeAdRequest.
let adRequest = MPNativeAdRequest(
adUnitIdentifier: "MOPUB_AD_UNIT_ID",
rendererConfigurations: [liftoffConfig, ...]
)

// Required if integrating with MPTableViewAdPlacer or MPCollectionViewAdPlacer.
let placer = MPTableViewAdPlacer(
// ...
rendererConfigurations: [liftoffConfig, ...]
)

// ...
}

// ...
}

Self Mediation​

The following code samples may be used as reference for requesting and displaying ads. Adjust the logic as necessary to meet the requirements of your app.

AppDelegate.swift
import LiftoffAds

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Supported log levels: none, info, debug, error.
Liftoff.logLevel = .error
// Contact your Liftoff POC to retrieve your API key. Define this constant
// elsewhere or replace with a hardcoded string.
Liftoff.initWithAPIKey(LIFTOFF_API_KEY)

print("Initialized LiftoffAds SDK \(Liftoff.sdkVersion)")

return true
}

// ...
}
ViewController.swift
import LiftoffAds

class ViewController: UIViewController, LOInterstitialDelegate, LOBannerDelegate, LONativeDelegate {
var loInterstitial: LOInterstitial!
var loBanner: LOBanner!
var loNative: LONative!
var nativeView: CustomNativeView

override func viewDidLoad() {
super.viewDidLoad()

// Contact your Liftoff POC to retrieve your ad unit IDs.
// NOTE: Liftoff interstitial, banner, and native objects cannot be reused
// to request multiple ads. You must initialize a new object for each ad
// request.

self.loInterstitial = Liftoff.initInterstitialAdUnit(for: LIFTOFF_INTERSTITIAL_AD_UNIT)
self.loInterstitial.delegate = self
self.loInterstitial.requestAd()

// The size argument may be any CGSize, but we recommend choosing from a
// preset list of sizes from LOConstants (a 0 indicates a flexible
// dimension):
// phoneBanner = CGSize(width: 320, height: 50)
// phoneBannerFlexWidth = CGSize(width: 0, height: 50)
// tabletBanner = CGSize(width: 728, height: 90)
// tabletBannerFlexWidth = CGSize(width: 0, height: 90)
// mediumRectangle = CGSize(width: 300, height: 250)
// mediumRectangleFlexWidth = CGSize(width: 0, height: 250)
// flexAll = CGSize.zero
self.loBanner = Liftoff.initBannerAdUnit(for: LIFTOFF_BANNER_AD_UNIT, size: LOConstants.phoneBanner)
self.loBanner.delegate = self
self.loBanner.requestAd()

self.loNative = Liftoff.initNativeAdUnit(for: LIFTOFF_NATIVE_AD_UNIT)
// self.nativeView must implement the LONativeViewAdapter protocol. See
// below for an example.
self.loNative.viewAdapter = self.nativeView
self.loNative.delegate = self
self.loNative.requestAd()
}


// MARK: LOInterstitialDelegate implementation

// Called when the interstitial ad request is successfully filled.
func loInterstitialDidLoad(_ interstitial: LOInterstitial) {
// This will display the interstitial immediately after the ad request is
// filled.
interstitial.showAd(with: self)

// To instead display the interstitial at an appropriate time as determined
// by your app UX:
// if self.loInterstitial.ready {
// self.loInterstitial.showAd(with: self)
// }
}

// Called when the interstitial ad request cannot be filled.
func loInterstitialDidFailToLoad(_ interstitial: LOInterstitial) {}

// Called when the interstitial ad fails during display.
func loInterstitialDidFailToDisplay(_ interstitial: LOInterstitial) {}

// Called before the interstitial view controller is presented.
func loInterstitialWillShow(_ interstitial: LOInterstitial) {}

// Called after the interstitial view controller is presented.
func loInterstitialDidShow(_ interstitial: LOInterstitial) {}

// Called before the interstitial view controller is hidden.
func loInterstitialWillHide(_ interstitial: LOInterstitial) {}

// Called after the interstitial view controller is hidden.
func loInterstitialDidHide(_ interstitial: LOInterstitial) {}

// Called when the interstitial becomes visible to the user.
func loInterstitialImpressionDidTrigger(_ interstitial: LOInterstitial) {}

// Called when the user will be directed to an external destination.
func loInterstitialClickDidTrigger(_ interstitial: LOInterstitial) {}

// Called when the user has earned a reward by watching a rewarded ad.
func loInterstitialWillRewardUser(_ interstitial: LOInterstitial) {}


// MARK: LOBannerDelegate implementation

// Called when the banner ad request is successfully filled. The view argument
// is the banner's UIView.
func loBannerDidLoad(_ banner: LOBanner, view: UIView) {
self.view.addSubview(view)
}

// Called when the banner ad request cannot be filled.
func loBannerDidFailToLoad(_ banner: LOBanner) {}

// Called when the banner ad fails during display.
func loBannerDidFailToDisplay(_ banner: LOBanner) {}

// Called when the banner becomes visible to the user.
func loBannerImpressionDidTrigger(_ banner: LOBanner) {}

// Called when the user will be directed to an external destination.
func loBannerClickDidTrigger(_ banner: LOBanner) {}

// Implementing this by returning a root view controller allows banners to
// present a StoreKit modal for app installs, which may improve conversion
// rates and your eCPM.
func loBannerViewControllerForPresentingModalView(_ banner: LOBanner) -> UIViewController? {
return self
}

// Called when a modal view controller will be displayed after a user click.
func loBannerModalWillShow(_ banner: LOBanner) {}

// Called when a modal view controller is displayed after a user click.
func loBannerModalDidShow(_ banner: LOBanner) {}

// Called when a modal view controller will be dismissed.
func loBannerModalWillHide(_ banner: LOBanner) {}

// Called when a modal view controller is dismissed.
func loBannerModalDidHide(_ banner: LOBanner) {}

// Called when the user will be directed to an external destination.
func loBannerWillLeaveApplication(_ banner: LOBanner)


// MARK: LONativeDelegate implementation

// Called when the native ad request is successful.
func loNativeDidLoad(_ native: LONative) {
self.loNative.renderAd()
self.view.addSubview(self.nativeView)
// If you want to control how the individual UI views are rendered, call the
// populate(adapter) method to fetch the native ad contents (text/URLs) and
// the prepare(viewAdapter) method to register impression/click handlers.
// self.loNative.populate(adapter);
// self.loNative.prepare(viewAdapter);
}

// Called when the native ad request cannot be filled.
func loNativeDidFailToLoad(_ native: LONative) {}

// Called when the native ad fails during display.
func loNativeDidFailToDisplay(_ native: LONative) {}

// Called when the native view becomes visible to the user.
func loNativeImpressionDidTrigger(_ native: LONative) {}

// Called when the user will be directed to an external destination.
func loNativeClickDidTrigger(_ native: LONative) {}

// Implementing this by returning a root view controller allows native ads to
// present a StoreKit modal for app installs, which may improve conversion
// rates and your eCPM.
func loNativeViewControllerForPresentingModalView(_ native: LONative) -> UIViewController? {
return self
}

// Called when a modal view controller will be displayed after a user click.
func loNativeModalWillShow(_ native: LONative) {}

// Called when a modal view controller is displayed after a user click.
func loNativeModalDidShow(_ native: LONative) {}

// Called when a modal view controller will be dismissed.
func loNativeModalWillHide(_ native: LONative) {}

// Called when a modal view controller is dismissed.
func loNativeModalDidHide(_ native: LONative) {}

// Called when the user will be directed to an external destination.
func loNativeWillLeaveApplication(_ native: LONative) {}
}
CustomNativeView.swift
import LiftoffAds

// Sample native ad view
class CustomNativeView: UIView, LONativeViewAdapter {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var descriptionLabel: UILabel!
@IBOutlet var ctaLabel: UILabel!
@IBOutlet var iconImage: UIImageView!
@IBOutlet var mainImage: UIImageView!


// MARK: LONativeViewAdapter implementation

func getLONativeMainImageView() -> UIImageView {
self.mainImage
}

func getLONativeIconImageView() -> UIImageView {
self.iconImage
}

func getLONativeTitleTextLabel() -> UILabel {
self.titleLabel
}

func getLONativeDescriptionTextLabel() -> UILabel {
self.descriptionLabel
}

func getLONativeCTATextLabel() -> UILabel {
self.ctaLabel
}

// ...
}

LiftoffAds complies with the EU's General Data Protection Regulation (GDPR) and the California Consumer Privacy Act (CCPA). However, LiftoffAds does not currently manage its own consent mechanism, so you will be required to pass user consent information to our SDK. The following code samples can be used as reference:

AppDelegate.swift
LOPrivacySettings.shared.setIsGDPRApplicable(true)
LOPrivacySettings.shared.setHasUserConsent(true)
LOPrivacySettings.shared.setIsAgeRestrictedUser(true)

Test Ad Units​

Use the following ad unit IDs to display a LiftoffAds test creative and verify successful integration.

Ad Unit IDSizeType
liftoff-banner-mrect-testBanner / MRECTVAST video, HTML video
liftoff-interstitial-video-testInterstitialVAST video
liftoff-interstitial-html-testInterstitialHTML video
liftoff-rewarded-video-testRewarded InterstitialVAST video
liftoff-native-testNativeNative

Creating a MoPub Custom SDK Network​

You may skip this section if you are not using MoPub mediation.

You will need to create a new custom SDK network in the MoPub web portal for the Liftoff ad network.

  1. Create a new custom SDK network for Liftoff in MoPub Networks.
  2. Create a new order for Liftoff in MoPub Orders.
  3. Create line items for your Liftoff ad units. Contact your Liftoff POC to set up ad units and retrieve your ad unit IDs.

The screenshots below show example configurations for Liftoff banner/medium rectangle, standard interstitial, rewarded interstitial, and native line items.

Both banner and mrect ads use the same custom event class.

Custom event class: LiftoffBannerCustomEvent

Custom event data: {"adUnitID": "LIFTOFF_BANNER_AD_UNIT_ID"}

Interstitial​

Custom event class: LiftoffInterstitialCustomEvent

Custom event data: {"adUnitID": "LIFTOFF_INTERSTITIAL_AD_UNIT_ID"}

Rewarded Interstitial​

Custom event class: LiftoffRewardedInterstitialCustomEvent

Custom event data: {"adUnitID": "LIFTOFF_REWARDED_INTERSTITIAL_AD_UNIT_ID"}

Native​

Custom event class: LiftoffNativeCustomEvent

Custom event data: {"adUnitID": "LIFTOFF_NATIVE_AD_UNIT_ID"}

COPPA​

LiftoffAds does not serve end users who fall under the restrictions of the Children’s Online Privacy Protection Act (COPPA), specifically age 12 years and younger. If you collect information that indicates a user falls under this category, you must not use the LiftoffAds SDK for the user's sessions.

Troubleshooting​

Set the log level to debug before troubleshooting:

Liftoff.logLevel = .debug

Available in 1.8.1+, observe the logs in the Console app using message:LiftoffAds as a filter along with your app's name filter.

For older versions, use the Xcode console to find messages using LiftoffAds as a filter.

Common integration issues:

  • "No API key provided": Missing API key. Verify that you've included the proper initialization code (see above).
  • "Error authentication: Check API key": Incorrect API key. Check for any typos in your API key.
  • "Unable to fetch ad unit: <PROVIDED_AD_UNIT_ID>": Could not fill ad request. Check ad unit ID for typos.

Reporting​

Reporting is available via programmatic API or scheduled emails. To receive scheduled email reports, contact your Liftoff POC with your desired recipient email addresses. By default, you will receive daily and monthly reports. The columns below are included; for further customization, contact your Liftoff POC.

  • Date
  • OS
  • Bundle
  • Ad Unit
  • Ad Unit ID
  • Country
  • Rewarded
  • Size
  • Requests
  • Fills
  • Fill Rate
  • Impressions
  • Clicks
  • CTR
  • Revenue
  • eCPM