Claude
Skills
Sign in
Back

gradle-kmp

Included with Lifetime
$97 forever

Gradle build system for Kotlin Multiplatform projects. Covers settings.gradle.kts, version catalogs (libs.versions.toml), KMP plugin configuration, source set hierarchy, target binaries (JAR, AAR, XCFramework, JS bundle), publishing (Maven Central, GitHub Packages), CI presets (build matrix, caching, parallel execution), composite builds, and dependency management. USE WHEN: user mentions "Gradle KMP", "settings.gradle.kts", "version catalog", "libs.versions.toml", "XCFramework Gradle", "publishToMavenCentral", "Gradle composite build", "Gradle build cache", "configuration cache", "Gradle CI" DO NOT USE FOR: Cross-compiling Rust crates - use `build-tools/rust-cross-compile` DO NOT USE FOR: Reproducible builds spec - use `infrastructure/reproducible-builds` DO NOT USE FOR: KMP source code patterns - use `mobile/kotlin-multiplatform`

Backend & APIs

What this skill does

# Gradle for Kotlin Multiplatform

> **Deep Knowledge**: Use `mcp__documentation__fetch_docs` with technology: `gradle-kmp` or `gradle`.

## settings.gradle.kts

```kotlin
pluginManagement {
    repositories {
        google { content { includeGroupByRegex("com\\.android.*"); includeGroupByRegex("androidx.*") } }
        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
        // For UniFFI KMP fork
        maven("https://maven.ubique.ch/snapshots")
    }
}

plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
    id("com.gradle.develocity") version "3.18.1"          // optional: build scan + cache
}

develocity {
    buildScan {
        termsOfUseUrl = "https://gradle.com/terms-of-service"
        termsOfUseAgree = "yes"
        publishing.onlyIf { System.getenv("CI") != null }
    }
}

rootProject.name = "BHODL"
include(":shared")
include(":apps:android")
include(":apps:desktop")
```

## Version Catalog (`gradle/libs.versions.toml`)

Single source of truth for dependency versions. Replaces ad-hoc `ext` blocks.

```toml
[versions]
kotlin = "2.2.0"
agp = "8.7.0"
compose-multiplatform = "1.8.0"
ktor = "3.0.0"
coroutines = "1.10.0"
serialization = "1.7.3"
sqldelight = "2.0.2"
koin = "4.0.0"

[libraries]
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqldelight" }
sqldelight-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }

[bundles]
ktor-common = ["ktor-core", "ktor-content-negotiation", "ktor-serialization"]

[plugins]
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
compose = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
```

Use:

```kotlin
plugins {
    alias(libs.plugins.kotlin.multiplatform)
}

dependencies {
    implementation(libs.coroutines.core)
    implementation(libs.bundles.ktor.common)
}
```

## gradle.properties

```properties
# JVM
org.gradle.jvmargs=-Xmx4g -XX:+UseG1GC -XX:MaxMetaspaceSize=1g

# Performance
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true
org.gradle.configuration-cache=true                # Gradle 8+ stable
org.gradle.unsafe.configuration-cache-problems=warn

# Kotlin
kotlin.code.style=official
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.mpp.enableCInteropCommonization=true
kotlin.native.cacheKind=static                      # Faster Native build
kotlin.native.ignoreDisabledTargets=true            # Skip iOS targets on Linux

# Android
android.useAndroidX=true
android.nonTransitiveRClass=true
android.nonFinalResIds=true

# Compose
org.jetbrains.compose.experimental.uikit.enabled=true
```

## Source Set Hierarchy

KMP 1.9+ has a default template — most projects don't need custom intermediate sets.

```kotlin
kotlin {
    androidTarget()
    jvm("desktop")
    listOf(iosX64(), iosArm64(), iosSimulatorArm64()).forEach { /* ... */ }

    sourceSets {
        commonMain.dependencies {
            implementation(libs.coroutines.core)
        }
        androidMain.dependencies {
            implementation(libs.ktor.okhttp)
        }
        iosMain.dependencies {
            implementation(libs.ktor.darwin)
        }
        commonTest.dependencies {
            implementation(kotlin("test"))
            implementation(libs.coroutines.test)
        }
    }
}
```

For custom intermediate set (e.g., shared between Android + Desktop):

```kotlin
sourceSets {
    val jvmCommonMain by creating {
        dependsOn(commonMain.get())
    }
    androidMain.get().dependsOn(jvmCommonMain)
    getByName("desktopMain").dependsOn(jvmCommonMain)
}
```

## XCFramework Output

```kotlin
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework

kotlin {
    val xcf = XCFramework("Shared")
    listOf(iosX64(), iosArm64(), iosSimulatorArm64()).forEach { target ->
        target.binaries.framework {
            baseName = "Shared"
            isStatic = true
            xcf.add(this)
            export(libs.coroutines.core.get())          // expose to Swift consumers
        }
    }
}
```

Build:
```bash
./gradlew :shared:assembleSharedXCFramework
# Output: shared/build/XCFrameworks/release/Shared.xcframework
```

## CocoaPods Plugin

```kotlin
plugins {
    kotlin("native.cocoapods") version "2.2.0"
}

kotlin {
    cocoapods {
        version = "1.0.0"
        summary = "Shared KMP module"
        homepage = "https://github.com/example/bhodl"
        ios.deploymentTarget = "16.0"
        framework {
            baseName = "Shared"
            isStatic = true
        }
        // Optionally consume CocoaPods deps from Kotlin
        pod("FirebaseAuth") { version = "11.0.0" }
    }
}
```

```bash
./gradlew :shared:podPublishXCFramework
cd apps/ios && pod install
```

## Embed-and-Sign for Xcode

Auto-build framework when Xcode builds:

```bash
# In Xcode build phase:
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode
```

The `embedAndSignAppleFrameworkForXcode` task is auto-registered by KMP plugin.

## Kotlin Compiler Options

```kotlin
kotlin {
    targets.all {
        compilations.all {
            compilerOptions.configure {
                freeCompilerArgs.addAll(
                    "-Xexpect-actual-classes",
                    "-Xcontext-parameters",
                    "-opt-in=kotlin.RequiresOptIn",
                    "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
                    "-Xjsr305=strict",
                )
            }
        }
    }
    androidTarget {
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_17)
        }
    }
    jvm("desktop") {
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_17)
        }
    }
}
```

## Maven Publishing

```kotlin
plugins {
    `maven-publish`
    signing
}

group = "com.bhodl"
version = "1.0.0"

publishing {
    repositories {
        maven {
            name = "GitHubPackages"
            url = uri("https://maven.pkg.github.com/bhodl/shared")
            credentials {
                username = providers.gradleProperty("gpr.user").orNull
                    ?: System.getenv("GITHUB_ACTOR")
                password

Related in Backend & APIs