Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Troubled Waters: Bridging platform-native SDKs with Kotlin Multiplatform

Troubled Waters: Bridging platform-native SDKs with Kotlin Multiplatform

Talking to native APIs from Kotlin Multiplatform (mostly) Mobile.

Kevin Galligan

June 02, 2022
Tweet

More Decks by Kevin Galligan

Other Decks in Technology

Transcript

  1. JNI

  2. Basic Topics • Tell Kotlin about the native code •

    Link native code into Kotlin Xcode Framework • API Design
  3. Interface Driven • 💰 Don’t need cinterop • 💰 No

    weird linking • 💰 No extra binary size • 🗑 Not easily testable • 🗑 Impractical for complex situations • 🗑 Bad for libraries
  4. interface KotlinAnalytics { fun logEvent(name: String, parameters: Map<String, Any>) }

    fun initKoinIos( userDefaults: NSUserDefaults, appInfo: AppInfo, analytics: KotlinAnalytics, doOnStartup: () -> Unit ) ( // Etc )
  5. class IosAnalytics: KotlinAnalytics { func logEvent(name: String, parameters: [String :

    Any]) { Analytics.logEvent(name, parameters: parameters) } }
  6. class IosAnalytics: KotlinAnalytics { func logEvent(name: String, parameters: [String :

    Any]) { Analytics.logEvent(name, parameters: parameters) } } KoinIOSKt.doInitKoinIos( userDefaults: userDefaults, appInfo: iosAppInfo, analytics: IosAnalytics(), doOnStartup: doOnStartup )
  7. kotlin { //etc cocoapods { summary = "Common library for

    the KaMP starter kit" homepage = "https://github.com/touchlab/KaMPKit" ios.deploymentTarget = "12.4" podfile = project.file("../ios/Podfile") pod("FirebaseAnalytics") } }
  8. Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_FIRStackFrame", referenced from: objc-class-ref in

    libco.touchlab:kermit-crashlytics-cache.a(result.o) "_OBJC_CLASS_$_FIRExceptionModel", referenced from: objc-class-ref in libco.touchlab:kermit-crashlytics-cache.a(result.o) "_OBJC_CLASS_$_FIRCrashlytics", referenced from: objc-class-ref in libco.touchlab:kermit-crashlytics-cache.a(result.o) ld: symbol(s) not found for architecture x86_64
  9. Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_FIRStackFrame", referenced from: objc-class-ref in

    libco.touchlab:kermit-crashlytics-cache.a(result.o) "_OBJC_CLASS_$_FIRExceptionModel", referenced from: objc-class-ref in libco.touchlab:kermit-crashlytics-cache.a(result.o) "_OBJC_CLASS_$_FIRCrashlytics", referenced from: objc-class-ref in libco.touchlab:kermit-crashlytics-cache.a(result.o) ld: symbol(s) not found for architecture x86_64
  10. /** * Multiplatform AtomicInt implementation */ expect class AtomicInt(initialValue: Int)

    { fun get(): Int fun set(newValue: Int) fun incrementAndGet(): Int fun decrementAndGet(): Int fun addAndGet(delta: Int): Int fun compareAndSet(expected: Int, new: Int): Boolean }
  11. import kotlin.native.concurrent.AtomicInt actual class AtomicInt actual constructor(initialValue:Int){ private val atom

    = AtomicInt(initialValue) actual fun get(): Int = atom.value actual fun set(newValue: Int) { atom.value = newValue } actual fun incrementAndGet(): Int = atom.addAndGet(1) actual fun decrementAndGet(): Int = atom.addAndGet(-1) actual fun addAndGet(delta: Int): Int = atom.addAndGet(delta) actual fun compareAndSet(expected: Int, new: Int): Boolean = atom.compareAndSet(expected, new) }
  12. import kotlin.native.concurrent.AtomicInt actual class AtomicInt actual constructor(initialValue:Int){ private val atom

    = AtomicInt(initialValue) actual fun get(): Int = atom.value actual fun set(newValue: Int) { atom.value = newValue } actual fun incrementAndGet(): Int = atom.addAndGet(1) actual fun decrementAndGet(): Int = atom.addAndGet(-1) actual fun addAndGet(delta: Int): Int = atom.addAndGet(delta) actual fun compareAndSet(expected: Int, new: Int): Boolean = atom.compareAndSet(expected, new) }
  13. expect class QuerySnapshot expect val QuerySnapshot.documentChanges_:List<DocumentChange> expect fun QuerySnapshot.getDocumentChanges_(…):List<DocumentChange> expect

    val QuerySnapshot.documents_:List<DocumentSnapshot> expect val QuerySnapshot.metadata: SnapshotMetadata expect val QuerySnapshot.query: Query expect val QuerySnapshot.empty: Boolean expect val QuerySnapshot.size: Int
  14. expect class QuerySnapshot expect val QuerySnapshot.documentChanges_:List<DocumentChange> expect fun QuerySnapshot.getDocumentChanges_(…):List<DocumentChange> expect

    val QuerySnapshot.documents_:List<DocumentSnapshot> expect val QuerySnapshot.metadata: SnapshotMetadata expect val QuerySnapshot.query: Query expect val QuerySnapshot.empty: Boolean expect val QuerySnapshot.size: Int
  15. actual typealias QuerySnapshot = FIRQuerySnapshot actual val QuerySnapshot.documentChanges_: List<DocumentChange> get()

    = documentChanges as List<DocumentChange> actual val QuerySnapshot.documents_: List<DocumentSnapshot> get() = documents as List<DocumentSnapshot> actual fun QuerySnapshot.getDocumentChanges_(metadataChanges: Metadata documentChangesWithIncludeMetadataChanges(metadataChanges == Metad iOS
  16. actual typealias QuerySnapshot = FIRQuerySnapshot actual val QuerySnapshot.documentChanges_: List<DocumentChange> get()

    = documentChanges as List<DocumentChange> actual val QuerySnapshot.documents_: List<DocumentSnapshot> get() = documents as List<DocumentSnapshot> actual fun QuerySnapshot.getDocumentChanges_(metadataChanges: Metadata documentChangesWithIncludeMetadataChanges(metadataChanges == Metad iOS
  17. actual typealias QuerySnapshot = FIRQuerySnapshot actual val QuerySnapshot.documentChanges_: List<DocumentChange> get()

    = documentChanges as List<DocumentChange> actual val QuerySnapshot.documents_: List<DocumentSnapshot> get() = documents as List<DocumentSnapshot> actual fun QuerySnapshot.getDocumentChanges_(metadataChanges: Metadata documentChangesWithIncludeMetadataChanges(metadataChanges == Metad iOS
  18. expect open class DocumentSnapshot DocumentSnapshot actual typealias DocumentSnapshot = FIRDocumentSnapshot

    iOS common actual typealias DocumentSnapshot = com.google.firebase.firestore.DocumentSnapshot Android
  19. actual typealias QuerySnapshot = com.google.firebase.firestore.QuerySn actual val QuerySnapshot.documentChanges_: List<DocumentChange> get()

    = documentChanges actual val QuerySnapshot.documents_: List<DocumentSnapshot> get() = documents actual fun QuerySnapshot.getDocumentChanges_(metadataChanges: Metadata getDocumentChanges(metadataChanges.toJvm()) Android
  20. At Touchlab • Big team build tools • Better iOS

    Dev ex • Swift code generation • Other things