Slide 1

Slide 1 text

Kotlin Budapest Meetup I 2024 Tamas Fabian Principal Android Software Engineer October 17, 2024 Mastering Dependencies in Kotlin Multiplatform

Slide 2

Slide 2 text

Kotlin Budapest Meetup I 2024 Agenda 1. Story time 2. Basics 3. Dependencies in Kotlin Multiplatform 4. Platform-specific deps 5. Common issues

Slide 3

Slide 3 text

Kotlin Budapest Meetup I 2024 Story time

Slide 4

Slide 4 text

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?

Slide 5

Slide 5 text

Kotlin Budapest Meetup I 2024

Slide 6

Slide 6 text

Kotlin Budapest Meetup I 2024 Basics

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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() }

Slide 9

Slide 9 text

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() }

Slide 10

Slide 10 text

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() } } }

Slide 11

Slide 11 text

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) } } }

Slide 12

Slide 12 text

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 } } }

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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) } } } }

Slide 15

Slide 15 text

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) } } } }

Slide 16

Slide 16 text

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 • SourceSets Basics sourceSets { commonMain.dependencies { //put your multiplatform dependencies here } commonTest.dependencies { implementation(libs.kotlin.test) } }

Slide 17

Slide 17 text

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 • SourceSets Basics sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) } jsMain.dependencies { implementation(libs.kotlinx.coroutines.core-js) } }

Slide 18

Slide 18 text

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 • • Intermediate source sets SourceSets Basics sourceSets { val commonJvm by creating { dependsOn(commonMain.get()) dependencies { implementation(libs.socketIo) } } androidMain { dependsOn(commonJvm) } jvmMain { dependsOn(commonJvm) } }

Slide 19

Slide 19 text

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 • • Intermediate source sets • DSL reference SourceSets Basics

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Kotlin Budapest Meetup I 2024 Dependencies in Kotlin Multiplatform

Slide 22

Slide 22 text

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) } }

Slide 23

Slide 23 text

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) }

Slide 24

Slide 24 text

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")) } }

Slide 25

Slide 25 text

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")) } }

Slide 26

Slide 26 text

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) } }

Slide 27

Slide 27 text

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) } }

Slide 28

Slide 28 text

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) } }

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Kotlin Budapest Meetup I 2024 Platform-specific dependencies

Slide 34

Slide 34 text

Kotlin Budapest Meetup I 2024 • The same Android Platform-specific dependencies sourceSets { androidMain.dependencies { implementation(libs.androidx.lifecycle.viewmodel) } }

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Kotlin Budapest Meetup I 2024 • npm() function • External declarations Kotlin/JS Platform-specific dependencies @JsModule("is-sorted") @JsNonModule external fun sorted(a: Array): Boolean

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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" } }

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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/") } }

Slide 41

Slide 41 text

Kotlin Budapest Meetup I 2024 Common issues

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Kotlin Budapest Meetup I 2024 cocoapods { pod("StripePaymentsUI") { version = ”23.31.1" } } Linked modules Common Issues pod("StripePayments") { version = ”23.31.1" } Solution

Slide 52

Slide 52 text

Kotlin Budapest Meetup I 2024 sourceSets { commonMain.dependencies { implementation(libs.google.gson) } } Dependency at the wrong place Common Issues Nothing :( Error

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Kotlin Budapest Meetup I 2024 Libraries’ libraries

Slide 55

Slide 55 text

Kotlin Budapest Meetup I 2024 Libraries’ libraries

Slide 56

Slide 56 text

Kotlin Budapest Meetup I 2024 Libraries’ libraries

Slide 57

Slide 57 text

Kotlin Budapest Meetup I 2024 Libraries’ libraries

Slide 58

Slide 58 text

Kotlin Budapest Meetup I 2024 Libraries’ libraries

Slide 59

Slide 59 text

Kotlin Budapest Meetup I 2024 Thank you.

Slide 60

Slide 60 text

Kotlin Budapest Meetup. I 2024 Get in Touch LinkedIn in/tamas--fabian X @tomi_fabian GitHub github.com/TomiFabian

Slide 61

Slide 61 text

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