Gradle in a KMP Project¶
If you've built Android apps, you already know Gradle as the build system. In a KMP project, Gradle takes on a larger role — it manages not just the Android build, but also the compilation of shared Kotlin code and the integration with Xcode for iOS.
What Gradle does in a KMP project¶
- Compiles shared Kotlin code into the right output for each platform
- Manages dependencies across modules (
shared,composeApp,iosApp) - Produces an iOS framework (
.framework) from thesharedmodule that Xcode can consume - Runs tasks like tests, code generation, and packaging
The file structure¶
A KMP project has multiple build.gradle.kts files — one per module:
SessionClick/
├── build.gradle.kts ← root build file (project-wide config)
├── settings.gradle.kts ← declares which modules exist
├── gradle.properties ← global properties (versions, flags)
├── shared/
│ └── build.gradle.kts ← shared module config (the most important one)
└── composeApp/
└── build.gradle.kts ← Android app config
The iosApp/ folder is an Xcode project — it has no build.gradle.kts. Gradle produces a framework that Xcode picks up, but Xcode has its own build system for the rest.
settings.gradle.kts¶
This is the entry point. It tells Gradle which modules are part of the project:
The shared module build file¶
This is where KMP is actually configured:
kotlin {
androidTarget() // compile for Android
iosX64() // compile for iOS simulator (Intel Mac)
iosArm64() // compile for real iOS device
iosSimulatorArm64() // compile for iOS simulator (Apple Silicon Mac)
sourceSets {
commonMain.dependencies {
// dependencies available on all platforms
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
}
androidMain.dependencies {
// Android-only dependencies
}
iosMain.dependencies {
// iOS-only dependencies (rare — usually using Apple frameworks directly)
}
}
}
How Gradle produces the iOS framework¶
When you build the project, Gradle compiles the shared module into a native iOS framework called shared.framework. Xcode is configured to run a Gradle task as part of its build phase to get this framework.
This is why you must have a working Gradle setup before the iOS app can build — Xcode depends on it.
gradle.properties¶
This file holds global configuration. In KMP projects, two entries are important:
You may also see KMP-specific flags here, like enabling the new Kotlin/Native memory model.
Version catalogs (libs.versions.toml)¶
Modern KMP projects use a version catalog to centralise dependency versions:
[versions]
kotlin = "2.0.0"
kotlinx-serialization = "1.7.0"
[libraries]
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
[plugins]
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
Instead of hardcoding version strings in each build.gradle.kts, you reference them as libs.kotlinx.serialization.json. This makes keeping versions consistent across modules much easier.
Common Gradle tasks in KMP¶
| Task | What it does |
|---|---|
./gradlew build |
Build all modules |
./gradlew :shared:build |
Build only the shared module |
./gradlew :composeApp:assembleDebug |
Build Android debug APK |
./gradlew :shared:iosArm64Binaries |
Compile shared code for real iOS device |
./gradlew test |
Run all tests |
./gradlew :shared:commonTest |
Run only shared module tests |