Bros Delivery Hero) • 7 years of Experience with Android and Kotlin Multiplatform • Developer Community Organizer GDG Korea Android) LinkedIn Gmail linkedin.com/in/wisemuji [email protected]
- This talk is for those already using, or about to use KMP on iOS. - Weʼll skip the docs and focus on what broke and how we fixed it. - Better ideas? Let's discuss!
it can't go in commonMain UNUserNotificationCenter Delegate callbacks, not flows CLLocationManager Background-thread callbacks RemoteConfig Firebase) Async with no Kotlin SDK AppDelegate lifecycle No KMP equivalent CBCentralManager Bluetooth) Stateful native session AVAudioSession Singleton, app-wide config
Long = 0) private val state = MutableStateFlow(ViewState()) fun mainViewController(onFinish: () -> Unit): UIViewController { return ComposeUIViewController { // This subscribes to the StateFlow state. val viewState by state.collectAsStateWithLifecycle() if (viewState.requiredAppVersionCode > currentAppVersionCode) { ... } App() } } } // This is called from SwiftUI. fun updateRequiredAppVersionCode(code: Long) { state.value = state.value.copy(requiredAppVersionCode = code) }
Long = 0) private val state = MutableStateFlow(ViewState()) fun mainViewController(onFinish: () -> Unit): UIViewController { return ComposeUIViewController { // This subscribes to the StateFlow state. val viewState by state.collectAsStateWithLifecycle() if (viewState.requiredAppVersionCode > currentAppVersionCode) { ... } App() } } } // This is called from SwiftUI. fun updateRequiredAppVersionCode(code: Long) { state.value = state.value.copy(requiredAppVersionCode = code) }
Long = 0) private val state = MutableStateFlow(ViewState()) fun mainViewController(onFinish: () -> Unit): UIViewController { return ComposeUIViewController { // This subscribes to the StateFlow state. val viewState by state.collectAsStateWithLifecycle() if (viewState.requiredAppVersionCode > currentAppVersionCode) { ... } App() } } } // This is called from SwiftUI. fun updateRequiredAppVersionCode(code: Long) { state.value = state.value.copy(requiredAppVersionCode = code) }
Firebase Crashlytics SDK is a regular Gradle dependency. Direct import in androidMain. Firebase iOS SDK is Swift/ObjC. Kotlin/Native cannot import it in iosMain.
Log delegate → crash recorded Log delegate is null → crash reporting silently fails Delegate was injected & the function was called, But at the call site delegate was always null 🤔
use Firebase from Kotlin/Native Kotlin logger/iosMain/Log.ios.kt import swiftPMImport.logger.FIRCrashlytics actual fun recordException(t: Throwable) { FIRCrashlytics.crashlytics() .recordError(t.toNSError()) }
Experimental ⚠ Experimental status JetBrains is collecting feedback in KotlinLang #kmp-swift-package-manager Slack channel. Not ready for critical production paths yet. ⚙ isStatic = true recommended Dynamic Kotlin/Native frameworks may hit linker errors or runtime symbol collisions with SwiftPM imports. 🚧 Round-trip not supported yet If your KMP module uses SwiftPM import, you can't yet re-export that module as a Swift package. Ref: kotlinlang.org/docs/multiplatform/multiplatform-spm-import.html
Study 1: // Swift Int != Kotlin Long func updateRequiredAppVersionCode(code: Int64) { SharedViewControllers() .updateRequiredAppVersionCode(code: code) } Kotlin Swift Trap Long Int64 Swift Int ≠ Kotlin Long Int Int32 Swift Int is 64-bit! Long? NSNumber? Boxed, loses type info Throwable KotlinThrowable Not NSError!
1. Native State Observation StateFlow + ComposeUIViewController to bridge native events into shared Compose UI 2. Integrating Non-KMP SDKs One framework, one binary, one singleton IoC, framework export) 3. Dependency Management CocoaPods today, SwiftPM import tomorrow Kotlin 2.4.0 One Year In 100% Compose UI · 98.2% Kotlin KMP on iOS works in production. 🎉