Kotlin 1.4.0 comes with lots of features and improvements in the tooling for multiplatform programming. Some of them just work out of the box on existing projects, and some require additional configuration steps. This guide will help you migrate your multiplatform projects to 1.4.0 and get the benefits of all its new features.
Starting with 1.4.0, Kotlin multiplatform projects require Gradle 6.0 or later. Make sure that your projects use the proper version of Gradle and upgrade it if needed. See the Gradle documentation for non-Kotlin-specific migration instructions.
Gradle module metadata provides rich publishing and dependency resolution features that are used in Kotlin Multiplatform Projects. In Gradle 6.0 and above, module metadata is used in dependency resolution and included in publications by default. Thus, once you update to Gradle 6.0, you can remove enableFeaturePreview("GRADLE_METADATA")
from the project’s settings.gradle
file.
If you use libraries published with metadata, you only have to specify dependencies on them only once in the shared source set, as opposed to specifying dependencies on different variants of the same library in the shared and platform-specific source sets prior to 1.4.0.
Starting from 1.4.0, you also no longer need to declare a dependency on stdlib
in each source set manually – it will now be added by default. The version of the automatically added standard library will be the same as the version of the Kotlin Gradle plugin, since they have the same versioning.
With these features, you can make your Gradle build file much more concise and easy to read:
... android() ios() js() sourceSets { commonMain { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") } } } ...
Don’t use kotlinx library artifact names with suffixes -common
or -native
, as they are no longer supported. Instead, use the library root artifact name, which in the example above is kotlinx-coroutines-core
.
With the new hierarchical project structure support, you can share code among several targets in a multiplatform project. You can use platform-dependent libraries, such as Foundation
, UIKit
, and posix
in source sets shared among several native targets. This can help you share more native code without being limited by platform-specific dependencies.
By enabling the hierarchical structure along with its ability to use platform-dependent libraries in shared source sets, you can eliminate the need to use certain workarounds to get IDE support for sharing source sets among several native targets, for example iosArm64
and iosX64
:
kotlin { // workaround 1: select iOS target platform depending on the Xcode environment variables val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true) ::iosArm64 else ::iosX64 iOSTarget("ios") }
# workaround 2: make symbolic links to use one source set for two targets ln -s iosMain iosArm64Main && ln -s iosMain iosX64Main
Instead of doing this, you can create a hierarchical structure with target shortcuts available for typical multi-target scenarios, or you can manually declare and connect the source sets. For example, you can create two iOS targets and a shared source set with the ios()
shortcut:
kotlin { ios() // iOS device and simulator targets; iosMain and iosTest source sets }
To enable the hierarchical project structure along with the use of platform-dependent libraries in shared source sets, just add the following to your gradle.properties
:
kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.native.enableDependencyPropagation=false
In future versions, the hierarchical project structure will become default for Kotlin multiplatform project, so we strongly encourage you to start using it now.
The Bintray plugin doesn’t support publishing Gradle module metadata, but there are a couple of ways to get around this issue:
maven-publish
instead of bintray-publish
as we did for kotlinx.serialization
While uploading your library to Bintray, you will see multiple versions for each artifact (such as my-library-jvm
, my-library-metadata
, etc.). To fix this, add systemProp.org.gradle.internal.publish.checksums.insecure=true
. See this issue for details. This is a common Gradle 6.0 issue that is neither MPP nor Kotlin specific.
The layout of kotlinx libraries has changed and now corresponds to the default layout, which we recommend using: The '“root” or “umbrella” library module now has a name without a suffix (for example,kotlinx-coroutines-core
instead of kotlinx-coroutines-core-native
). Publishing libraries with maven-publish Gradle plugin follows this layout by default.
A hierarchical project structure allows reusing code in similar targets, as well as publishing and consuming libraries with granular APIs targeting similar platforms. We recommend that you switch to the hierarchical project structure in your libraries when migrating to Kotlin 1.4.0:
ios()
shortcuts in their gradle.build
files won’t be able to use your library in their iOS-shared code.To enable hierarchical project structure support, add the following to your gradle.properties
:
kotlin.mpp.enableGranularSourceSetsMetadata=true
The introduction of the hierarchical project structure in multiplatform projects resulted in a couple of changes to the names of some Gradle tasks:
metadataJar
task has been renamed to allMetadataJar
compile<SourceSet>KotlinMetadata
tasks for all published intermediate source-setsThese changes are relevant only for projects with the hierarchical project structure.
When declaring dependencies on npm packages, you are now required to explicitly specify a version or version range based on npm’s semver syntax. Specifying multiple version ranges is also supported.
While we don’t recommend it, you can use a wildcard *
in place of a version number if you do not want to specify a version or version range explicitly.
Kotlin 1.4.0 introduces the Alpha IR compiler for Kotlin/JS. For more detailed information about the Kotlin/JS IR compiler’s backend and how to configure it, consult the documentation.
To choose between the different Kotlin/JS compiler options, set the key kotlin.js.compiler
in your gradle.properties
to legacy
, ir
, or both
. Alternatively, pass LEGACY
, IR
, or BOTH
to the js
function in your build.gradle(.kts)
.
kotlin { js(IR) { // or: LEGACY, BOTH // . . . } binaries.executable() }
both
modeChoosing both
as the compiler option (so that it will compile with both the legacy and the IR backend) means that some Gradle tasks are renamed to explicitly mark them as only affecting the legacy compilation. compileKotlinJs
is renamed to compileKotlinJsLegacy
, and compileTestKotlinJs
is renamed to compileTestKotlinJsLegacy
.
When using the IR compiler, the binaries.executable()
instruction must be present in the js
target configuration block of your build.gradle(.kts)
. If this option is omitted, only Kotlin-internal library files are generated. These files can be used from other projects, but not run on their own.
For backwards compatibility, when using the legacy compiler for Kotlin/JS, including or omitting binaries.executable()
will have no effect – executable files will be generated in either case. To make the legacy backend stop producing executable files without the presence of binaries.executable()
(for example, to improve build times where runnable artifacts aren't required), set kotlin.js.generate.executable.default=false
in your gradle.properties
.
The Dukat integration for Gradle has received minor naming and functionality changes with Kotlin 1.4.0.
kotlin.js.experimental.generateKotlinExternals
flag has been renamed to kotlin.js.generate.externals
. It controls the default behavior of Dukat for all specified npm dependencies.npm
dependency function now takes a third parameter after the package name and version: generateExternals
. This allows you to individually control whether Dukat should generate declarations for a specific dependency, and it overrides the generateKotlinExternals
setting.A way to manually trigger the generation of Kotlin externals is also available. Please consult the documentation for more information.
The choice between the IR
and LEGACY
compilers was not yet available in Kotlin 1.3.xx. Because of this, you may encounter a Gradle error Cannot choose between the following variants...
if one of your dependencies (or any transitive dependency) was built using Kotlin 1.4+ but your project uses Kotlin 1.3.xx. A workaround is provided here.
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/migrating-multiplatform-project-to-14.html