Skip to content

iOS Managed MAX

OriviaMaxSdk is a high-level wrapper over AppLovin MAX that manages the full ad lifecycle — loading, retry on failure — so you don't have to wire MAX callbacks yourself.

Import Dependencies

Add the Orivia specs repository, then the core SDK and MAX mediation pod, to your Podfile:

source 'https://github.com/orivia-ai/orivia-specs.git'
source 'https://cdn.cocoapods.org/'

pod 'OriviaMonetization', '1.18.0'
pod 'OriviaMonetizationMax', '1.18.0'

Run pod install.

Import Package

Make sure the Orivia SDK MAX mediation module is available in your files:

import OriviaMonetization
import OriviaMonetizationMax

Setup

1. Define SDK Keys & Ad Unit IDs

Declare your MAX SDK key, Orivia publisher ID, and ad unit IDs:

private let maxSdkKey = "YOUR_MAX_SDK_KEY"
private let oriviaPublisherId = "YOUR_ORIVIA_PUBLISHER_ID"

private let interstitialAdUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID"
private let rewardedAdUnitId = "YOUR_REWARDED_AD_UNIT_ID"

2. Initialize

Subscribe to callbacks, then call initialize:

func start() {
    // For debug purposes only.
    OriviaMaxSdk.shared.setLoggingEnabled(true)

    OriviaMaxSdk.shared.onInterstitialLoaded = {
        // Ad is ready to show. isInterstitialReady() == true.
    }
    OriviaMaxSdk.shared.onRewardedLoaded = {
        // Ad is ready to show. isRewardedReady() == true.
    }

    OriviaMaxSdk.shared.initialize(
        sdkKey: maxSdkKey,
        publisherId: oriviaPublisherId,
        defaultInterstitialAdUnitId: interstitialAdUnitId,
        defaultRewardedAdUnitId: rewardedAdUnitId
    ) {
        // Both Orivia SDK and MAX are ready — safe to start loading
        OriviaMaxSdk.shared.loadInterstitial()
        OriviaMaxSdk.shared.loadRewarded()
    }
}

initialize initializes Orivia SDK first, fetches remote config, then initializes AppLovin MAX. Both must complete before ads can be loaded.

initialize also accepts a defaultBannerAdUnitId. OriviaMaxSdk does not load or show banners itself — manage banners directly via the raw MAX API — but passing it in lets the ad unit rotation logic account for banner placements too.

Important

You may register a raw MAX delegate via addInterstitialAdDelegate / addRewardedAdDelegate directly for informational purposes (e.g., analytics), but all ad display operations must go through OriviaMaxSdk.

3. Handle Initialization Completion

OriviaMaxSdk.shared.initialize(
    sdkKey: maxSdkKey,
    publisherId: oriviaPublisherId,
    defaultInterstitialAdUnitId: interstitialAdUnitId,
    defaultRewardedAdUnitId: rewardedAdUnitId
) {
    // Both Orivia SDK and MAX are ready — safe to start loading
    OriviaMaxSdk.shared.loadInterstitial()
    OriviaMaxSdk.shared.loadRewarded()
}

Info

The completion closure is called after both Orivia SDK config and AppLovin MAX have initialized successfully. It is the recommended place to trigger the first ad load. It fires on success only — a failed OriviaSdk initialization is only logged internally.

Loading Ads

OriviaMaxSdk.shared.loadInterstitial()
OriviaMaxSdk.shared.loadRewarded()

Behavior:

  • If an ad is already ready — fires onInterstitialLoaded / onRewardedLoaded immediately and returns.
  • If a load is already in progress — skips silently.

After a failed load, OriviaMaxSdk retries automatically. You do not need to schedule retries yourself.

Callbacks

Subscribe before calling initialize to avoid missing the first event:

OriviaMaxSdk.shared.onInterstitialLoaded = {
    // Ad is ready to show. isInterstitialReady() == true.
}

OriviaMaxSdk.shared.onRewardedLoaded = {
    // Ad is ready to show. isRewardedReady() == true.
}

The callback fires only when the full load cycle is complete. It is safe to call showInterstitial / showRewarded directly from the callback.

Observing Raw MAX Events

iOS's AppLovin MAX SDK has no global callback bus (unlike Unity's static MaxSdkCallbacks.*) — OriviaMaxSdk owns the ad instance and its delegate internally, so this is the only way to see raw ad events (display, hide, click, load failure, display failure, revenue) for your own analytics:

final class AdEventsObserver: NSObject, MAAdDelegate, MAAdRevenueDelegate, MARewardedAdDelegate {
    func didLoad(_ ad: MAAd) { /* ... */ }
    func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { /* ... */ }
    func didDisplay(_ ad: MAAd) { /* ... */ }
    func didHide(_ ad: MAAd) { /* ... */ }
    func didClick(_ ad: MAAd) { /* ... */ }
    func didFail(toDisplay ad: MAAd, withError error: MAError) { /* ... */ }
    func didRewardUser(for ad: MAAd, with reward: MAReward) { /* ... */ }
    func didPayRevenue(for ad: MAAd) { /* ... */ }
}

// OriviaMaxSdk holds the delegate weakly, so keep a strong reference to it yourself
// for as long as you want to keep observing events.
let observer = AdEventsObserver()
OriviaMaxSdk.shared.addInterstitialAdDelegate(observer)
OriviaMaxSdk.shared.addInterstitialAdRevenueDelegate(observer)
OriviaMaxSdk.shared.addRewardedAdDelegate(observer)
OriviaMaxSdk.shared.addRewardedAdRevenueDelegate(observer)

Unregister with the matching remove* method (e.g. removeInterstitialAdDelegate) once you no longer need the events — for example in deinit. Has no effect when dataCollectionOnly == true, since you already own the raw ad instance and set your own delegate on it directly.

