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

Going Multiplatform with Your Android App (mDev...

Going Multiplatform with Your Android App (mDevCamp 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

June 04, 2026

More Decks by Márton Braun

Other Decks in Programming

Transcript

  1. 11

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

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

    Fragmentation • Structural changes ? 31
  4. Migrate from Java to Kotlin • Docs on kotlinlang.org kotl.in/java-to-kotlin

    • J2K converter in Intell" IDEA • AI tools kotl.in/agent-skills 53
  5. 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") } 59
  6. Update ALL the dependencies • Gradle • Android Gradle Plugin

    • Kotlin • Jetpack Compose kotl.in/kmp-compat kotl.in/cmp-compat kotl.in/gradle/agp9 •… 60
  7. 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 67
  8. 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 68
  9. Handling the rest commonMain expect fun getPlatformId(): String androidMain actual

    fun getPlatformId(): String = !!... iosMain actual fun getPlatformId(): String = !!... 73
  10. Handling the rest commonMain androidMain iosMain interface Platform { !!...

    } fun init(platform: Platform) class AndroidPlatform : Platform { !!... } class IosPlatform : Platform { !!... } 74
  11. Handling the rest commonMain androidMain iosMain interface Platform { !!...

    } fun init(platform: Platform) class AndroidPlatform( context: Context ) : Platform { !!... } class IosPlatform : Platform { !!... } 75
  12. Setting up the KMP plugin (for Android) Change plugins Move

    dependencies Move sources Add AGP 9 opt-ins 87
  13. 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 88
  14. Setting up the KMP plugin + + plugins { alias(libs.plugins.android.library)

    alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.android.multiplatform.library) } 89
  15. 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 } } 90
  16. 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 } } } 91
  17. 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 } } } 92
  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 } } } 93
  19. 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
  20. 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 } 95
  21. Setting up the KMP plugin kotlin { android { namespace

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

    = "com.example.mylibrary" compileSdk = 36 minSdk = 24 } } compilerOptions { jvmTarget = JvmTarget.JVM_11 } 97
  23. 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 { } } } 99
  24. 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) } } } 100
  25. 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) } } } 101
  26. Add AGP 9 opt-ins kotlin { android { androidResources.enable =

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

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

    } } } dependencies { androidRuntimeClasspath(libs.compose.ui.tooling) } 108
  29. 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" } 110
  30. Add more platforms kotlin { android { ...} iosArm64() iosSimulatorArm64()

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

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

    jvm() } wasmJs { browser() } js { browser() } 115
  33. What’s next? • Project configurations kotl.in/kmp-project-config • Introducing your team

    to KMP • Try Swift Export kotl.in/kmp-team-intro kotl.in/swift-export • Compose Hot Reload kotl.in/compose-hot-reload 130