prebid / prebid-mobile-ios

Prebid Mobile SDK for iOS applications
Apache License 2.0
47 stars 92 forks source link

Design a new Demo App Architecture #705

Closed YuriyVelichkoPI closed 1 year ago

YuriyVelichkoPI commented 1 year ago

Motivation

Make integration examples convenient and self-descriptive.

Our goal is to introduce one file/controller for each integration case. The codebase of the integration case should be compact and commented. Users should focus only on the code related to the particular integration case during studying.

Objectives

OlenaPostindustria commented 1 year ago

IntegrationCase

struct IntegrationCase {

    let title: String 
    let integrationKind: IntegrationKind
    let adFormat: AdFormat
    let configurationClosure: () -> UIViewController
}

IntegrationKind

enum IntegrationKind: CustomStringConvertible, CaseIterable {

    case gamOriginal
    case gam
    case inApp
    case adMob
    case max

    var description: String {
        switch self {
        case .gamOriginal:
            return "GAM (Original API)"
        case .gam:
            return "GAM"
        case .inApp:
            return "In-App"
        case .adMob:
            return "AdMob"
        case .max:
            return "MAX"
        }
    }
}

AdFormat

enum AdFormat: CustomStringConvertible, CaseIterable {

    case displayBanner
    case videoBanner
    case nativeBanner
    case displayInterstitial
    case videoInterstitial
    case videoRewarded
    case videoInstream
    case native

    var description: String {
        switch self {
        case .displayBanner:
            return "Display Banner"
        case .videoBanner:
            return "Video Banner"
        case .nativeBanner:
            return "Native Banner"
        case .displayInterstitial:
            return "Display Interstitial"
        case .videoInterstitial:
            return "Video Interstitial"
        case .videoRewarded:
            return "Video Rewarded"
        case .videoInstream:
            return "Video In-stream"
        case .native:
            return "Native"
        }
    }
}

Integration case title template - [IntegrationKind] [AdFormat] [Size] [IntegrationKind] - GAM (Original API), GAM, In-App, AdMob, MAX [AdFormat] - "Display Banner", "Video Banner", "Native Banner", "Display Interstitial", "Video Interstitial", "Video Rewarded", "Video In-stream", "Native" [Size] - size of ad, f.e. 320x50

GAMOriginalAPIBannerDisplayViewController

import UIKit
import PrebidMobile
import GoogleMobileAds

fileprivate let storedResponseDisplayBanner = "response-prebid-banner-320-50"
fileprivate let storedImpDisplayBanner = "imp-prebid-banner-320-50"
fileprivate let gamAdUnitDisplayBannerOriginal = "/21808260008/prebid_demo_app_original_api_banner"

class GAMOriginalAPIBannerDisplayViewController: BannerBaseViewController, GADBannerViewDelegate {

    // Prebid
    private var adUnit: BannerAdUnit!

    // GAM
    private let gamRequest = GAMRequest()
    private var gamBanner: GAMBannerView!

    override func loadView() {
        super.loadView()

        Prebid.shared.storedAuctionResponse = storedResponseDisplayBanner
        createAd()
    }

    func createAd() {
        // Create a BannerAdUnit associated with a Prebid Server configuration ID and a banner size
        adUnit = BannerAdUnit(configId: storedImpDisplayBanner, size: adSize)
        // Create and setup banner parameters
        let parameters = BannerParameters()
        // Define any appropriate API Frameworks
        parameters.api = [Signals.Api.MRAID_2]
        adUnit.parameters = parameters
        // Set autorefresh interval
        adUnit.setAutoRefreshMillis(time: 30000)

        // Setup integration kind - GAM
        gamBanner = GAMBannerView(adSize: GADAdSizeFromCGSize(adSize))
        gamBanner.adUnitID = gamAdUnitDisplayBannerOriginal
        gamBanner.rootViewController = self
        gamBanner.delegate = self
        bannerView?.addSubview(gamBanner)

        // Trigger a call to Prebid Server to retrieve demand for this Prebid Mobile ad unit.
        adUnit.fetchDemand(adObject: gamRequest) { [weak self] resultCode in
            PrebidDemoLogger.shared.info("Prebid demand fetch for GAM \(resultCode.name())")
            // Load ad
            self?.gamBanner.load(self?.gamRequest)
        }
    }

    // MARK: - GADBannerViewDelegate

    func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
        AdViewUtils.findPrebidCreativeSize(bannerView, success: { size in
            guard let bannerView = bannerView as? GAMBannerView else { return }
            bannerView.resize(GADAdSizeFromCGSize(size))
        }, failure: { (error) in
            PrebidDemoLogger.shared.error("Error occuring during searching for Prebid creative size: \(error)")
        })
    }

    func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
        PrebidDemoLogger.shared.error("GAM did fail to receive ad with error: \(error)")
    }
}

Integration case view controller can be inherited from one of the base view controllers(f.e. BannerBaseViewController). Base view controllers provide default controls to show ad(f.e. banner view, loadAd button for interstitials etc).

IntegrationCaseManager is responsible for storing integration cases. All cases will be populated in table view.

struct IntegrationCaseManager {

    static var allCases: [IntegrationCase] = [
        IntegrationCase(
            title: "GAM (Original API) Display Banner 320x50",
            integrationKind: .gamOriginal,
            adFormat: .displayBanner,
            configurationClosure: {
                GAMOriginalAPIBannerDisplayViewController()
            }
        ),
    ]
}

Files hierarchy

image