Showing Ads

placement and customData are passed directly to AppLovin MAX and behave identically to MAInterstitialAd.show / MARewardedAd.show.

OriviaMaxSdk.shared.showInterstitial()                          // no placement
OriviaMaxSdk.shared.showInterstitial(placement: "game_over")    // with placement
OriviaMaxSdk.shared.showInterstitial(placement: "level_end", customData: "my_data") // with placement + custom data

OriviaMaxSdk.shared.showRewarded()
OriviaMaxSdk.shared.showRewarded(placement: "extra_life")
OriviaMaxSdk.shared.showRewarded(placement: "extra_life", customData: "my_data") // with placement + custom data

Important

show logs a warning and returns early if no ad is ready. Always check isInterstitialReady() / isRewardedReady() before showing, or load first and show from the loaded callback.

Checking Readiness

if OriviaMaxSdk.shared.isInterstitialReady() {
    OriviaMaxSdk.shared.showInterstitial(placement: "placement")
}

if OriviaMaxSdk.shared.isRewardedReady() {
    OriviaMaxSdk.shared.showRewarded(placement: "placement")
}

Data Collection Only Mode

In this mode OriviaMaxSdk only tracks events — it does not create, load, or show any MAX ad instance itself. The publisher initializes AppLovin MAX, creates and owns the raw MAInterstitialAd / MARewardedAd instances, and drives loading and display directly.

Pass dataCollectionOnly: true to initialize, and report every load/failure/revenue event back to Orivia by calling onAdLoaded, onAdLoadFailed, and onAdRevenuePaid from your own delegate — the same contract OriviaMaxHelper already exposes, mirrored here for a single entry point:

OriviaMaxSdk.shared.initialize(
    sdkKey: maxSdkKey, // unused in this mode, but still required
    publisherId: oriviaPublisherId,
    defaultInterstitialAdUnitId: interstitialAdUnitId,
    defaultRewardedAdUnitId: rewardedAdUnitId,
    dataCollectionOnly: true
) {
    // Orivia config is ready — MAX init is not awaited
}

// The publisher initializes MAX and loads/shows ads as usual:
final class InterstitialDelegate: NSObject, MAAdDelegate, MAAdRevenueDelegate {
    func didLoad(_ ad: MAAd) {
        OriviaMaxSdk.shared.onAdLoaded(ad)
    }

    func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
        OriviaMaxSdk.shared.onAdLoadFailed(adType: .interstitial, adUnitId: adUnitIdentifier)
    }

    func didPayRevenue(for ad: MAAd) {
        OriviaMaxSdk.shared.onAdRevenuePaid(ad)
    }

    // ... other MAAdDelegate callbacks
}

let interstitialAd = MAInterstitialAd(adUnitIdentifier: interstitialAdUnitId)
let delegate = InterstitialDelegate()
interstitialAd.delegate = delegate
interstitialAd.revenueDelegate = delegate
interstitialAd.load()

loadInterstitial, showInterstitial, loadRewarded, and showRewarded are disabled in this mode and log a warning if called. isInterstitialReady / isRewardedReady always return false — track readiness yourself. addInterstitialAdDelegate and related registration methods have no effect in this mode, since you already own the raw ad instance and its delegate.

Client Parameters

To pass client parameters to the server:

let nested = ValueMap.Builder().put("nested", "value").build()
let clientParams = ValueMap.Builder()
    .put("str", "value")
    .put("int", 12)
    .put("float", 1.3)
    .put("bool", true)
    .put("nested", nested)
    .build()
OriviaSdk.shared.setClientParams(clientParams)

If the parameters should be passed in the init request, call setClientParams before OriviaMaxSdk.initialize.

Important

Passing nil to this method has no effect. To clear the parameters, pass an empty ValueMap.

Logging

Turn on internal logs for debugging:

OriviaMaxSdk.shared.setLoggingEnabled(true)

Logs appear in the Xcode Console.

Privacy

To pass GDPR Applies there are 2 options.

Pass it through CMP IABTCF_gdprApplies property or using SDK method:

OriviaSdk.shared.setGdprApplies(true) // or false, or nil for unknown

To pass COPPA:

OriviaSdk.shared.setCoppa(true) // or false, or nil for unknown

Null values reset properties.

Full Example

import OriviaMonetization
import OriviaMonetizationMax
import AppLovinSDK

final class AdsManager: NSObject, ObservableObject {

    override init() {
        super.init()

        // For debug purposes only.
        OriviaMaxSdk.shared.setLoggingEnabled(true)

        OriviaMaxSdk.shared.onInterstitialLoaded = {
            // Ad is ready — show it when appropriate
        }
        OriviaMaxSdk.shared.onRewardedLoaded = {
            // Ad is ready — show it when appropriate
        }

        OriviaMaxSdk.shared.initialize(
            sdkKey: "YOUR_MAX_SDK_KEY",
            publisherId: "YOUR_PUBLISHER_ID",
            defaultInterstitialAdUnitId: "YOUR_INTERSTITIAL_AD_UNIT_ID",
            defaultRewardedAdUnitId: "YOUR_REWARDED_AD_UNIT_ID"
        ) {
            OriviaMaxSdk.shared.loadInterstitial()
            OriviaMaxSdk.shared.loadRewarded()
        }
    }

    func showInterstitial() {
        if OriviaMaxSdk.shared.isInterstitialReady() {
            OriviaMaxSdk.shared.showInterstitial(placement: "my_placement")
        }
    }

    func showRewarded() {
        if OriviaMaxSdk.shared.isRewardedReady() {
            OriviaMaxSdk.shared.showRewarded(placement: "my_placement")
        }
    }
}