- Kotlin 多平台兼容性指南
- New approach to auto-generated targets
- Changes in Gradle input and output compile tasks
- New configuration names for dependencies on the compilation
- Deprecated Gradle properties for hierarchical structure support
- Deprecated support of multiplatform libraries published in the legacy mode
- Deprecated API for adding Kotlin source sets directly to the Kotlin compilation
- Migration from
kotlin-js
Gradle plugin tokotlin-multiplatform
Gradle plugin - Rename of
android
target toandroidTarget
Kotlin 多平台兼容性指南
This guide summarizes incompatible changes you might encounter while developing projects with Kotlin Multiplatform.
Mind the deprecation cycle of a specific change in relation to the Kotlin version you have in your projects. The current Stable version of Kotlin is 1.9.10.
New approach to auto-generated targets
What’s changed?
Target accessors auto-generated by Gradle are no longer available inside the kotlin.targets
block. Use the findByName("targetName")
method instead.
Note that such accessors are still available in the kotlin.targets
case, for example, kotlin.targets.linuxX64
.
What’s the best practice now?
Before | Now |
kotlin kotlin { targets { configure(['windows', 'linux']) { } } } | kotlin kotlin { targets { configure([findByName('windows'), findByName('linux')]) { } } } |
When do the changes take effect?
In Kotlin 1.7.20, an error is introduced when using target accessors in the kotlin.targets
block.
For more information, see the corresponding issue in YouTrack.
Changes in Gradle input and output compile tasks
What’s changed?
Kotlin compile tasks no longer inherit the Gradle AbstractCompile
task that has the sourceCompatibility
and targetCompatibility
inputs, making them unavailable in Kotlin users’ scripts.
Other breaking changes in compile tasks:
What’s the best practice now?
Before | Now |
---|---|
The SourceTask.stableSources input is no longer available. | Use the sources input instead. Also, the setSource() methods are still available. |
The sourceFilesExtensions input was removed. | Compile tasks still implement the PatternFilterable interface. Use its methods for filtering Kotlin sources. |
The Gradle destinationDir: File output was deprecated. | Use the destinationDirectory: DirectoryProperty output instead. |
The classpath property of the KotlinCompile task is deprecated. | All compile tasks now use the libraries input for a list of libraries required for compilation. |
When do the changes take effect?
In Kotlin 1.7.20, inputs are not available, the output is replaced, and the classpath
property is deprecated.
For more information, see the corresponding issue in YouTrack.
New configuration names for dependencies on the compilation
What’s changed?
Compilation configurations created by the Kotlin Multiplatform Gradle Plugin received new names.
A target in the Kotlin Multiplatform project has two default compilations, main
and test
. Each of these compilations has its own default source set, for example, jvmMain
and jvmTest
. Previously the configuration names for the test compilation and its default source set were the same, which might lead to a name clash resulting in issues when a configuration marked with platform-specific attributes is included in another configuration.
Now compilation configurations have an extra Compilation
postfix, while projects and plugins that use old hard-coded configuration names no longer compile.
Configuration names for dependencies on the corresponding source set stay the same.
What’s the best practice now?
Before | Now | |
Dependencies of the jvmMain compilation | kotlin jvm<scope> | kotlin jvmCompilation<scope> |
kotlin dependencies { add("jvmImplementation", "foo.bar.baz:1.2.3") } | kotlin dependencies { add("jvmCompilationImplementation", "foo.bar.baz:1.2.3") } | |
Dependencies of the jvmMain source set | kotlin jvmMain<scope> | |
Dependencies of the jvmTest compilation | kotlin jvmTest<scope> | kotlin jvmTestCompilation<scope> |
Dependencies of the jvmTest source set | kotlin jvmTest<scope> |
The available scopes are Api
, Implementation
, CompileOnly
, and RuntimeOnly
.
When do the changes take effect?
In Kotlin 1.8.0, an error is introduced when using old configuration names in hard-coded strings.
For more information, see the corresponding issue in YouTrack.
Deprecated Gradle properties for hierarchical structure support
What’s changed?
Throughout its evolution, Kotlin was gradually introducing the support for hierarchical structure, in multiplatform projects, an ability to have intermediate source sets between the common source set commonMain
and any platform-specific one, for example, jvmMain
.
For the transition period, while the toolchain wasn’t stable enough, a couple of Gradle properties were introduced, allowing granular opt-ins and opt-outs.
Since Kotlin 1.6.20, the hierarchical project structure support has been enabled by default. However, these properties were kept for opting out in case of blocking issues. After processing all the feedback, we’re now starting to phase out those properties completely.
The following properties are now deprecated and will be removed in Kotlin 1.9.20:
kotlin.internal.mpp.hierarchicalStructureByDefault
kotlin.mpp.enableCompatibilityMetadataVariant
kotlin.mpp.hierarchicalStructureSupport
kotlin.mpp.enableGranularSourceSetsMetadata
kotlin.native.enableDependencyPropagation
What’s the best practice now?
- Remove these properties from your
gradle.properties
andlocal.properties
files. - Avoid setting them programmatically in the Gradle build scripts or your Gradle plugins.
- In case deprecated properties are set by some third-party Gradle plugin used in your build, ask the plugin maintainers not to set these properties.
As the default behavior of the Kotlin toolchain doesn’t include such properties since 1.6.20, we don’t expect any serious impact from removing them. Most possible consequences will be visible immediately after the project rebuild.
If you’re a library author and want to be extra safe, check that consumers can work with your library.
When do the changes take effect?
In 1.8.20, the Kotlin Gradle plugin shows a warning if the build sets these properties. Starting with Kotlin 1.9.0, the properties are silently ignored.
In the unlikely case you face some problems after removing these properties, create an issue in YouTrack.
Deprecated support of multiplatform libraries published in the legacy mode
What’s changed?
Previously, we have deprecated the legacy mode in Kotlin Multiplatform projects preventing the publication of “legacy” binaries and encouraged you to migrate your projects to the hierarchical structure.
To continue phasing out “legacy” binaries from the ecosystem, starting with Kotlin 1.9.0, the use of legacy libraries is also discouraged. If your project uses dependencies on legacy libraries, you’ll see the following warning:
The dependency group:artifact:1.0 was published in the legacy mode. Support for such dependencies will be removed in the future
What’s the best practice now?
If you use multiplatform libraries, most of them have already migrated to the “hierarchical structure” mode, so you only need to update the library version. See the documentation of the respective libraries for details.
If the library doesn’t support non-legacy binaries yet, you can contact the maintainers and tell them about this compatibility issue.
If you’re a library author, update the Kotlin Gradle plugin to the latest version and ensure you’ve fixed the deprecated Gradle properties.
The Kotlin team is eager to help the ecosystem migrate, so if you face any issues, don’t hesitate to create an issue in YouTrack.
When do the changes take effect?
- 1.9.0: introduce a deprecation warning for dependencies on legacy libraries
- 1.9.20: raise the warning for dependencies on legacy libraries to an error
- > 1.9.20: the support for dependencies on legacy libraries is removed. Using such dependencies can cause build failures
Deprecated API for adding Kotlin source sets directly to the Kotlin compilation
What’s changed?
The access to KotlinCompilation.source
has been deprecated. A code like this produces a deprecation warning:
kotlin {
jvm()
js()
ios()
sourceSets {
val commonMain by getting
val myCustomIntermediateSourceSet by creating {
dependsOn(commonMain)
}
targets["jvm"].compilations["main"].source(myCustomIntermediateSourceSet)
}
}
What’s the best practice now?
To replace KotlinCompilation.source(someSourceSet)
, add the dependsOn
relation from the default source set of the KotlinCompilation
to someSourceSet
. We recommend referring to the source directly using by getting
, which is shorter and more readable. However, you can also use KotlinCompilation.defaultSourceSet.dependsOn(someSourceSet)
, which is applicable in all cases.
You can change the code above in one of the following ways:
kotlin {
jvm()
js()
ios()
sourceSets {
val commonMain by getting
val myCustomIntermediateSourceSet by creating {
dependsOn(commonMain)
}
// Option #1. Shorter and more readable, use it when possible:
val jvmMain by getting { // Usually, the name of the default source set
// is a simple concatenation of the target name and the compilation name
dependsOn(myCustomIntermediateSourceSet)
}
// Option #2. Generic solution, use it if your build script requires a more advanced approach:
targets["jvm"].compilations["main"].defaultSourceSet.dependsOn(myCustomIntermediateSourceSet)
}
}
When do the changes take effect?
In 1.9.0, the use of KotlinComplation.source
produces a deprecation warning. This API will be removed in Kotlin 1.9.20 and later, leading to “unresolved reference” errors on the KotlinCompilation.source
calls.
Migration from kotlin-js
Gradle plugin to kotlin-multiplatform
Gradle plugin
What’s changed?
Starting with Kotlin 1.9.0, the kotlin-js
Gradle plugin is deprecated. Basically, it duplicated the functionality of the kotlin-multiplatform
plugin with the js()
target and shared the same implementation under the hood. Such overlap created confusion and increased maintenance load on the Kotlin team. We encourage you to migrate to the kotlin-multiplatform
Gradle plugin with the js()
target instead.
What’s the best practice now?
- Remove the
kotlin-js
Gradle plugin from your project and applykotlin-multiplatform
in thesettings.gradle.kts
file if you’re using thepluginManagement
block:
【kotlin-js】
// settings.gradle.kts
pluginManagement {
plugins {
// Remove the following line:
kotlin("js") version "1.9.0"
}
repositories {
// ...
}
}
【kotlin-multiplatform】
// settings.gradle.kts
pluginManagement {
plugins {
// Add the following line instead:
kotlin("multiplatform") version "1.9.0"
}
repositories {
// ...
}
}
In case you’re using a different way of applying plugins, see the Gradle documentation for migration instructions.
- Move your source files from the
main
andtest
folders to thejsMain
andjsTest
folders in the same directory. Adjust dependency declarations:
- We recommend using the
sourceSets
block and configuring dependencies of respective source sets,jsMain
for production dependencies andjsTest
for test dependencies. See Adding dependencies for more details. However, if you want to declare your dependencies in a top-level block, change declarations from
api("group:artifact:1.0")
toadd("jsMainApi", "group:artifact:1.0")
and so on.In this case, make sure that the top-level
dependencies
block comes after thekotlin
block. Otherwise, you’ll get an error “Configuration not found”.
You can change the code in your
build.gradle.kts
file in one of the following ways:- We recommend using the
【kotlin-js】
// build.gradle.kts
plugins {
kotlin("js") version "1.9.0"
}
dependencies {
testImplementation(kotlin("test"))
implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0")
}
kotlin {
js {
// ...
}
}
【kotlin-multiplatform】
// build.gradle.kts
plugins {
kotlin("multiplatform") version "1.9.0"
}
kotlin {
js {
// ...
}
// Option #1. Declare dependencies in the `sourceSets` block:
sourceSets {
val jsMain by getting {
dependencies {
// No need for the `js` prefix here, you can just copy and paste it from the top-level block
implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0")
}
}
}
}
dependencies {
// Option #2. Add the `js` prefix to the dependency declaration:
add("jsTestImplementation", kotlin("test"))
}
- The DSL provided by the Kotlin Gradle plugin inside the
kotlin
block remains unchanged in most cases. However, if you were referring to low-level Gradle entities, like tasks and configurations, by names, you now need to adjust them, usually by adding thejs
prefix. For example, you can find thebrowserTest
task under the namejsBrowserTest
.
When do the changes take effect?
In 1.9.0, the use of the kotlin-js
Gradle plugin produces a deprecation warning.
Rename of android
target to androidTarget
What’s changed?
We continue our efforts to stabilize Kotlin Multiplatform. An essential step in this way is to provide first-class support for the Android target. In the future, this support will be provided via a separate plugin, developed by the Android team from Google.
To open the way for the new solution from Google, we’re renaming the android
block to androidTarget
in the current Kotlin DSL in 1.9.0. This is a temporary change that is necessary to free the short android
name for the upcoming DSL from Google.
What’s the best practice now?
Rename all the occurrences of the android
block to androidTarget
. When the new plugin for the Android target support is available, migrate to the DSL from Google. It will be the preferred option to work with Android in Kotlin Multiplatform projects.
When do the changes take effect?
In Kotlin 1.9.0, a deprecation warning is introduced when the android
name is used in Kotlin Multiplatform projects.