Kmp4free - A Gradle Plugin that allows seamless switching between Kotlin JVM and the Kotlin Multiplatform Plugins

Overview

🆓 kmp4free

LICENSE Latest Snapshot CI

Allows you to toggle between Kotlin JVM Plugin -> Kotlin Multiplatform with a Gradle Property kmp4free=true.

This Gradle Plugin was built to support gradual adoption of Kotlin Multiplatform. It's called kmp4free because you are able to take a normal Kotlin JVM module, and with a single line change, enable or disable the Kotlin Multiplatform Plugin.

There is always a risk of adding something new, especially with a large project. The introduction of a technology that is not at a stable version yet can block the adoption of a new technology. The goal of this plugin is to reduce risk to a single line change.

Plugin Installation

Add the Snapshot Repo in your project's settings.gradle.kts

pluginManagement {
    repositories {
        // ...
        maven { url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" }
    }
}

Add the Plugin on your project's build.gradle.kts

plugins {
    id("com.handstandsam.kmp4free") version "${latest_version}"
}

Usage

Just replace kotlin("jvm") with id("com.handstandsam.kmp4free") in the plugins block of your module's build.gradle.kts file.

Enabling Multiplatform

You can set kmp4free=true in your gradle.properties or send it in as a command-line parameter to gradle with -Pkmp4free=true.

This enables property the Kotlin Multiplatform Plugin, along with the additional changes required to support seamless switching between the Kotlin JVM Plugin.

Any code in the main sourceSet needs to be commonMain compatible when multiplatform is enabled, otherwise the build will fail about not being able to resolve JVM dependencies. This isn't a bad thing though, as you will then be able to identify what you need to change to make your code multiplatform compatible.

SourceSet Mapping

  • src/main ➡️ src/commonMain
  • src/test ➡️ src/jvmTest

Configuration Mapping

  • implementation ➡️ commonMainImplementation
  • api ➡️ commonMainApi
  • testImplementation ➡️ jvmTestImplementation
  • testApi ➡️ jvmTestApi

When tests are already written with JVM Libraries like JUnit and Google's Truth library, it would be a lot of work to migrate those tests over to commonTest, so these tests will only run on the JVM with kmp4free. Additionally, this task alias means that your scripts that run Gradle Tasks do not have to update either when the plugin is enabled, since the test task will be available.

Task Aliasing

  • :module:test ➡️ :module:jvmTest

Disabling Multiplatform

This uses the Kotlin JVM Plugin, and bypasses Kotlin Multiplatform entirely.

SourceSet Mapping

  • src/commonMain ➡️ src/main
  • src/jvmMain ➡️ src/main
  • src/commonTest ➡️ src/test
  • src/jvmTest ➡️ src/test

Configuration Mapping

  • commonMainImplementation ➡️ implementation
  • commonMainApi ➡️ api
  • commonTestImplementation ➡️ testImplementation
  • commonTestApi ➡️ testApi
  • jvmTestImplementation ➡️ testImplementation
  • jvmTestApi ➡️ testApi

You can set the following properties in your gradle.properties

Related Content

Droidcon SF Presentation: Embracing commonMain for Android Development

FAQ

Why do I need to use maybeCreate()?

You may typically see source sets defined like val commonMain by getting. Because with kmp4free we toggle the multiplatform plugin on/off, that Source Set will be sometimes be already there, and other times may not be. Therefore we use maybeCreate("commonMain") to avoid the error.

What Configurations are Mapped?

  • api
  • implementation
  • compileOnly
  • runtimeOnly
  • apiDependenciesMetadata
  • implementationDependenciesMetadata
  • compileOnlyDependenciesMetadata
  • runtimeOnlyDependenciesMetadata

Can I use kmp4free on an Android Library?

No. kmp4free is a step in the journey of migrating a kotlin("jvm") module to kotlin("multiplatform") with a commonMain SourceSet without adding any plugin changes when disabled.

The reason why you can't is because a kotlin("jvm") module means you cannot have resources in the res directory, an AndroidManifest.xml and not use Android APIs. You may find that your Android Library doesn't have any of those. If that's true, just convert it to a kotlin("jvm") module, and then you can use the plugin!

See Issue #6 for more discussion on this topic.

How do I configure my Source Sets?

You are able to use jvm or multiplatform style configuration. Note: will want to use the maybeCreate("commonMain") call instead of val commonMain by getting when accessing Source Sets.

That is because sometimes the configuration is there when enabled, but off when disabled. When you are ready, you can migrate away from the kmp4free plugin and start using the standard kotlin("jvm") project with just a jvm() target.

How do I configure my iOS and JS Targets?

You can only apply your configuration IF the kotlin("multiplatform") plugin has been added. That is because this plugin allows it to be on & off.

Look up the KotlinMultiplatformExtension, and if not null (Checked by the ?. operator), you can supply your configuration like this:

import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

project.extensions.findByType(KotlinMultiplatformExtension::class.java)?.apply {
    ios()
}

You can find more information in Issue #2. I'm thinking this would be a lambda in the plugin configuration block for each target.

Comments
  • Unable to resolve plugin

    Unable to resolve plugin

    Hi,

    I can't seem to be able to resolve this plugin. I've included the custom maven repo as shown in the readme but I get is the following exception when adding the plugin itself to the plugins {} block.

    * Exception is:
    java.lang.NoClassDefFoundError: org/gradle/configurationcache/extensions/CharSequenceExtensionsKt
    	at com.handstandsam.kmp4free.internal.Kmp4FreeSourceSetMagic.extendConfigurationsAndSourceSets(Kmp4FreeSourceSetMagic.kt:65)
    	at com.handstandsam.kmp4free.internal.Kmp4FreeMagic.enableKotlinJvm(Kmp4FreeMagic.kt:48)
    	at com.handstandsam.kmp4free.Kmp4FreePlugin.apply(Kmp4FreePlugin.kt:25)
    
    opened by ThanosFisherman 4
  • Java Resources not included from `jvmMain/resources`

    Java Resources not included from `jvmMain/resources`

    @jonamireh reported that if you have a proguard file in src/jvmMain/resources/proguard/rules.pro, it won't be in the resulting JAR.

    We need to make sure we also map the resource directories over along with the java and kotlin directories.

    opened by handstandsam 1
  • Support JAR Resources in jvmMain

    Support JAR Resources in jvmMain

    Thank you @jonamireh for identifying the issue, and providing the reproduction case. It made it easy to figure out. Also thanks for #13 to fix this. After this fix, it worked when building with kmp4free=true, but did not work with kmp4free=false, so this diff fixes that support when it is disabled and additionally adds in a sample file so I could could test.

    You can see in the debugging lines below, but we need to add it to the javaPluginExtension as well to see the debug output: Added src/jvmMain/resources as Java resources for main where it maps correctly when kmp4free is disabled.


    Fix: We didn't have the support to include resources in the source directory of your src/jvmMain folder. This PR fixes that.

    kmp4free=false

    Screen Shot 2022-09-14 at 8 06 39 AM
    --------
    Mapping SourceSet commonMain -> main
    ** SourceSets: main now includes sources from commonMain **
    Added src/commonMain/java as a Kotlin sources for main
    Added src/commonMain/kotlin as a Kotlin sources for main
    --------
    Added src/commonMain/resources as Kotlin resources for main
    Added src/commonMain/resources as Java resources for main
    --------
    ** Configurations: main extendsFrom commonMain **
    api extendsFrom commonMainApi
    implementation extendsFrom commonMainImplementation
    compileOnly extendsFrom commonMainCompileOnly
    runtimeOnly extendsFrom commonMainRuntimeOnly
    apiDependenciesMetadata extendsFrom commonMainApiDependenciesMetadata
    implementationDependenciesMetadata extendsFrom commonMainImplementationDependenciesMetadata
    compileOnlyDependenciesMetadata extendsFrom commonMainCompileOnlyDependenciesMetadata
    runtimeOnlyDependenciesMetadata extendsFrom commonMainRuntimeOnlyDependenciesMetadata
    --------
    Mapping SourceSet jvmMain -> main
    ** SourceSets: main now includes sources from jvmMain **
    Added src/jvmMain/java as a Kotlin sources for main
    Added src/jvmMain/kotlin as a Kotlin sources for main
    --------
    Added src/jvmMain/resources as Kotlin resources for main
    Added src/jvmMain/resources as Java resources for main
    --------
    ** Configurations: main extendsFrom jvmMain **
    api extendsFrom jvmMainApi
    implementation extendsFrom jvmMainImplementation
    compileOnly extendsFrom jvmMainCompileOnly
    runtimeOnly extendsFrom jvmMainRuntimeOnly
    apiDependenciesMetadata extendsFrom jvmMainApiDependenciesMetadata
    implementationDependenciesMetadata extendsFrom jvmMainImplementationDependenciesMetadata
    compileOnlyDependenciesMetadata extendsFrom jvmMainCompileOnlyDependenciesMetadata
    runtimeOnlyDependenciesMetadata extendsFrom jvmMainRuntimeOnlyDependenciesMetadata
    --------
    Mapping SourceSet commonTest -> test
    ** SourceSets: test now includes sources from commonTest **
    Added src/commonTest/java as a Kotlin sources for test
    Added src/commonTest/kotlin as a Kotlin sources for test
    --------
    Added src/commonTest/resources as Kotlin resources for test
    Added src/commonTest/resources as Java resources for test
    --------
    

    kmp4free=true

    Screen Shot 2022-09-14 at 8 07 03 AM ``` -------- Mapping SourceSet main -> commonMain ** SourceSets: commonMain now includes sources from main ** Added src/main/java as a Kotlin sources for commonMain Added src/main/kotlin as a Kotlin sources for commonMain -------- Added src/main/resources as Kotlin resources for commonMain -------- ** Configurations: commonMain extendsFrom main ** commonMainApi extendsFrom api commonMainImplementation extendsFrom implementation commonMainCompileOnly extendsFrom compileOnly commonMainRuntimeOnly extendsFrom runtimeOnly commonMainApiDependenciesMetadata extendsFrom apiDependenciesMetadata commonMainImplementationDependenciesMetadata extendsFrom implementationDependenciesMetadata commonMainCompileOnlyDependenciesMetadata extendsFrom compileOnlyDependenciesMetadata commonMainRuntimeOnlyDependenciesMetadata extendsFrom runtimeOnlyDependenciesMetadata -------- Mapping SourceSet test -> jvmTest ** SourceSets: jvmTest now includes sources from test ** Added src/test/java as a Kotlin sources for jvmTest Added src/test/kotlin as a Kotlin sources for jvmTest -------- Added src/test/resources as Kotlin resources for jvmTest -------- ```
    opened by handstandsam 1
  • Should we use withJava() for the jvm {} multiplatform target?

    Should we use withJava() for the jvm {} multiplatform target?

    Do we need withJava() since we are already mapping sourcesets? Not sure. Creating this issue to track this thought.

    https://kotlinlang.org/docs/multiplatform-configure-compilations.html#use-java-sources-in-jvm-compilations

    val multiplatformExtension =
        target.extensions.getByType(KotlinMultiplatformExtension::class.java)
    multiplatformExtension.apply {
        // Always enable JVM
        jvm {
            // Do we really need withJava()?
            // https://kotlinlang.org/docs/multiplatform-configure-compilations.html#use-java-sources-in-jvm-compilations
            //withJava()
        }
    }
    

    For now, we'll go with just jvm() unless we can see why we'd need withJava()

    opened by handstandsam 1
  • Add resources support

    Add resources support

    Summary

    This PR adds JVM resources support by configuring the resources property of each KotlinSourceSet rather than adding that to the kotlin property

    Fixes #15

    opened by jonamireh 0
  • Support resources srcDir

    Support resources srcDir

    This was an attempt to fix https://github.com/handstandsam/kmp4free/issues/15 but wasn't exactly right. See the issue for the follow up work that fixed it.

    opened by handstandsam 0
  • Find a way to optionally apply add multiplatform config.

    Find a way to optionally apply add multiplatform config.

    Tried to figure out an elegant solution to https://github.com/handstandsam/kmp4free/issues/2

    It didn't make sense for kmp4free to be opinionated about what multiplatform targets you should use or support. This method allows you to have full control over that, and then it is outside the scope of this plugin.

    opened by handstandsam 0
Releases(0.1.1)
  • 0.1.1(Sep 14, 2022)

  • 0.1.0(Jul 29, 2022)

    Initial Release. Validated and working with Kotlin 1.6.21 and 1.7.0. See the samples or https://github.com/handstandsam/ShoppingApp for example usage.

    Artifacts on Maven Central: https://repo1.maven.org/maven2/com/handstandsam/kmp4free/kmp4free/0.1.0/

    Source code(tar.gz)
    Source code(zip)
Owner
Sam Edwards
Android & Kotlin
Sam Edwards
Kotlin Gradle plugins for conveniently setting up Kotlin projects (JVM/MPP), publishing, Dokka, etc

Arrow Gradle config Add basic config to a Kotlin Multiplatform project In an Arrow KMP project, just add to the plugin block: plugins { kotlin("mu

ΛRROW 8 Aug 3, 2022
Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects

Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects. Former: kotlin-ir-plugin-adapter-gradle

null 2 Mar 8, 2022
Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it

decomposer Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it How to use Run bui

Takahiro Menju 56 Nov 18, 2022
A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes.

Change Tracker Plugin A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes

Ismael Di Vita 110 Dec 19, 2022
How to write Gradle plugins - answers to common questions and alternative implementation solutions

Gradle Plugins: Why? How? There is some misunderstanding and confusion about the concept of Plugins in Gradle. This is unfortunate, as it is one of th

Jendrik Johannes 89 Dec 25, 2022
Gradle plugins for easy start into kotlin

Starter gradle plugins for kotlin The aim The aim of this project is to create a

MIPT-NPM 5 Mar 5, 2022
Showcases different ways of writing backwards-compatible Gradle plugins.

manifestprinter This project showcases different ways of writing backwards-compatible Gradle plugins. It accompanies a talk held at droidcon Berlin 20

Simon Schiller 5 Jul 12, 2022
Gradle Plugin to automatically upgrade your gradle project dependencies and send a GitHub pull request with the changes

Gradle Plugin to automatically upgrade your gradle project dependencies and send a GitHub pull request with the changes

Dipien 142 Dec 29, 2022
Gradle plugin that generates a Swift Package Manager manifest and an XCFramework to distribute a Kotlin Multiplatform library for Apple platforms.

Multiplatform Swift Package This is a Gradle plugin for Kotlin Multiplatform projects that generates an XCFramework for your native Apple targets and

Georg Dresler 262 Jan 5, 2023
A Gradle plugin to ease testing in Kotlin Multiplatform projects.

Multiplatform Testing Plugin A Gradle plugin for easy testing of Kotlin Multiplatform projects in your CI pipeline. Support for testing android() targ

DeepMedia 6 Oct 19, 2022
Gradle Plugin that determines if modules are Kotlin Multiplatform (KMP) ready.

Gradle Plugin that determines if modules are Kotlin Multiplatform (KMP) ready. KMP Ready means that the code is Kotlin Multiplatform compatible.

Sam Edwards 58 Dec 22, 2022
KMP Ready is a Gradle Plugin that provides actionable advice to make your code Kotlin Multiplatform compatible.

KMP Ready IS ?? UNDER DEVELOPMENT ?? Decisioning Logic Positive Signals ✅ Only Kotlin .kt Source Files Using Kotlin JVM Plugin Uses the Kotlin Multipl

Sam Edwards 58 Dec 22, 2022
Useful and Fun plugins to use for Aliucord!

♥ Aliucord Plugins ♥ What do I need to use plugins ? To obtain Aliucord plugins (Plugins for Discord) make sure you have Aliucord installed! If you do

Link 10 Sep 2, 2022
Free plugins for kraken using the community api.

Community Plugins Free plugins for kraken using the community api. Wiki Make sure you read the Wiki for guides and information on how to use the commu

RSKrakenCommunity 2 Jun 25, 2022
Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms.

CompleteKotlin Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms. What this plugin provides This zero-conf

Louis CAD 235 Jan 3, 2023
Klinker is a gradle plugin making it possible to link kotlin native executables with custom linkers and options.

Klinker is a gradle plugin making it possible to link kotlin native executables with custom linkers and options. It does this by creating a static library for kotlin compilation, then generates a c+kotlin wrapper that calls into kotlin to start the app, finally using the specified compiler to compile and link the c code and kotlin library into a binary.

Jason Monk 4 Apr 14, 2022
Android Gradle Plugin -- Auto Check big image and compress image in building.

McImage I will continue to update, please rest assured to use 中文文档 Android优雅的打包时自动化获取全部res资源 McImage is a Non-invasive plugin for compress all res in

smallSohoSolo 1.1k Dec 28, 2022
Gradle Plugin for publishing artifacts to Sonatype and Nexus

Introduction Due to Sonatype's strict validation rules, the publishing requirement must be satisfied by every artifact which wants to be published to

Johnson Lee 21 Oct 14, 2022
Gradle plugin that parses version updates and assigns them to groups of people.

Notifier Gradle Plugin This gradle plugin serves the need of automating how dependencies are handles in a project. More specifically, it functions usi

Plum 4 Oct 27, 2022