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

KMP4FREE in 2023 @ Droidcon NYC 2022

Sam Edwards
September 02, 2022

KMP4FREE in 2023 @ Droidcon NYC 2022

Video: https://www.droidcon.com/2022/09/29/kmp4free-in-2023/

At Droidcon SF 2022, I first publicly announced the KMP4FREE Gradle Plugin and how it can be used to seamlessly toggle between the Kotlin JVM and Kotlin Multiplatform Plugins with a single line change. In this talk I'll show you what this will look like over the next year, and more real world examples of how this Gradle Plugin can be used. KMP4FREE can help you can start making your Kotlin code Multiplatform Compatible, today!

Sam Edwards

September 02, 2022
Tweet

More Decks by Sam Edwards

Other Decks in Technology

Transcript

  1. Sam Edwards - @HandstandSam Kotlin & Android GDE @ Dropbox

    KMP4FREE in 2023 Droidcon NYC 2022
  2. Sam Edwards - @HandstandSam Kotlin & Android GDE @ Dropbox

    Multiplaformization in 2023 Droidcon NYC 2022
  3. https://twitter.com/relizarov/status/1564288780261068802 KMP4FREE is a Tool to help with Multiplatformization

  4. K 4FREE MP

  5. 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
  6. KMP4FREE Work? How Does

  7. JVM Project Structure plugins { kotlin("jvm") } dependencies { implementation(libs.kotlin.stdlib)

    implementation(project(":samples:jvm_kmp4free")) testImplementation(libs.kotlin.test.common) testImplementation(libs.truth) }
  8. 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) }
  9. Enable/Disable with Property # gradle.properties kmp4free=true or ./gradlew … -Pkmp4free=true

  10. JVM Project Structure

  11. JVM Project Structure

  12. JVM Project Structure kmp4free=false

  13. JVM Project Structure kmp4free=true kmp4free=false

  14. JVM Project Structure kmp4free=true kmp4free=false

  15. JVM Project Structure kmp4free=true kmp4free=false

  16. Source Set and Con fi guration Mapping How?

  17. 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
  18. 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
  19. K 4FREE MP Demo

  20. Enable and Disable Multiplatform Targets? Can’t You Just

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

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

    guration-caching-with-HMPP
  23. Multiplatform Plugin Adds Overhead 7 Tasks 14 Tasks

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

  25. KMP4FREE? Should I Use

  26. but NOT Inde fi nitely It Depends

  27. to Multiplatform Finding Your Path

  28. Paths to Multiplatformization New Code

  29. Paths to Multiplatformization commonMain New Code

  30. Paths to Multiplatformization commonMain Existing Code New Code

  31. Paths to Multiplatformization Existing Code commonMain New Code KMP4FREE?

  32. Paths to Multiplatformization Existing Code commonMain KMP4FREE?

  33. Shapes The Future Every Decision

  34. Has Consequences Every Decision

  35. On Kotlin Going All In

  36. On Compose Going All In

  37. On Multiplatform Going All In

  38. Mitigation Risk

  39. From The Past Learn

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

  41. “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.”
  42. 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
  43. Write Kotlin Multiplatform Code? When Will Your Team

  44. with KMP4FREE Starting Now

  45. Ship Kotlin Multiplatform Code on iOS? When Will Your Team

  46. Maybe Never? ¯\_(ツ)_/¯

  47. For Kotlin Multiplatform Plant a Seed 🌱

  48. …And It Might Grow 🌲

  49. Plant a Seed 🌱 • Same Kotlin Code • Di

    ff erent Gradle plugin • Forces modularity • Makes developers more likely to try coding in the other platform
  50. Identifying Target Projects

  51. Plugins Kotlin + Gradle

  52. Gradle Plugin Migration kotlin(“android”)

  53. Gradle Plugin Migration kotlin(“android”) kotlin(“jvm”)

  54. Gradle Plugin Migration kotlin(“android”) kotlin(“jvm”) kotlin(“multiplatform”)

  55. Android Library Kotlin JVM Step 1 ➡

  56. dependency-analysis-android-gradle-plugin github.com/autonomousapps/dependency-analysis-android-gradle-plugin

  57. dependency-analysis-android-gradle-plugin 1. Gathers Module Data 2. Runs Decisioning Logic 3.

    Shares Actionable Advice
  58. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  59. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  60. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  61. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  62. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  63. data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val

    usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { Android Library ➡ JVM Module Advice
  64. @TypeLabel("android_score") @JsonClass(generateAdapter = false) data class AndroidScore( val hasAndroidAssets: Boolean,

    val hasAndroidRes: Boolean, val usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { @delegate:Transient private val score: Float by unsafeLazy { var count = 0f if (hasAndroidAssets) count += 2 if (hasAndroidRes) count += 2 if (usesAndroidClasses) count += 2 if (hasBuildConfig) count += 0.5f if (hasAndroidDependencies) count += 0.5f count } Android Library ➡ JVM Module Advice
  65. @TypeLabel("android_score") @JsonClass(generateAdapter = false) data class AndroidScore( val hasAndroidAssets: Boolean,

    val hasAndroidRes: Boolean, val usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { @delegate:Transient private val score: Float by unsafeLazy { var count = 0f if (hasAndroidAssets) count += 2 if (hasAndroidRes) count += 2 if (usesAndroidClasses) count += 2 if (hasBuildConfig) count += 0.5f if (hasAndroidDependencies) count += 0.5f count } Android Library ➡ JVM Module Advice
  66. /** True if this project uses no Android facilities at

    all. */ fun shouldBeJvm(): Boolean = score == 0f Android Library ➡ JVM Module Advice @TypeLabel("android_score") @JsonClass(generateAdapter = false) data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { @delegate:Transient private val score: Float by unsafeLazy { var count = 0f if (hasAndroidAssets) count += 2 if (hasAndroidRes) count += 2 if (usesAndroidClasses) count += 2 if (hasBuildConfig) count += 0.5f if (hasAndroidDependencies) count += 0.5f count }
  67. /** True if this project uses no Android facilities at

    all. */ fun shouldBeJvm(): Boolean = score == 0f /** True if this project only uses some limited number of Android facilities. */ fun couldBeJvm(): Boolean = score < THRESHOLD Android Library ➡ JVM Module Advice @TypeLabel("android_score") @JsonClass(generateAdapter = false) data class AndroidScore( val hasAndroidAssets: Boolean, val hasAndroidRes: Boolean, val usesAndroidClasses: Boolean, val hasBuildConfig: Boolean, val hasAndroidDependencies: Boolean, ) : ModuleAdvice() { @delegate:Transient private val score: Float by unsafeLazy { var count = 0f if (hasAndroidAssets) count += 2 if (hasAndroidRes) count += 2 if (usesAndroidClasses) count += 2 if (hasBuildConfig) count += 0.5f if (hasAndroidDependencies) count += 0.5f count }
  68. Module Advice from ./gradlew buildHealth Advice for :samples:android_lib Module structure

    advice This project uses limited Android features and could be a JVM project. * Includes BuildConfig.
  69. Refactoring is Rarely Trivial

  70. Extract Android Specific Code • Android Classes • BuildCon fi

    g • Assets • Strings • Activities • Layouts • Drawables
  71. Kotlin JVM Kotlin Multiplatform Step 2 ➡

  72. KMP-Readiness github.com/handstandsam/kmp-readiness

  73. KMP-Readiness Decisioning 1. Multiplatform Plugin Already Enabled? 2. Only Kotlin

    Code? 3. References to java.util, etc? 4. Multiplatform Compatible Dependencies?
  74. Multiplatform Compatible Dependencies?

  75. None
  76. None
  77. None
  78. 9 Days Later …

  79. None
  80. Maven Search https://search.maven.org/search?q=ktor-client

  81. Maven Search JSON API https://search.maven.org/solrsearch/select?q=g%3Aorg.jetbrains.kotlinx+AND+a%3Akotlinx-datetime+AND+v%3A0.3.2+AND+p%3Ajar+AND+l%3Akotlin-tooling-metadata&rows=1&wt=json { "response": { "numFound": 1,

    "start": 0, "docs": [ { "id": "org.jetbrains.kotlinx:kotlinx-datetime:0.3.2", "g": "org.jetbrains.kotlinx", "a": "kotlinx-datetime", "v": "0.3.2", "p": "jar", "timestamp": 1641926665000, "ec": [ "-javadoc.jar", "-sources.jar", ".jar", "-all.jar", "-kotlin-tooling-metadata.json", ".module", ".pom" ], "tags": [ "kotlin", "library", "datetime" ] } ] } } https://search.maven.org/search?q=g:org.jetbrains.kotlinx%20AND%20a:kotlinx-datetime%20AND%20v:0.3.2%20AND%20p:jar%20AND%20l:kotlin-tooling-metadata
  82. Maven Search JSON API https://search.maven.org/solrsearch/select?q=g%3Aorg.jetbrains.kotlinx+AND+a%3Akotlinx-datetime+AND+v%3A0.3.2+AND+p%3Ajar+AND+l%3Akotlin-tooling-metadata&rows=1&wt=json "-kotlin-tooling-metadata.json"

  83. kotlin-metadata-tooling.json

  84. { "schemaVersion": "1.0.0", "buildSystem": "Gradle", "buildSystemVersion": "7.5.1", "buildPlugin": "org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper", "buildPluginVersion":

    "1.6.21", "projectSettings": { "isHmppEnabled": true, "isCompatibilityMetadataVariantEnabled": true }, "projectTargets": [ { "target": "org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget", "platformType": "jvm", "extras": { "jvm": { "jvmTarget": "1.8", "withJavaEnabled": false } } }, { "target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget", "platformType": "common" } ] } kotlin-tooling-metadata.json https://repo1.maven.org/maven2/io/ktor/ktor-client/2.1.0/ktor-client-2.1.0-kotlin-tooling-metadata.json
  85. "platformType": "common" kotlin-tooling-metadata.json https://repo1.maven.org/maven2/io/ktor/ktor-client/2.1.0/ktor-client-2.1.0-kotlin-tooling-metadata.json

  86. See Created kotlin-tooling-metadata.json for the Kotlin Team

  87. February 2nd, 2021 - Kotlin Lang Slack

  88. kdoctor https://github.com/Kotlin/kdoctor

  89. KMP-readiness github.com/handstandsam/kmp-readiness Demo

  90. Kotlin Multiplatform Multiplatformization Success!

  91. What’s the Cost?

  92. Upfront Investment, Low Risk, …

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

  94. Coming Soon! Kotlin Multiplatform Beta

  95. Minimize Risk during Multiplatformization We Can

  96. Test and Experiment ♻ • Create a multiplatform iOS and

    Desktop app that exercises it • Create Shadow Jobs to Build Multiplatform to ensure compatibility
  97. 2023 is the Year of Multiplatformization

  98. Is a helpful tool on your path to Multiplaformization in

    2023 KMP4FREE
  99. Is a helpful tool on your path to Multiplaformization in

    2023 KMP-Readiness
  100. With Multiplatform in Mind Write Code

  101. Thank You