Liftoff Monetize

In this article, you will learn how to use Nimbus to request and render Liftoff Ads.

Integrating Nimbus with Liftoff Monetize requires an App ID.

How it works

The SDK will automatically inject the Vungle token and app id into the outbound request to Nimbus when using the NimbusAdManager. When the NimbusVungleRequestInterceptor is initialized it will fetch the Liftoff Monetize token in the background for use on future requests and install the NimbusVungleAdRenderer to render any wins from Liftoff Monetize.

Installation

Swift Package Manager

Following the steps defined in the integration section to install Nimbus using Swift Package Manager, include the package 'NimbusVungleKit' in the selected packages.

CocoaPods

  1. Add NimbusVungleKit subspec for the NimbusSDK declaration into your project’s Podfile. pod 'NimbusSDK', subspecs: ['NimbusKit', 'NimbusVungleKit']

  2. Run pod install

The Liftoff Monetize SDK will be automatically installed when using CocoaPods or Swift Package Manager

Configure the SDK to include Liftoff Monetize

Be sure Nimbus is initialized before continuing with the Liftoff integration.

Include the Liftoff Monetize interceptor and renderer.

let vungleInterceptor = NimbusVungleRequestInterceptor(
  appId: LocalConfigManager.shared.vungleAppId,
  delegate: self
)
NimbusAdManager.requestInterceptors = [vungleInterceptor]

Nimbus.shared.renderers = [.forNetwork("vungle"): NimbusVungleAdRenderer()]

To be notified when Liftoff Monetize finishes its initialization, your class must implement NimbusVungleRequestInterceptorDelegate. This can be used to monitor any errors.

extension YourClass: NimbusVungleRequestInterceptorDelegate {
    func didInitializeVungle(with error: Error?) {
        var message = "success"
        if let error {
            message = "error: \(error.localizedDescription)"
        }
        print("Nimbus: Vungle initialization finished with \(message)")
    }
}

Native Ads

Since Nimbus iOS SDK 2.18.0, NimbusVungleKit supports Liftoff native ads. Please follow this guide to integrate Liftoff native ads.

Prerequisites

1. Define your native ad view

A native ad view is a UIView that is responsible for the visual representation of a native Liftoff Monetize ad. Nimbus requires such view to conform to NimbusVungleNativeAdViewType protocol in order to pass Liftoff Monetize SDK everything it needs.

The protocol is defined as:

public protocol NimbusVungleNativeAdViewType: UIView {
    // Vungle media view, it must be an instance of VungleAdsSDK.MediaView
    var mediaView: MediaView { get set }

    // An icon view
    var iconImageView: UIImageView? { get set }
    
    // Array of views that trigger the ad click action, e.g. [ mediaView ]
    // would make only the mediaView clickable
    var clickableViews: [UIView]? { get }
}

If you want to get quickly started, feel free to use the native ad view snippet below, that already conforms to NimbusVungleNativeAdViewType protocol, or check out the public sample app where we showcase a native Liftoff ad.

final class NimbusVungleNativeAdView: UIView, NimbusVungleNativeAdViewType {

