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

Hi, have you met Kotlin Multiplatform | DevFest Hamburg

Hi, have you met Kotlin Multiplatform | DevFest Hamburg

Kotlin Multiplatform is getting more and more hype every day. It started as an experimental technology, then alpha, beta and now it's on the path of becoming 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

November 03, 2023
Tweet

More Decks by Marco Gomiero

Other Decks in Programming

Transcript

  1. 👨💻 Senior Android Engineer 
 Google Developer Expert for Kotlin

    Marco Gomiero @marcoGomier 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
  4. @marcoGomier Common and Platform-specific code • Write regular Kotlin code

    in the common source set • Platform-specific code goes into platform source sets
  5. @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) } }
  6. @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 -> ... } }
  7. @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? }
  8. @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 ... } }
  9. @marcoGomier Some gotchas • No namespaces • No default parameters

    • Enums are not Swift-friendly (no values) • Sealed classes are simple classes • Coroutines and Flows
  10. @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
  11. @marcoGomier Common Kotlin Android App iOS App .aar XCFramework 


    Android App Repository KMP Repository iOs App Repository
  12. @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") } } }
  13. @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?
  14. @marcoGomier Start little then go bigger • Validate the process

    with “little” effort • Then you can go bigger and share more “features” 

  15. @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 ...
  16. @marcoGomier • Kotlin Multiplatform ! = Cross Platform • Stable

    since Kotlin 1.9.20 • It’s the future • It’s a joint and team approach Conclusions
  17. 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/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/
  18. @marcoGomier Thank you! > Twitter: @marcoGomier 
 > Github: prof18

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