$30 off During Our Annual Pro Sale. View Details »

Embracing commonMain for Android Development - Droidcon SF 2022

Embracing commonMain for Android Development - Droidcon SF 2022

Video: https://www.droidcon.com/2022/06/28/embracing-commonmain-for-android-development/

We are all excited to use Kotlin Multiplatform, but on large projects it’s hard to figure out where to start using it without introducing risk. In this talk, I’ll give you techniques to start writing your code in commonMain right now. The code you write in commonMain is just Kotlin code, so it’s no different than what you write today, but with some slightly different configuration and guidelines that need to be followed. I’ll show you how to quickly set up your project configuration, and what guidelines to follow so you can start exercising your Multiplatform muscles. Writing code in commonMain helps promote modularity, and makes you think like a “Mobile developer” instead of just an “Android” developer.

Sam Edwards

June 03, 2022
Tweet

More Decks by Sam Edwards

Other Decks in Programming

Transcript

  1. Sam Edwards - @HandstandSam
    Kotlin & Android GDE @ Dropbox
    Embracing commonMain 🫂
    for Android Development
    Droidcon SF 2022

    View Slide

  2. KotlinMultiplatform
    for Android Development

    View Slide

  3. 🤔
    https://dropbox.tech/mobile/the-not-so-hidden-cost-of-sharing-code-between-ios-and-android

    View Slide

  4. “By writing code in a non-standard fashion, we
    took on overhead that we would have not had
    to worry about had we stayed with the widely
    used platform defaults. This overhead ended
    up being more expensive than just writing the
    code twice.”

    View Slide

  5. The Overhead of:
    1. Custom frameworks and libraries
    2. Custom development environment
    3. Addressing di
    ff
    erences between the platforms
    4. Training, hiring, and retaining developers

    View Slide

  6. Kotlin Multiplatform?
    When Will You Use

    View Slide

  7. If/when it happens, it’ll be ORGANIC 🌱
    ¯\_(ツ)_/¯

    View Slide

  8. Plant a seed for Kotlin Multiplatform 🌱
    and we’ll see where it takes us
    • Same Kotlin Code, di
    ff
    erent Gradle plugin

    • Forces modularity

    • Makes developers more likely to try coding in the other platform

    View Slide

  9. What’s the Cost?

    View Slide

  10. Small Investment, Low Risk, …

    View Slide

  11. The Ultimate Source Set for Kotlin Multiplatform (KMP)
    commonMain

    View Slide

  12. View Slide

  13. View Slide

  14. commonMain

    View Slide

  15. JVM
    main Kotlin Compiler
    org.jetbrains.kotlin.android Plugin

    View Slide

  16. JVM
    main Kotlin Compiler
    org.jetbrains.kotlin.jvm Plugin

    View Slide

  17. JVM
    commonMain Kotlin Compiler
    org.jetbrains.kotlin.multiplatform Plugin

    View Slide

  18. JVM
    commonMain Kotlin Compiler
    org.jetbrains.kotlin.multiplatform Plugin
    JS
    iOS

    View Slide

  19. Plugins
    Kotlin + Gradle

    View Slide

  20. Kotlin + Gradle
    • kotlin(“android“)
    • kotlin(“jvm“)


    • kotlin(“multiplatform“)
    Plugins
    main
    main
    commonMain

    View Slide

  21. main and test
    Kotlin + Gradle
    dependencies {
    api(project(“:sample:module1”))
    implementation(project(“:sample:module2"))
    testImplementation(libs.kotlin.test.common)
    }

    View Slide

  22. main and test
    Kotlin + Gradle
    dependencies {
    api(project(“:sample:module1”))
    implementation(project(“:sample:module2"))
    testImplementation(libs.kotlin.test.common)
    }

    View Slide

  23. main and test
    Kotlin + Gradle
    dependencies {
    api(project(“:sample:module1”))
    implementation(project(“:sample:module2"))
    testImplementation(libs.kotlin.test.common)
    }

    View Slide

  24. main and test
    Kotlin + Gradle
    dependencies {
    api(project(“:sample:module1”))
    implementation(project(“:sample:module2"))
    testImplementation(libs.kotlin.test.common)
    }

    View Slide

  25. main and test
    Kotlin + Gradle
    dependencies {
    api(project(“:sample:module1”))
    implementation(project(“:sample:module2"))
    testImplementation(libs.kotlin.test.common)
    }

    View Slide

  26. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  27. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  28. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  29. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  30. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  31. commonMain and commonTest Con
    fi
    gurations
    Kotlin + Gradle
    kotlin {
    jvm()
    sourceSets {
    maybeCreate("commonMain").apply {
    dependencies {
    implementation(libs.kotlin.coroutines)
    }
    }
    maybeCreate("commonTest").apply {
    dependencies {
    implementation(libs.kotlin.test.common)
    implementation(libs.kotlin.test.annotations.common)
    }
    }
    }
    }

    View Slide

  32. Run Anywhere*
    Write Once
    * Yes, but…

    View Slide

  33. Multiplatform is Still Under Development
    https://blog.jetbrains.com/kotlin/2022/05/kotlin-multiplatform-mobile-beta-roadmap-update/

    View Slide

  34. Compiling Multiplatform Can Be Slow
    https://medium.com/yazio-engineering/speeding-up-kotlin-multiplatform-61ebf8dae560
    grade.properties

    View Slide

  35. Multiplatform Doesn’t Support Con
    fi
    guration Caching (Yet)
    https://youtrack.jetbrains.com/issue/KT-49933/Support-Gradle-Con
    fi
    guration-caching-with-HMPP

    View Slide

  36. Multiplatform Plugin Adds Overhead
    7 Tasks 14 Tasks

    View Slide

  37. To Use Multiplatform with Zero Risk
    What Can We Do?

    View Slide

  38. Initial Proof of Concept
    https://github.com/handstandsam/ShoppingApp/pull/42

    View Slide

  39. Doesn’t Quite Work in Android Studio
    https://issuetracker.google.com/issues/229628556

    View Slide

  40. View Slide

  41. kmp4free

    View Slide

  42. JVM Project Structure
    plugins {
    kotlin("jvm")
    }
    dependencies {
    implementation(libs.kotlin.stdlib)
    implementation(project(":samples:jvm_kmp4free"))
    testImplementation(libs.kotlin.test.common)
    testImplementation(libs.truth)
    }

    View Slide

  43. JVM Project Structure
    plugins {
    id("com.handstandsam.kmp4free")
    }
    dependencies {
    implementation(libs.kotlin.stdlib)
    implementation(project(":samples:jvm_kmp4free"))
    testImplementation(libs.kotlin.test.common)
    testImplementation(libs.truth)
    }

    View Slide

  44. Enable/Disable with Property
    # gradle.properties
    kmp4free=true
    or
    ./gradlew … -Pkmp4free=true

    View Slide

  45. JVM Project Structure

    View Slide

  46. JVM Project Structure

    View Slide

  47. JVM Project Structure
    kmp4free=false

    View Slide

  48. JVM Project Structure
    kmp4free=true
    kmp4free=false

    View Slide

  49. JVM Project Structure
    kmp4free=true
    kmp4free=false

    View Slide

  50. JVM Project Structure
    kmp4free=true
    kmp4free=false

    View Slide

  51. Source Set and Con
    fi
    guration Mapping
    How?

    View Slide

  52. Primary Goals of kmp4free
    • No Risk, Single Line Change to Enable Multiplatform

    • Support JVM & Multiplatform Con
    fi
    g

    • Allow Experimentation and Possible Migration to Multiplatform

    View Slide

  53. kmp4free=true
    • SourceSet Mapping
    • src/main ➡ src/commonMain

    • src/test ➡ src/jvmTest

    • Con
    fi
    guration Mapping
    • implementation ➡ commonMainImplementation

    • testImplementation ➡ jvmTestImplementation

    • Task Aliasing
    • :module:test ➡ :module:jvmTest

    View Slide

  54. kmp4free=false
    • SourceSet Mapping
    • src/commonMain ➡ src/main

    • src/jvmMain ➡ src/main

    • src/commonTest ➡ src/test

    • src/jvmTest ➡ src/test

    • Con
    fi
    guration Mapping
    • commonMainImplementation ➡ implementation

    • commonTestImplementation ➡ testImplementation

    • jvmTestImplementation ➡ testImplementation

    View Slide

  55. Migrating to commonMain
    com.android.library
    kotlin(“jvm”)
    kotlin(“multiplatform”)

    commonMain

    View Slide

  56. Migrating tests from androidTest ➡ jvm
    androidTest (instrumented)
    test (jvm)
    • Does not require any devices

    • Faster (usually)

    View Slide

  57. Demo!

    View Slide

  58. KMP4FREE 🆓
    is a low risk way
    to explore Kotlin Multiplatform

    View Slide

  59. No.
    Is it REALLY 🆓?

    View Slide

  60. Test and Experiment ♻
    • Create a multiplatform app that exercises it.

    View Slide

  61. Thank You
    Dropbox is Hiring!

    View Slide