    /// Label used for title
    let titleLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 15)
        label.numberOfLines = 1
        label.textColor = .black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    /// Label used for rating
    let adStarRatingLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 12)
        label.numberOfLines = 1
        label.textColor = .black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    /// Label used for sponsor
    let sponsoredLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 12)
        label.textColor = .black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    /// Label used for body text
    let bodyTextLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 12)
        label.numberOfLines = 2
        label.textColor = .black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    /// Button used for call to action
    let callToActionButton: UIButton = {
        let button = UIButton()
        button.contentEdgeInsets = UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3)
        button.titleLabel?.font = .systemFont(ofSize: 12)
        button.titleLabel?.textColor = .white
        button.backgroundColor = .systemBlue
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    /// View used for media
    var mediaView: MediaView = {
        let mediaView = MediaView()
        mediaView.translatesAutoresizingMaskIntoConstraints = false
        return mediaView
    }()

    /// Image view used for icon
    var iconImageView: UIImageView? = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    /// All clickable views
    var clickableViews: [UIView]? { [mediaView, callToActionButton] }

    /// Spacing between components
    private let spacing: CGFloat = 5
    
    private let labelStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        return stackView
    }()

    /**
     Initializes a NimbusVungleNativeAdView instance
     
     - Parameters:
     - vungleNativeAd: Vungle native ad
     - dimensions: Nimbus ad dimensions
     */
    init(_ vungleNativeAd: VungleNative) {
        super.init(frame: CGRect.zero)

        translatesAutoresizingMaskIntoConstraints = false
        
        backgroundColor = .white

        titleLabel.text = vungleNativeAd.title
        adStarRatingLabel.text = String(vungleNativeAd.adStarRating)
        sponsoredLabel.text = vungleNativeAd.sponsoredText
        bodyTextLabel.text = vungleNativeAd.bodyText
        callToActionButton.setTitle(vungleNativeAd.callToAction, for: .normal)
        iconImageView?.image = vungleNativeAd.iconImage

        setupViews()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupViews() {
        addSubview(iconImageView!)
        addSubview(titleLabel)
        addSubview(adStarRatingLabel)
        addSubview(sponsoredLabel)
        addSubview(mediaView)
        addSubview(callToActionButton)
        addSubview(bodyTextLabel)
        
        addSubview(labelStackView)
        
        labelStackView.addArrangedSubview(titleLabel)
        labelStackView.addArrangedSubview(adStarRatingLabel)
        labelStackView.addArrangedSubview(sponsoredLabel)
        
        mediaView.backgroundColor = .white

        NSLayoutConstraint.activate([
            iconImageView!.topAnchor.constraint(equalTo: topAnchor, constant: spacing),
            iconImageView!.leftAnchor.constraint(equalTo: leftAnchor, constant: spacing),
            iconImageView!.heightAnchor.constraint(equalToConstant: 48),
            iconImageView!.widthAnchor.constraint(equalToConstant: 48),
            iconImageView!.bottomAnchor.constraint(lessThanOrEqualTo: mediaView.topAnchor, constant: -spacing),

            labelStackView.topAnchor.constraint(equalTo: topAnchor, constant: spacing),
            labelStackView.rightAnchor.constraint(equalTo: rightAnchor, constant: -spacing),
            labelStackView.leftAnchor.constraint(equalTo: iconImageView!.rightAnchor, constant: spacing),
            labelStackView.heightAnchor.constraint(equalTo: iconImageView!.heightAnchor),

            mediaView.topAnchor.constraint(equalTo: labelStackView.bottomAnchor, constant: spacing),
            mediaView.leftAnchor.constraint(equalTo: leftAnchor),
            mediaView.rightAnchor.constraint(equalTo: rightAnchor),

            callToActionButton.topAnchor.constraint(greaterThanOrEqualTo: mediaView.bottomAnchor, constant: spacing * 2),
            callToActionButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -spacing),
            callToActionButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -(spacing * 2)),
            callToActionButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.5),

            bodyTextLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: spacing),
            bodyTextLabel.centerYAnchor.constraint(equalTo: callToActionButton.centerYAnchor)
        ])
    }
}

2. Set the adRenderer delegate

NimbusVungleAdRenderer has a new property named adRendererDelegate. It's required to implement the delegate to use native Liftoff ads.

The ad renderer delegate has only one method: customViewForRendering(...) which asks you to provide a native ad view that should be used for rendering.

Important: Do not at any point add the native ad view to the view hierarchy, our SDK does that later.

Complete Example

Let's take a look at the following code snippet of a UIViewController that can display a native ad.

import UIKit
import NimbusVungleKit
import VungleAdsSDK

final class VungleNativeAdViewController: UIViewController {
    private var adManager = NimbusAdManager()
    private var adController: AdController?
    private let nativeAdContentView = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        // Make sure Liftoff interceptor is set
        let renderer = NimbusVungleAdRenderer()
        
        // Notice we set the adRendererDelegate
        renderer.adRendererDelegate = self
        Nimbus.shared.renderers[.forNetwork("vungle")] = renderer
        
        setupContentView()
        
        adManager.delegate = self
        adManager.showAd(
            request: NimbusRequest.forNativeAd(position: "position"),
            container: nativeAdContentView,
            adPresentingViewController: self
        )
    }
    
    // We set the Auto Layout constraints of our container view
    func setupContentView() {
        nativeAdContentView.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(nativeAdContentView)
        
        NSLayoutConstraint.activate([
            nativeAdContentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            nativeAdContentView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            nativeAdContentView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            nativeAdContentView.widthAnchor.constraint(equalToConstant: 300),
            nativeAdContentView.heightAnchor.constraint(equalToConstant: 300)
        ])
    }
}

extension VungleNativeAdViewController: NimbusAdManagerDelegate {
    func didRenderAd(request: NimbusRequest, ad: NimbusAd, controller: AdController) {
        print("didRenderAd")
        adController = controller
    }
    
    func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
        print("didCompleteNimbusRequest")
    }
    
    func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
        print("didFailNimbusRequest: \(error.localizedDescription)")
    }
}

// Here we simply return the custom view we want to use to render
// the native ad. We don't add it to the view hierarchy, just instantiate it
// using the Liftoff native ad that the delegate provides us with.
extension VungleNativeAdViewController: NimbusVungleAdRendererDelegate {
    func customViewForRendering(container: UIView, nativeAd: VungleNative) -> NimbusVungleNativeAdViewType {
        NimbusVungleNativeAdView(nativeAd)
    }
}

Last updated