The release of Kotlin 1.9.20 marked a significant milestone for Kotlin Multiplatform enthusiasts, as this update moved Kotlin Multiplatform to Stable. Kotlin 1.9.20 introduces several notable features and enhancements. Among these updates, the new source set hierarchy template by the Kotlin Gradle Plugin stands out to me for its ability to simplify configuration complexities. It was launched as experimental in Kotlin 1.8.20 and has been made default in Kotlin 1.9.20.
Simplified iOS Target Configuration
In the common Kotlin Multiplatform project set-up, you would have seen specific source set setup for two or three iOS targets like for X64, Arm64.
Instead of the common and confusing 'ios()' target, one must always declare specific targets like 'iosArm64()' as required. Once one of the iOS targets is declared, the default template would automatically create iosMain
source set. So no more val iosMain by creating
boilerplate required.
Before 1.9.20 | After 1.9.20 |
kotlin { ios() iosSimulatorArm64() sourceSets { val commonMain by getting val iosMain by creating { dependsOn(commonMain) } val iosX64Main by getting { dependsOn(iosMain) } val iosArm64Main by getting { dependsOn(iosMain) } val iosSimulatorArm64Main by getting { dependsOn(iosMain) } } } |
kotlin { iosX64() iosArm64() iosSimulatorArm64() // The iosMain source set is now created automatically // You can directly use the reference now iosMain.dependencies { implementation("...") } } |
If you've an old KMP project and still have reference of
darwinMain
, you can simply rename it toappleMain
now as that encapsulates all other apple targets.
Checkout the full hierarchy template!
Streamlined Custom Source Sets
Managing custom source sets in Kotlin Multiplatform projects is now more straightforward with Kotlin 1.9.20. The update simplifies the process of setting up dependencies between source sets, reducing the need for extensive boilerplate code and enhancing overall readability.
For example, let's assume that you already have kotlin/JS
support with jsMain/jsTest
source sets. Now, you want to add kotlinWasm
support. Since wasmJs
and kotlinJs
can share a common source, you want to introduce a new jsAndWasmJsMain
parent source set for common code sharing between them. Instead of using by creating
, you can declare new custom source set inside applyDefaultHierarchyTemplate {}
.
Before 1.9.20 | After 1.9.20 |
kotlin { js() wasmJs() sourceSets { val commonMain by getting val commonTest by getting val jsAndWasmJsMain by creating { dependsOn(commonMain) getByName("jsMain").dependsOn(this) getByName("wasmMain").dependsOn(this) } val jsAndWasmJsTest by creating { dependsOn(commonTest) getByName("jsTest").dependsOn(this) getByName("wasmTest").dependsOn(this) } } } |
kotlin { js() wasmJs() // This is an experimental API, so opt-in is required @OptIn(ExperimentalKotlinGradlePluginApi::class) applyDefaultHierarchyTemplate { // create a new group that // depends on `common` common { // Define group name without // `Main` as suffix group("jsAndWasmJs") { // Provide which targets would // be part of this group withJs() withWasm() } } } // Now you will already have `jsAndWasmJsMain` } |
Manually apply the template
Note that if you have explict by creating
usage for custom source set then defauly template hierarchy would not apply automatically and you would see warning about the same.
w: The Default Kotlin Hierarchy Template was not applied to 'project ':XXX'':
Explicit .dependsOn() edges were configured for the following source sets:
[XXX]
In order to get the default hierachy, you would have to call applyDefaultHierarchyTemplate()
manually once you declare all the targets.
Also, checkout Opting Out of Default Templates
Enhanced Code Completion Support
The updated source set hierarchy template enhances code completion support in the IDE. Developers can now utilize predefined source sets directly, eliminating the need for repetitive declarations and enhancing overall development efficiency.
So even in simple cases, you can still clean up your source set declarations, and make them more readable.
Default before 1.9.20 | With 1.9.20 |
kotlin { // ... sourceSets { val commonMain by getting { dependencies { // ... } } val androidMain by getting { dependencies { // ... } } val iosMain by creating { dependencies { // ... } } } } |
kotlin { // ... sourceSets { commonMain.dependencies { // ... } androidMain.dependencies { // .. } iosMain.dependencies { // ... } } } |
Android instrumented test changes
With introduction of the new Android source set layout (now default starting Kotlin 1.9.0), the androidInstrumentedTest
source set doesn't automatically depend on commonTest
.
In order to have that dependency set-up, with 1.9.0, you would need to explicitly set the dependsOn
relationship between them, and with 1.9.20, you now just need to set the correct sourceSetTree
property inside android target.
With 1.9.0 | With 1.9.20 |
kotlin { // ... sourceSets { val commonTest by getting val androidInstrumentedTest by getting { dependsOn(commonTest) } } } |
kotlin { androidTarget { // This is an experimental API, so opt-in is required @OptIn(ExperimentalKotlinGradlePluginApi::class) instrumentedTestVariant { // This makes instrumented tests depend on commonTest source sourceSetTree.set(KotlinSourceSetTree.test) } } } |
Opting Out of Default Templates
For projects with existing complex source set hierarchies, Kotlin 1.9.20 offers the flexibility to opt-out of the default template. By setting kotlin.mpp.applyDefaultHierarchyTemplate=false
in the gradle.properties
, developers can retain their current configurations.
Conclusion
As you transition to Kotlin 1.9.20, consider how these improvements can optimize your Gradle configurations and enhance your multiplatform development workflow.
We recently updated most of our OSS projects to use Kotlin 1.9.22, leveraging the benefits of these enhancements. We hope you find the transition as beneficial as we have.
Share your experiences and questions with us on #touchlab-tools channel on Kotlin Slack. Also, you can reach out to me at @shaktiman_droid on Twitter(X) or LinkedIn. Happy coding!
Top comments (0)