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

Hi, have you met Kotlin Multiplatform? | Appdevcon

Hi, have you met Kotlin Multiplatform? | Appdevcon

Kotlin Multiplatform is getting more and more hype every day. It started as an experimental technology, then alpha, beta, and now it’s finally stable.

We constantly read of new companies and teams that are using KMP for experiments and production projects alike. And we’re left wondering: why pick KMP over any other cross-platform solution? How to approach it? And, most importantly, is it possible to start using it in existing projects?

In this talk, I’ll answer these questions, clarifying all the doubts and making you ready to use and love Kotlin Multiplatform.

Marco Gomiero

March 15, 2024
Tweet

More Decks by Marco Gomiero

Other Decks in Programming

Transcript

  1. Marco Gomiero @marcoGomier 👨💻 Senior Android Developer @ Airalo Google

    Developer Expert for Kotlin Hi, have you met Kotlin Multiplatform?
  2. @marcoGomier “Classic” Cross Platform Solutions • All-in approach • Everything

    is shared, UI included • Different platforms have different patterns
  3. @marcoGomier Common Kotlin Kotlin/JVM Kotlin/JS Kotlin/Native JVM Android Browser NodeJS

    iOS macOS watchOS tvOS Linux Windows Supported Platforms Kotlin/Wasm Browser Alpha
  4. @marcoGomier Common Kotlin Kotlin/JVM Kotlin/JS Kotlin/Native JVM Android Browser NodeJS

    iOS macOS watchOS tvOS Linux Windows Mobile Kotlin/Wasm Browser Alpha
  5. @marcoGomier Common and Platform-specific code • Write regular Kotlin code

    in the common source set • Platform-specific code goes into platform source sets
  6. @marcoGomier expect fun debugLog(tag: String, message: String) import android.util.Log actual

    fun debugLog(tag: String, message: String) { Log.d(tag, message) } import platform.Foundation.NSLog actual fun debugLog(tag: String, message: String) { if (Platform.isDebugBinary) { NSLog("%s: %s", tag, message) } }
  7. @marcoGomier internal interface XmlFetcher { suspend fun fetchXml(url: String): ParserInput

    } internal class JvmXmlFetcher( private val callFactory: Call.Factory, ): XmlFetcher { override suspend fun fetchXml(url: String): ParserInput { val request = createRequest(url) return ParserInput( inputStream = callFactory.newCall(request).await() ) } } internal class IosXmlFetcher( private val nsUrlSession: NSURLSession, ): XmlFetcher { override suspend fun fetchXml(url: String): ParserInput = suspendCancellableCoroutine { continuation -> ... } }
  8. @marcoGomier import org.jsoup.Jsoup internal class JvmHtmlParser : HtmlParser { override

    fun getTextFromHTML(html: String): String? { return try { val doc = Jsoup.parse(html) doc.text() } catch (e: Throwable) { null } } } import shared import SwiftSoup class IosHtmlParser: HtmlParser { func getTextFromHTML(html: String) -> String? { do { let doc: Document = try SwiftSoup.parse(html) return try doc.text() } catch { return nil } } } interface HtmlParser { fun getTextFromHTML(html: String): String? }
  9. @marcoGomier when (appState.newsState) { is NewsState.Loading -> { progressBar.visibility =

    View.VISIBLE ... } is NewsState.Error -> { errorButton.visibility = View.VISIBLE errorMessage.visibility = View.VISIBLE ... } is NewsState.Success -> { progressBar.visibility = View.GONE errorMessage.visibility = View.GONE recyclerView.visibility = View.VISIBLE ... } }
  10. @marcoGomier Some gotchas • No namespaces • No default parameters

    • Enums are not Swift-friendly (no values) • Sealed classes are simple classes • Coroutines without cancellation • Flows
  11. @marcoGomier CocoaPods integration https://kotlinlang.org/docs/reference/native/cocoapods.html Pod::Spec.new do |spec| spec.name = 'shared'

    spec.version = '1.0' spec.homepage = 'Link to the Shared Module homepage' spec.source = { :http=> ''} spec.authors = '' spec.license = '' spec.summary = 'Some description for the Shared Module' spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework' spec.libraries = 'c++' spec.ios.deployment_target = '14.1' spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':shared', 'PRODUCT_MODULE_NAME' => 'shared', } spec.script_phases = [ { :name => 'Build shared', :execution_position => :before_compile, :shell_path => '/bin/sh', :script => <<-SCRIPT if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment exit 0 fi set -ev REPO_ROOT="$PODS_TARGET_SRCROOT" "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ -Pkotlin.native.cocoapods.archs="$ARCHS" \ -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" SCRIPT } ] end
  12. @marcoGomier Common Kotlin Android App iOS App .aar XCFramework Android

    App Repository KMP Repository iOs App Repository
  13. @marcoGomier Setup a Maven repository to share the artifacts: build.gradle.kts

    plugins { //... id("maven-publish") } group = "com.prof18.hn.foundation" version = "1.0" publishing { repositories { maven { credentials { username = "username" password = "pwd" } url = URI.create("https://mymavenrepo.it") } } }
  14. @marcoGomier Build an XCFramework https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework kotlin { ...

    val libName = "LibraryName" val xcf = XCFramework(libName) listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { it.binaries.framework { baseName = libName xcf.add(this) isStatic = true } } }
  15. @marcoGomier Existing projects Common Kotlin Android App iOS App .aar

    XCFramework Android App Repository KMP Repository iOs App Repository
  16. @marcoGomier • Boring code to write multiple times • Code/feature

    that centralizes the source of truth • Code/feature that can be gradually extracted Where to start?
  17. @marcoGomier Start little then go bigger • Validate the process

    with “little” effort • Then you can go bigger and share more “features”
  18. @marcoGomier • Networking: Ktor, Apollo • Persistence: SQLDelight, multiplatform-settings, Realm

    • Serialization: kotlinx.serialization • Dependency Injection: Koin, Kodein, kotlin-inject • Asynchronous: Coroutines, Reaktive • Date/Time: kotlinx-datetime • Logging: Kermit, Napier Common Libraries And much more ...
  19. @marcoGomier • Kotlin Multiplatform ! = Cross Platform • Stable

    since Kotlin 1.9.20 • It’s a joint and team approach Conclusions
  20. Bibliography / Useful Links • https: / / kotlinlang.org/docs/multiplatform.html •

    https: / / kotlinlang.org/docs/native-overview.html • https: / / kotlinlang.org/docs/js-overview.html • https: / / kotlinlang.org/docs/multiplatform-share-on-platforms.html • https: / / kotlinlang.org/docs/multiplatform-connect-to-apis.html • https: / / devstreaming-cdn.apple.com/videos/wwdc/2019/416h8485aty341c2/416/416_binary_frameworks_in_swift.pdf • https: / / developer.apple.com/videos/play/wwdc2019/416/ • https: / / medium.com/@aoriani/list/writing-swiftfriendly-kotlin-multiplatform-apis-c51c2b317fce • https: / / kotlinlang.org/docs/native-objc-interop.html • https: / / speakerdeck.com/kpgalligan/kotlinconf-2023-kotlin-mobile-multiplatform-for-teams • https: / / speakerdeck.com/kpgalligan/sdk-design-and-publishing-for-kotlin-multiplatform-mobile • https: / / kotlinlang.org/docs/reference/native/cocoapods.html • https: / / kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks • https: / / github.com/touchlab/KMMBridge • https: / / github.com/prof18/kmp-framework-bundler • https: / / github.com/luca992/multiplatform-swiftpackage • https: / / github.com/touchlab/xcode-kotlin • https: / / github.com/terrakok/kmp-awesome • https: / / github.com/AAkira/Kotlin-Multiplatform-Libraries • https: / / github.com/touchlab/CrashKiOS • https: / / www.droidcon.com/2023/07/31/10-myths-about-crossplatform-mobile-development-with-kotlin/ • https: / / blog.jetbrains.com/kotlin/2023/11/kotlin-multiplatform-stable/
  21. @marcoGomier Thank you! > Twitter: @marcoGomier > Github: prof18 >

    Website: marcogomiero.com > Mastodon: androiddev.social/@marcogom Marco Gomiero 👨💻 Senior Android Developer @ Airalo Google Developer Expert for Kotlin