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

Going Multiplatform with Your Android App (next...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Going Multiplatform with Your Android App (next app dev con Berlin 2026)

Existing Android apps are in a great position to expand into Kotlin Multiplatform: you might already be using patterns, libraries, and APIs that work on more platforms than just Android. With Compose Multiplatform, you can build an app with a fully shared Kotlin codebase, targeting iOS, desktop, and even the web!

In this talk, we’ll look at how you can migrate an existing Android app to multiplatform. As this can be a significant engineering effort for an existing, well-established app, we’ll also discuss how to plan and organize the required changes, and how to adopt KMP incrementally across your codebase without disrupting day-to-day development.

https://zsmb.co/talks/going-multiplatform-with-your-android-app/

Avatar for Márton Braun

Márton Braun

October 07, 2026

More Decks by Márton Braun

Other Decks in Programming

Transcript

  1. @ next.app devcon Wednesday, 10:20 Swift Export: Where We Stand

    Wednesday, 12:00 Going Multiplatform with Your Android App Wednesday, 14:50 Kotlin by JetBrains (roundtable) Thursday, 10:20 What’s New in Compose Multiplatform Friday, 12:00 Building a Multiplatform Window Manager for Fun 2
  2. Why go KMP? One shared codebase More platforms Safe, low-risk

    Reuse Android skills Easier than you think! 4
  3. 12

  4. Quick start • Ship almost immediately • Nontrivial moves •

    Fragmentation Ktor Coroutines Coil Koin KSP Retrofit RxJava Glide Dagger kapt 31
  5. Quick start • Ship almost immediately • Nontrivial moves •

    Fragmentation • Structural changes ? 32
  6. Migrate from Java to Kotlin • Docs on kotlinlang.org kotl.in/java

    - to - kotlin • J2K converter in IntelliJ IDEA • AI tools kotl.in/agent - skills 54
  7. kapt to KSP // Android dependencies { ksp("androidx.room3:room3-compiler:3.0.0-alpha01") } //

    Kotlin Multiplatform dependencies { add("kspAndroid","androidx.room3:room3-compiler:3.0.0-alpha01") add("kspIosArm64","androidx.room3:room3-compiler:3.0.0-alpha01") add("kspJvm","androidx.room3:room3-compiler:3.0.0-alpha01") add("kspJs","androidx.room3:room3-compiler:3.0.0-alpha01") add("kspWasmJs","androidx.room3:room3-compiler:3.0.0-alpha01") } 60
  8. Update ALL the dependencies • Gradle • Android Gradle Plugin

    • Kotlin • Jetpack Compose kotl.in/kmp - compat kotl.in/cmp - compat kotl.in/gradle/agp9 • ... 61
  9. A few common replacements JDK, Android APIs Kotlin standard library

    java.time kotlinx-datetime JUnit kotlin.test, kotest Moshi, Jackson, Gson kotlinx.serialization OkHttp Ktor Retrofit Ktorfit gRPC kotlinx-rpc (Preview) SQLite SQLDelight Dagger, Anvil Metro Glide Coil 68
  10. Already good to go Kotlin standard library kotlinx-datetime Compose kotlin.test,

    kotest Koin kotlinx.serialization Arrow Ktor Room Ktorfit DataStore kotlinx-rpc (Preview) Apollo GraphQL SQLDelight Metro Coil 69
  11. Handling the rest commonMain expect fun getPlatformId (): String androidMain

    actual fun getPlatformId (): String = ... iosMain actual fun getPlatformId (): String = ... 74
  12. Handling the rest commonMain interface androidMain class AndroidPlatform iosMain class

    IosPlatform fun init Platform { ... } (platform: Platform) : Platform { ... } : Platform { ... } 75
  13. Handling the rest commonMain androidMain iosMain interface fun init Platform

    { ... } (platform: Platform) class AndroidPlatform context: Context : ) Platform { ... } class IosPlatform ( : Platform { ... } 76
  14. Setting up the KMP plugin (for Android) Change plugins Move

    dependencies Move sources Add AGP 9 opt-ins 88
  15. Setting up the KMP plugin (for Android) Change plugins Move

    dependencies Move sources Add AGP 9 opt-ins Set up Compose Multiplatform Configure previews Use multiplatform resources 89
  16. Setting up the KMP plugin + + plugins { alias(libs.plugins.android.library)

    alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.android.multiplatform.library) } 90
  17. Setting up the KMP plugin android { namespace = "com.example.mylibrary"

    compileSdk = 36 defaultConfig { minSdk = 24 } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } } 91
  18. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 defaultConfig { minSdk = 24 } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } } } 92
  19. Setting up the KMP plugin kotlin { androidLibrary { namespace

    = "com.example.mylibrary" compileSdk = 36 defaultConfig { minSdk = 24 } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } } } 93
  20. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 defaultConfig { minSdk = 24 } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } } } 94
  21. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 defaultConfig { minSdk = 24 } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } } } 95
  22. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 minSdk = 24 } } compileOptions { sourceCompatibility = VERSION_11 targetCompatibility = VERSION_11 } buildFeatures { compose = true } 96
  23. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 minSdk = 24 compilerOptions { jvmTarget = JvmTarget.JVM_11 } } } buildFeatures { compose = true } 97
  24. Setting up the KMP plugin kotlin { android { namespace

    = "com.example.mylibrary" compileSdk = 36 minSdk = 24 } } compilerOptions { jvmTarget = JvmTarget.JVM_11 } 98
  25. Setting up the KMP plugin dependencies { implementation(libs.androidx.preference) implementation(libs.kotlinx.datetime) implementation(libs.ktor.client.core)

    implementation(libs.ktor.client.content.negotiation) } kotlin { sourceSets { androidMain.dependencies { } commonMain.dependencies { } } } 100
  26. Setting up the KMP plugin dependencies { implementation(libs.androidx.preference) } kotlin

    { sourceSets { androidMain.dependencies { } commonMain.dependencies { implementation(libs.kotlinx.datetime) implementation(libs.ktor.client.core) implementation(libs.ktor.client.content.negotiation) } } } 101
  27. Setting up the KMP plugin kotlin { sourceSets { androidMain.dependencies

    { implementation(libs.androidx.preference) } commonMain.dependencies { implementation(libs.kotlinx.datetime) implementation(libs.ktor.client.core) implementation(libs.ktor.client.content.negotiation) } } } 102
  28. Add AGP 9 opt-ins kotlin { android { androidResources.enable =

    true } } withHostTest { isIncludeAndroidResources = true } withDeviceTest { instrumentationRunner = "androidx.test.runner.AndroidJUnit } 104
  29. Setting up the CMP plugin + + androidx-compose-foundation = {

    module = "androidx.compose.foundation:foundation" module = "org.jetbrains.compose.foundation:foundation", version.ref = "composeMultiplatform" } 107
  30. Setting up previews kotlin { sourceSets { commonMain.dependencies { implementation(libs.compose.ui.tooling.preview)

    } } } dependencies { androidRuntimeClasspath(libs.compose.ui.tooling) } 109
  31. Setting up previews import import androidx.compose.ui.tooling.preview. androidx.compose.ui.tooling.preview. @Preview ( showBackground

    = true , fontScale @PreviewLightDark @Composable fun ButtonPreview () { Button ( "Click me!" ) } Preview PreviewLightDark = 2f ) 110
  32. Migrate to CMP resources kotlin { android { androidResources.enable =

    true } sourceSets { commonMain.dependencies { implementation(libs.compose.components.resources) } } } // Optional customization compose.resources { nameOfResClass = "Res" packageOfResClass = "org.example.resources" } 111
  33. Add more platforms kotlin { android { ...} iosArm64() iosSimulatorArm64()

    jvm() } wasmJs { browser() } js { browser() } 114
  34. Add more platforms kotlin { android { ...} iosArm64() iosSimulatorArm64()

    jvm() } wasmJs { browser() } js { browser() } 115
  35. Add more platforms kotlin { android { ...} iosArm64() iosSimulatorArm64()

    jvm() } wasmJs { browser() } js { browser() } 116
  36. What’s next? • Project configurations kotl.in/kmp - project - config

    • Introducing your team to KMP • Try Swift Export • Compose Hot Reload kotl.in/kmp - team - intro kotl.in/swift - export kotl.in/compose - hot - reload 131
  37. @ next.app devcon Wednesday, 14:50 Kotlin by JetBrains (roundtable) Thursday,

    10:20 What’s New in Compose Multiplatform Friday, 12:00 Building a Multiplatform Window Manager for Fun The entire time Booth! 133
  38. Going Multiplatform with Your Android App kotl.in/go - kmp -

    talk Márton Braun @zsmb.co zsmb.co/talks zsmb.co/talks