I’m working on a Kotlin Multiplatform Mobile (KMM) project where I publish shared modules to a local or remote Maven repository. My module targets:
android
jvm
iosX64
iosArm64
iosSimulatorArm64
Locally, running the following command on my MacBook:
./gradlew publishToMavenLocal
generates the correct output structure in .m2/repository/
, including the iOS-specific folders:
network-iosarm64/
network-iosx64/
network-iossimulatorarm64/
However, when I run this on Bamboo CI, using the same Gradle project and the same command:
./gradlew publishToMavenLocal -Dmaven.repo.local=$SCRIPT_DIR/repository
…I only see Android and JVM outputs, like:
network/
network-android/
But no iOS artifacts are generated at all.
Originally this was a Linux agent, but I switched it to a macOS Bamboo agent to support iOS builds. This was confirmed by printing uname -a
in the script and seeing Darwin output.
My Gradle script also includes this to build iOS frameworks:
./gradlew linkReleaseFrameworkIosArm64 linkReleaseFrameworkIosX64 linkReleaseFrameworkIosSimulatorArm64
And I also tried:
./gradlew assembleNetworkReleaseXCFramework
Still, no iOS folders are published to the Maven repository on CI.
My Gradle build.gradle.kts
:
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
id("org.jetbrains.kotlin.multiplatform")
id("com.android.library")
alias(libs.plugins.kotlinxSerialization)
id("com.jfrog.artifactory") version "4.24.23"
id("co.touchlab.skie") version "0.10.1"
id("maven-publish")
}
kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
freeCompilerArgs += listOf("-Xskip-metadata-version-check")
}
}
publishLibraryVariants("release", "debug")
}
jvm()
val xcf = XCFramework("Network")
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "Network"
isStatic = false
xcf.add(this)
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.client.serialization.json)
implementation(libs.kodein)
implementation(libs.kermit.logging)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.ktor.client.logging)
implementation(libs.kotlinx.serialization.json)
implementation(libs.apollo.runtime)
}
}
val androidMain by getting {
dependencies {
implementation(libs.ktor.client.okhttp)
}
}
val jvmMain by getting {}
val iosX64Main by getting {
dependencies {
implementation(libs.ktor.client.darwin)
}
}
val iosArm64Main by getting {
dependencies {
implementation(libs.ktor.client.darwin)
}
}
val iosSimulatorArm64Main by getting {
dependencies {
implementation(libs.ktor.client.darwin)
}
}
}
}
android {
namespace = "com.xxxx.kmp.network"
compileSdk = libs.versions.android.compileSdk.get().toInt()
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
}
}
group = "com.xxxx.kmp.network"
version = "1.0.0"
artifactory {
publish {
defaults {
setPublishPom(true)
setPublishArtifacts(true)
}
}
}
publishing {
publications {
withType<MavenPublication>().configureEach {
// Optional: customize POM if needed
}
}
}