Skip to main content

iOS SDK Integration Guide

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"
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.

Code Changes​

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-html-testBanner / MRECTHTML
liftoff-banner-mrect-video-testBanner / MRECTVAST video
liftoff-interstitial-html-testInterstitialHTML
liftoff-interstitial-video-testInterstitialVAST video
liftoff-rewarded-video-testRewarded InterstitialVAST video
liftoff-native-testNativeNative

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