RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/App Dev
App Dev/2026-05-24Advanced

Adding AppLovin MAX to a Rork-Generated iOS Project — A Field Note on Init Order, ATT Consent, and eCPM A/B Testing

A field note from an indie developer on layering AppLovin MAX on top of a Rork-generated iOS app: SDK initialization order, ATT and MAX consent flag sync, and a minimal A/B setup to compare eCPM against AdMob-only.

Rork515AppLovin MAXAdMob70iOS109ATT9eCPM4Mediation7

Premium Article

I am Hirokawa, an indie developer who has been shipping apps as a personal developer since 2014. I recently spent a couple of weeks layering AppLovin MAX on top of an iOS app whose scaffold came out of Rork, and the work turned out to be more delicate than I expected. After years of running AdMob solo across the wallpaper apps that together have crossed 50 million downloads, I rediscovered how easily a single misplaced initialization call can either silence the first banner at launch or quietly miswire the consent state behind the ATT dialog.

Rork is excellent at giving you a working skeleton fast, but the monetization layer is still on you to assemble. This note is the implementation memo I wish I had on hand when I started: it covers what worked when slotting AppLovin MAX into a Rork-generated iOS target, with the goal of running it alongside AdMob through mediation rather than swapping AdMob out entirely.

Why I moved from AdMob-only to running MAX in parallel

The trigger was a stretch of days during the most recent Beautiful HD Wallpapers update where AdMob banner and app-open eCPM hit a clear regional ceiling. Between mid-April and early May, U.S. and Indonesia eCPM each dropped roughly 18% and 22% week over week, while fill rate stayed above 95%. Revenue was sliding without an impression problem, which is exactly when it becomes worth widening the mediation denominator.

Wiring AppLovin MAX in via AdMob mediation lets me keep the GoogleMobileAds call sites essentially untouched. The Rork output here is React Native based, so I added a thin native bridge on the iOS side and contained the entire MAX integration in native code. The JavaScript layer still talks to AdMob; only the iOS target gained an additional SDK and consent path.

In practice, when running two ad SDKs in parallel, the time sink is not adding lines of code. It is keeping the initialization order and consent flags in sync. This note focuses on that.

SDK initialization order with SwiftPM

To add AppLovin MAX to the iOS target via SwiftPM, declare the package dependency on https://github.com/AppLovin/AppLovin-MAX-SDK-iOS in Xcode's Package Dependencies. If you are still migrating Firebase from CocoaPods to SPM at the same time, finish the Firebase SPM migration first to avoid Package.resolved fighting with Podfile.lock. I keep the Firebase migration steps in an internal doc and only add the AppLovin MAX dependency after the SPM-only state is stable.

The launch sequence I now use is:

  1. Inside application(_:didFinishLaunchingWithOptions:), call FirebaseApp.configure() first.
  2. Defer the ATT prompt to applicationDidBecomeActive(_:) rather than asking at launch.
  3. After ATT resolves, call ALSdk.shared().initialize(with: config).
  4. From the AppLovin init completion callback, call GADMobileAds.sharedInstance().start(completionHandler:).
  5. Only after step 4 completes, post an "ads ready" event to the React Native side.

The point is "never call GADMobileAds.start before ATT resolves." If you do, AdMob direct campaigns may lock into a non-IDFA-aware targeting state that does not fully recover until the next process launch.

import AppTrackingTransparency
import AppLovinSDK
import GoogleMobileAds
import FirebaseCore
 
final class AdsBootstrap {
    static let shared = AdsBootstrap()
    private(set) var isReady = false
    private var initInFlight = false
 
    func configureOnLaunch() {
        FirebaseApp.configure()
    }
 
    func startAfterActive() {
        guard !isReady, !initInFlight else { return }
        initInFlight = true
        ATTrackingManager.requestTrackingAuthorization { [weak self] status in
            DispatchQueue.main.async {
                self?.bootstrapMax(attStatus: status)
            }
        }
    }
 
    private func bootstrapMax(attStatus: ATTrackingManager.AuthorizationStatus) {
        let config = ALSdkInitializationConfiguration(sdkKey: AppEnv.applovinSdkKey) { builder in
            builder.mediationProvider = ALMediationProviderMAX
            builder.testDeviceAdvertisingIdentifiers = AppEnv.testDeviceIDFAs
        }
        ALSdk.shared().initialize(with: config) { [weak self] _ in
            self?.bootstrapAdMob(attStatus: attStatus)
        }
    }
 
    private func bootstrapAdMob(attStatus: ATTrackingManager.AuthorizationStatus) {
        GADMobileAds.sharedInstance().start { [weak self] _ in
            self?.isReady = true
            self?.initInFlight = false
            NotificationCenter.default.post(name: .adsBootstrapReady, object: nil, userInfo: [
                "att": attStatus.rawValue,
            ])
        }
    }
}
 
extension Notification.Name {
    static let adsBootstrapReady = Notification.Name("AdsBootstrapReady")
}

The React Native side subscribes to this AdsBootstrapReady notification through a native module and exposes a useAdsReady() hook to JavaScript. Once your call sites gate on a single boolean, the launch-time race conditions stop reproducing in testing.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A practical sequence for wiring AppLovin MAX into a Rork-scaffolded iOS app via SwiftPM, without touching the React Native ad call sites
How to align the ATT prompt, MAX privacy flags, and AdMob initialization so the order does not silently degrade eCPM
A minimal Remote Config + Crashlytics A/B setup that lets a solo developer compare AdMob-only vs AdMob + AppLovin MAX in two weeks
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Business2026-05-21
Putting AdMob Bidding into Production for a Rork App — Five Networks Bidding in Parallel, eCPM Trends, and Daily Operations
I moved the AdMob mediation layer of my Rork-generated apps from waterfall to bidding, with five ad networks bidding in parallel. Here are my real-world numbers after three weeks of production, the SDK pitfalls, and how I delegate daily monitoring to Claude in Chrome.
Dev Tools2026-05-07
Rork iOS App: Why Your App Tracking Transparency Prompt Never Shows Up — and How to Fix It
Three real causes the ATT (App Tracking Transparency) dialog never appears in Rork-generated iOS apps — Info.plist, call timing, and AdMob init order — with working code and on-device verification steps.
Dev Tools2026-04-21
Lifting ATT Opt-in Rates in Rork Apps — Turning iOS Tracking Consent into Real Ad Revenue
Implementation patterns that raise App Tracking Transparency (ATT) opt-in rates in Rork-built iOS apps, wired to your AdMob revenue. Covers purpose string copy, prompt timing, a pre-permission screen, cohort-level measurement, UMP (GDPR) ordering, and a dynamic non-personalized ads fallback.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →