Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Mastering Dependencies in Kotlin Multiplatform

Mastering Dependencies in Kotlin Multiplatform

In this presentation, we'll dive deep into the Kotlin Multiplatform Plugin's dependency management system and explore strategies for handling both KMP-specific and platform-specific libraries. We'll also provide solutions to common Cocoapods-related issues. By the end, you'll have the skills to manage dependencies like a pro and build successful Kotlin Multiplatform applications.

Tamás Fábián

October 18, 2024
Tweet

More Decks by Tamás Fábián

Other Decks in Programming

Transcript

  1. Kotlin Budapest Meetup I 2024 Tamas Fabian Principal Android Software

    Engineer October 17, 2024 Mastering Dependencies in Kotlin Multiplatform
  2. Kotlin Budapest Meetup I 2024 Agenda 1. Story time 2.

    Basics 3. Dependencies in Kotlin Multiplatform 4. Platform-specific deps 5. Common issues
  3. Kotlin Budapest Meetup I 2024 The Project The company's chat

    application is in need of an overhaul. Two principal Native Mobile Developers got hired. Options: - Refactor - Reimplement native apps - Or... guess what?
  4. Kotlin Budapest Meetup I 2024 Basics commonMain nativeMain androidNativeMain appleMain

    iosMain iosArm64Main iosSimulatorArm64M ain macosMain tvosMain watchosMain linuxMain mingwMain androidMain jvmMain compilation main .classfiles jsMain compilation test .classfiles commonTest jvmTest compilation main .js jsTest compilation test .js nativeTest androidNativeTest appleTest iosTest iosArm64Test iosSimulatorArm64T est macosTest tvosTest watchosTest linuxTest mingwTest androidTest jvm target js target
  5. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms Targets Basics kotlin { applyDefaultHierarchyTemplate() androidTarget() iosX64(), iosArm64(), iosSimulatorArm64() }
  6. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms Targets Basics kotlin { applyDefaultHierarchyTemplate() androidTarget() iosX64(), iosArm64(), iosSimulatorArm64() }
  7. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms Targets Basics kotlin { applyDefaultHierarchyTemplate { common { group("posix") { withLinux() withMingw() withMacos() } } }
  8. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms • Common & Target-specific configurations Targets Basics kotlin { androidTarget { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } } }
  9. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms • Common & Target-specific configurations Targets Basics kotlin { listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { baseName = "Shared" isStatic = true } } }
  10. Kotlin Budapest Meetup I 2024 Part of the build responsible

    for compiling, testing, and packaging a piece of software targeting one of the supported platforms. • Presets for supported platforms • Common & Target-specific configurations • One or more compilations Targets Basics
  11. Kotlin Budapest Meetup I 2024 Compilations are used for defining

    the way how final artifacts are produced. • JVM, JS, Native: main & test Compilations Basics kotlin { jvm { val main by compilations.getting { compilerOptions.configure { jvmTarget.set(JvmTarget.JVM_17) } } } }
  12. Kotlin Budapest Meetup I 2024 Compilations are used for defining

    the way how final artifacts are produced. • JVM, JS, Native: main & test • Android: by build variants Compilations Basics kotlin { jvm { val main by compilations.getting { compilerOptions.configure { jvmTarget.set(JvmTarget.JVM_17) } } } }
  13. Kotlin Budapest Meetup I 2024 A source set is a

    set of source files with its own targets, dependencies, and compiler options. It's the main way to share code in multiplatform projects. • Unique name • Predefined source sets • commonMain • <targetName><compilationName> SourceSets Basics sourceSets { commonMain.dependencies { //put your multiplatform dependencies here } commonTest.dependencies { implementation(libs.kotlin.test) } }
  14. Kotlin Budapest Meetup I 2024 A source set is a

    set of source files with its own targets, dependencies, and compiler options. It's the main way to share code in multiplatform projects. • Unique name • Predefined source sets • commonMain • <targetName><compilationName> SourceSets Basics sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) } jsMain.dependencies { implementation(libs.kotlinx.coroutines.core-js) } }
  15. Kotlin Budapest Meetup I 2024 A source set is a

    set of source files with its own targets, dependencies, and compiler options. It's the main way to share code in multiplatform projects. • Unique name • Predefined source sets • commonMain • <targetName><compilationName> • Intermediate source sets SourceSets Basics sourceSets { val commonJvm by creating { dependsOn(commonMain.get()) dependencies { implementation(libs.socketIo) } } androidMain { dependsOn(commonJvm) } jvmMain { dependsOn(commonJvm) } }
  16. Kotlin Budapest Meetup I 2024 A source set is a

    set of source files with its own targets, dependencies, and compiler options. It's the main way to share code in multiplatform projects. • Unique name • Predefined source sets • commonMain • <targetName><compilationName> • Intermediate source sets • DSL reference SourceSets Basics
  17. Kotlin Budapest Meetup I 2024 Basics commonMain nativeMain androidNativeMain appleMain

    iosMain iosArm64Main iosSimulatorArm64M ain macosMain tvosMain watchosMain linuxMain mingwMain androidMain jvmMain compilation main .classfiles jsMain compilation test .classfiles commonTest jvmTest compilation main .js jsTest compilation test .js nativeTest androidNativeTest appleTest iosTest iosArm64Test iosSimulatorArm64T est macosTest tvosTest watchosTest linuxTest mingwTest androidTest jvm target js target
  18. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) } jsMain.dependencies { implementation(libs.kotlinx.coroutines.core-js) } }
  19. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform dependencies { commonMainImplementation(libs.kotlinx.coroutines.core) jsMainImplementation(libs.kotlinx.coroutines.core-js) }
  20. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level You can add dependencies on: • Kotlin library api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { commonMain.dependencies { implementation(kotlin("stdlib")) } commonTest.dependencies { implementation(kotlin("test")) } }
  21. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level You can add dependencies on: • Kotlin library api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { commonMain.dependencies { implementation(kotlin("stdlib")) } commonTest.dependencies { implementation(kotlin("test")) } }
  22. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level You can add dependencies on: • Kotlin library • Kotlin Multiplatform library api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { commonMain.dependencies { implementation(libs.kotlinx.serialization.json) } }
  23. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level You can add dependencies on: • Kotlin library • Kotlin Multiplatform library • Platform-specific library api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { androidMain.dependencies { implementation(libs.retrofit) } }
  24. Kotlin Budapest Meetup I 2024 You can set them at:

    • Source set level • Top level You can add dependencies on: • Kotlin library • Kotlin Multiplatform library • Platform-specific library • Kotlin Multiplatform project api, implementation, compileOnly, runtimeOnly Dependencies in Kotlin Multiplatform sourceSets { commonMain.dependencies { api(projects.core) } }
  25. Kotlin Budapest Meetup I 2024 • Compatible targets • Versions

    are aligned through source sets Dependency resolution Dependencies in Kotlin Multiplatform
  26. Kotlin Budapest Meetup I 2024 • Compatible targets • Versions

    are aligned through source sets Dependency resolution Dependencies in Kotlin Multiplatform kermit:2.0.0 commonMain kermit:2.0.0 androidMain kermit:2.0.0 iosMain
  27. Kotlin Budapest Meetup I 2024 • Compatible targets • Versions

    are aligned through source sets Dependency resolution Dependencies in Kotlin Multiplatform kermit:2.0.0 commonMain kermit:2.0.0 kermit:2.0.4 anAndroidLibrary:1.0.0 androidMain kermit:2.0.0 iosMain
  28. Kotlin Budapest Meetup I 2024 • Compatible targets • Versions

    are aligned through source sets Dependency resolution Dependencies in Kotlin Multiplatform kermit:2.0.0 kermit:2.0.4 commonMain kermit:2.0.0 kermit:2.0.4 anAndroidLibrary:1.0.0 androidMain kermit:2.0.0 kermit:2.0.4 iosMain
  29. Kotlin Budapest Meetup I 2024 • The same Android Platform-specific

    dependencies sourceSets { androidMain.dependencies { implementation(libs.androidx.lifecycle.viewmodel) } }
  30. Kotlin Budapest Meetup I 2024 • npm() function Kotlin/JS Platform-specific

    dependencies sourceSets { jsMain.dependencies { implementation(npm(“is-sorted”, ”1.0,5”)) } }
  31. Kotlin Budapest Meetup I 2024 • npm() function • External

    declarations Kotlin/JS Platform-specific dependencies @JsModule("is-sorted") @JsNonModule external fun <T> sorted(a: Array<T>): Boolean
  32. Kotlin Budapest Meetup I 2024 • Definition file .def •

    Properties Kotlin/Native Platform-specific dependencies headers = curl/curl.h headerFilter = curl/* compilerOpts.linux = -I/usr/include -I/usr/include/x86_64-linux-gnu linkerOpts.osx = -L/opt/local/lib -L/usr/local/opt/curl/lib -lcurl linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -lcurl
  33. Kotlin Budapest Meetup I 2024 • Cocoapods • (SPM) iOS

    Platform-specific dependencies cocoapods { summary = "Some description for the Shared Module" homepage = "Link to the Shared Module homepage" version = "1.0" ios.deploymentTarget = "16.0" podfile = project.file("../iosApp/Podfile") framework { baseName = "shared" isStatic = true } pod("FirebaseAuth") { version = "10.16.0" } }
  34. Kotlin Budapest Meetup I 2024 • Cocoapods • cinterop iOS

    Platform-specific dependencies MyFramework.def language = Objective-C modules = MyFramework package = MyFramework
  35. Kotlin Budapest Meetup I 2024 • Cocoapods • cinterop iOS

    Platform-specific dependencies iosArm64 { val main by compilations.getting { val MyFramework by cinterops.creating { definitionFile.set(project.file("src/nativeInterop/cinterop/MyFramework.def")) compilerOpts("-framework", "MyFramework", "-F/path/to/framework/") } } binaries.all { linkerOpts("-framework", "MyFramework", "-F/path/to/framework/") } }
  36. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” moduleName = "SocketIO" } } Swift-only library Common Issues :shared:iosArm64Main: cinterop file: /Users/tfabian/AndroidStudioProjects/Couchbase/shared/build/c lasses/kotlin/iosArm64/main/cinterop/ shared-cinterop-SocketIO.klib does not exist Possible solution: - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories .html Error
  37. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” moduleName = "SocketIO" } } Swift-only library Common Issues @objc public class SocketIo: NSObject { @objc public func connect() { socket.connect() } @objc public func disconnect() { socket.disconnect() } ... } Solution
  38. Kotlin Budapest Meetup I 2024 sourceSets { commonMain.dependencies { api(libs.kotlinx.serialization.json)

    } } Transitive dependencies Common Issues java.lang.NoClassDefFoundError: Failed resolution of: Lkotlinx/serialization/json/JsonKt Error
  39. Kotlin Budapest Meetup I 2024 sourceSets { commonMain.dependencies { api(libs.kotlinx.serialization.json)

    } } Transitive dependencies Common Issues kotlin { ios.binaries.framework { export(libs.kotlinx.serialization.json) // OR transitiveExport = true } } Solution
  40. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” moduleName = "SocketIO" } } @import directives Common Issues Exception in thread "main" java.lang.Error: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSi mulator18.0.sdk/usr/include/copyfile.h:35:10: fatal error: 'sys/cdefs.h' file not found … /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSi mulator18.0.sdk/System/Library/Frameworks/CFNetwork.framework/Headers/CFNetwork.h:18:10: fatal error: could not build module 'CoreFoundation’ /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSi mulator18.0.sdk/usr/include/xpc/xpc.h:6:10: fatal error: could not build module 'os_object’ at org.jetbrains.kotlin.native.interop.indexer.ModuleSupportKt.getModulesASTFiles(ModuleSupport.kt:80) at org.jetbrains.kotlin.native.interop.indexer.ModuleSupportKt.getModulesInfo(ModuleSupport.kt:15) at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.buildNativeLibrary(main.kt:564) at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLib(main.kt:308) at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLibSafe(main.kt:244) at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.access$processCLibSafe(main.kt:1) at org.jetbrains.kotlin.native.interop.gen.jvm.Interop.interop(main.kt:102) at org.jetbrains.kotlin.cli.utilities.InteropCompilerKt.invokeInterop(InteropCompiler.kt:49) at org.jetbrains.kotlin.cli.utilities.MainKt.mainImpl(main.kt:23) at org.jetbrains.kotlin.cli.utilities.MainKt.main(main.kt:44) Error
  41. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” moduleName = "SocketIO" } } @import directives Common Issues extraOpts += listOf("-compiler-option", "-fmodules") Solution
  42. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” } } Dash in cocoapod’s name Common Issues fatal error: module 'socket_io_wrapper' not found Error
  43. Kotlin Budapest Meetup I 2024 cocoapods { pod("Socket.IO-Client-Swift") { version

    = "16.1.1” } } Dash in cocoapod’s name Common Issues moduleName = "SocketIO" Solution
  44. Kotlin Budapest Meetup I 2024 cocoapods { pod("StripePaymentsUI") { version

    = ”23.31.1" } } Pod::Spec.new do |s| s.name = 'StripePaymentsUI’ ... s.dependency 'StripeCore', s.version.to_s s.dependency 'StripeUICore', s.version.to_s s.dependency 'StripePayments', s.version.to_s end Linked modules Common Issues Unresolved reference: STPPaymentHandlerActionStatus Error
  45. Kotlin Budapest Meetup I 2024 cocoapods { pod("StripePaymentsUI") { version

    = ”23.31.1" } } Linked modules Common Issues pod("StripePayments") { version = ”23.31.1" } Solution
  46. Kotlin Budapest Meetup I 2024 sourceSets { commonMain.dependencies { implementation(libs.google.gson)

    } } Dependency at the wrong place Common Issues androidMain • Remember what you’ve learned. • KT-72287 Improve error reporting when dependency doesn't match expected platforms Solution
  47. Kotlin Budapest Meetup. I 2024 Get in Touch LinkedIn in/tamas--fabian

    X @tomi_fabian GitHub github.com/TomiFabian
  48. Kotlin Budapest Meetup I 2024 • https://kotlinlang.org/docs/multiplatform-intro.html • https://github.com/JetBrains/kotlin •

    https://github.com/JakeWharton/mosaic • https://stackoverflow.com/questions/tagged/kotlin-multiplatform • https://youtrack.jetbrains.com/issues/KT References