Setelah kode KMP ditulis dan diuji, langkah akhir adalah membangun artifact dan mendistribusikannya. KMP menghasilkan banyak artifact dari satu source—JAR untuk JVM, AAR untuk Android, Framework untuk iOS, KLIB untuk Native, file JS untuk JavaScript, dan artifact metadata untuk resolusi konsumen. Setiap artifact memiliki pipeline build, distribusi, dan signature yang berbeda. Pada chapter ini kita akan melihat pipeline build untuk delapan target, struktur artifact yang dihasilkan, dan strategi distribusi ke berbagai repository.
Pipeline Build per Target #
Build KMP dimulai dengan langkah umum—lint, compile commonMain menjadi metadata, lalu compile per-target source set. Setelah itu, langkah spesifik per target dijalankan: JVM memaket JAR, Android memaket AAR, iOS membangun XCFramework, JS menjalankan webpack.
// JVM: ./gradlew :lib:assembleJvmJar
// Android: ./gradlew :lib:assembleReleaseAar
// iOS: ./gradlew :lib:assembleIosArm64XCFramework
// JS: ./gradlew :lib:jsBrowserProductionWebpackUntuk publikasi lengkap, satu perintah ./gradlew publish memicu kompilasi semua target sekaligus.
Artifact per Target #
Setiap target menghasilkan artifact dengan format berbeda. JVM menghasilkan JAR yang berisi bytecode; konsumen JVM menambahkannya ke classpath. Android menghasilkan AAR yang berisi bytecode plus resource Android; konsumen Android menambahkannya ke dependencies. iOS menghasilkan framework yang berisi native binary; konsumen iOS menambahkannya via CocoaPods atau SPM. JS menghasilkan file JS atau NPM package.
| Target | Artifact | Distribusi Umum |
|---|---|---|
| JVM | library.jar | Maven Central |
| Android | library.aar | Maven Central, Google Maven |
| iOS (Arm64/X64/Sim) | library.framework | CocoaPods, Maven Central |
| JS | library.js atau npm package | npm registry |
| Native (Linux/Mac/Win) | library.klib | Maven Central |
| Metadata | library-metadata.jar | Maven Central |
Simulasi Build Pipeline #
Demo berikut mensimulasikan pipeline build lengkap untuk delapan target—JVM, Android, tiga target iOS, JS, Linux x64, dan metadata. Setiap target memiliki langkah build, artifact, dan distribusi sendiri.
// multiplatform_deployment.kt
// Distribusi artifact KMP per target: iOS framework, Android AAR, JVM JAR.
// Demo: simulasi build pipeline + ukuran artifact + distribusi.
data class ArtifactOutput(
val target: String,
val artifactType: String,
val filename: String,
val ukuranKB: Int,
val distribusi: String,
val langkahBuild: List<String>
)
data class HasilBuild(
val versi: String,
val artifacts: List<ArtifactOutput>
) {
fun totalUkuranKB(): Int = artifacts.sumOf { it.ukuranKB }
fun ringkasan(): String {
val sb = StringBuilder()
sb.appendLine("Versi : $versi")
sb.appendLine("Total target: ${artifacts.size}")
sb.appendLine("Total ukuran: ${totalUkuranKB()} KB")
sb.appendLine()
sb.appendLine("Artifacts:")
for (a in artifacts) {
sb.appendLine(" ${a.target.padEnd(20)} ${a.artifactType.padEnd(10)} ${a.filename.padEnd(40)} ${a.ukuranKB.toString().padStart(5)} KB")
}
return sb.toString().trimEnd()
}
}
class BuildPipeline(private val versi: String) {
private val langkahUmum = listOf(
"1. Validasi source code (lint)",
"2. Compile commonMain -> metadata",
"3. Compile per-target source set",
"4. Run commonTest di semua target",
"5. Sign artifact (jika dipublikasi)"
)
fun jalankan(targetDefinisi: List<Triple<String, String, Int>>): HasilBuild {
println("=== Build Pipeline versi $versi ===")
println()
println("Langkah umum:")
langkahUmum.forEach { println(" $it") }
println()
val artifacts = mutableListOf<ArtifactOutput>()
for ((target, tipe, ukuran) in targetDefinisi) {
println("Build target: $target")
val langkah = langkahBuild(target, tipe)
langkah.forEach { println(" - $it") }
val artifact = ArtifactOutput(
target = target,
artifactType = tipe,
filename = namaFile(target, tipe),
ukuranKB = ukuran,
distribusi = distribusi(target),
langkahBuild = langkah
)
artifacts.add(artifact)
println(" Output: ${artifact.filename} (${artifact.ukuranKB} KB)")
println(" Distribusi: ${artifact.distribusi}")
println()
}
return HasilBuild(versi, artifacts)
}
private fun langkahBuild(target: String, tipe: String): List<String> = when (target) {
"jvm" -> listOf(
"compileKotlinJvm",
"packageJvmJar",
"shadowJarRuntime (jika diperlukan)"
)
"android" -> listOf(
"compileReleaseKotlinAndroid",
"bundleReleaseAar",
"signReleaseAar"
)
"iosArm64", "iosX64", "iosSimulatorArm64" -> listOf(
"compileKotlin${target.replaceFirstChar { it.uppercase() }}",
"linkDebugFramework${target.replaceFirstChar { it.uppercase() }}",
"assemble${target.replaceFirstChar { it.uppercase() }}XCFramework"
)
"js" -> listOf(
"compileKotlinJs",
"browserProductionWebpack (atau esbuild)",
"bundleJs"
)
else -> listOf("compileKotlin${target.replaceFirstChar { it.uppercase() }}")
}
private fun namaFile(target: String, tipe: String): String {
val base = "kmp-util-$versi"
return when (tipe) {
"JAR" -> "$base.jar"
"AAR" -> "$base.aar"
"Framework" -> "$base-${target}.framework"
"KLIB" -> "$base-${target}.klib"
"JS" -> "$base.js"
"Metadata" -> "$base-metadata.jar"
else -> "$base-${target}.bin"
}
}
private fun distribusi(target: String): String = when (target) {
"jvm" -> "Maven Central + GitHub Releases"
"android" -> "Maven Central + Google Maven"
"iosArm64", "iosX64", "iosSimulatorArm64" -> "CocoaPods + Maven Central"
"js" -> "npm registry + GitHub Releases"
else -> "Maven Central"
}
}
fun main() {
val pipeline = BuildPipeline("1.0.0")
val targetDefinisi = listOf(
Triple("jvm", "JAR", 85),
Triple("android", "AAR", 120),
Triple("iosArm64", "Framework", 95),
Triple("iosX64", "Framework", 95),
Triple("iosSimulatorArm64", "Framework", 95),
Triple("js", "JS", 45),
Triple("linuxX64", "KLIB", 30),
Triple("metadata", "Metadata", 20)
)
val hasil = pipeline.jalankan(targetDefinisi)
println("=== Hasil Build ===")
println(hasil.ringkasan())
println()
println("=== Distribusi per artifact ===")
for (a in hasil.artifacts) {
println("${a.target.padEnd(22)} -> ${a.distribusi}")
}
println()
println("=== Verifikasi artifact siap rilis ===")
val semuanyaSiap = hasil.artifacts.all { it.ukuranKB > 0 }
println("Semua artifact punya ukuran > 0: $semuanyaSiap")
println("Total artifact yang dibangun : ${hasil.artifacts.size}")
println("Versi rilis : ${hasil.versi}")
println()
println("=== Ringkasan distribusi ===")
println("Maven Central : ${hasil.artifacts.count { "Maven" in it.distribusi }} artifact")
println("CocoaPods : ${hasil.artifacts.count { "CocoaPods" in it.distribusi }} artifact")
println("npm registry : ${hasil.artifacts.count { "npm" in it.distribusi }} artifact")
println("GitHub Releases: ${hasil.artifacts.count { "GitHub" in it.distribusi }} artifact")
}Output yang Dihasilkan:
=== Build Pipeline versi 1.0.0 ===
Langkah umum:
1. Validasi source code (lint)
2. Compile commonMain -> metadata
3. Compile per-target source set
4. Run commonTest di semua target
5. Sign artifact (jika dipublikasi)
Build target: jvm
- compileKotlinJvm
- packageJvmJar
- shadowJarRuntime (jika diperlukan)
Output: kmp-util-1.0.0.jar (85 KB)
Distribusi: Maven Central + GitHub Releases
Build target: android
- compileReleaseKotlinAndroid
- bundleReleaseAar
- signReleaseAar
Output: kmp-util-1.0.0.aar (120 KB)
Distribusi: Maven Central + Google Maven
Build target: iosArm64
- compileKotlinIosArm64
- linkDebugFrameworkIosArm64
- assembleIosArm64XCFramework
Output: kmp-util-1.0.0-iosArm64.framework (95 KB)
Distribusi: CocoaPods + Maven Central
Build target: iosX64
- compileKotlinIosX64
- linkDebugFrameworkIosX64
- assembleIosX64XCFramework
Output: kmp-util-1.0.0-iosX64.framework (95 KB)
Distribusi: CocoaPods + Maven Central
Build target: iosSimulatorArm64
- compileKotlinIosSimulatorArm64
- linkDebugFrameworkIosSimulatorArm64
- assembleIosSimulatorArm64XCFramework
Output: kmp-util-1.0.0-iosSimulatorArm64.framework (95 KB)
Distribusi: CocoaPods + Maven Central
Build target: js
- compileKotlinJs
- browserProductionWebpack (atau esbuild)
- bundleJs
Output: kmp-util-1.0.0.js (45 KB)
Distribusi: npm registry + GitHub Releases
Build target: linuxX64
- compileKotlinLinuxX64
Output: kmp-util-1.0.0-linuxX64.klib (30 KB)
Distribusi: Maven Central
Build target: metadata
- compileKotlinMetadata
Output: kmp-util-1.0.0-metadata.jar (20 KB)
Distribusi: Maven Central
=== Hasil Build ===
Versi : 1.0.0
Total target: 8
Total ukuran: 585 KB
Artifacts:
jvm JAR kmp-util-1.0.0.jar 85 KB
android AAR kmp-util-1.0.0.aar 120 KB
iosArm64 Framework kmp-util-1.0.0-iosArm64.framework 95 KB
iosX64 Framework kmp-util-1.0.0-iosX64.framework 95 KB
iosSimulatorArm64 Framework kmp-util-1.0.0-iosSimulatorArm64.framework 95 KB
js JS kmp-util-1.0.0.js 45 KB
linuxX64 KLIB kmp-util-1.0.0-linuxX64.klib 30 KB
metadata Metadata kmp-util-1.0.0-metadata.jar 20 KB
=== Distribusi per artifact ===
jvm -> Maven Central + GitHub Releases
android -> Maven Central + Google Maven
iosArm64 -> CocoaPods + Maven Central
iosX64 -> CocoaPods + Maven Central
iosSimulatorArm64 -> CocoaPods + Maven Central
js -> npm registry + GitHub Releases
linuxX64 -> Maven Central
metadata -> Maven Central
=== Verifikasi artifact siap rilis ===
Semua artifact punya ukuran > 0: true
Total artifact yang dibangun : 8
Versi rilis : 1.0.0
=== Ringkasan distribusi ===
Maven Central : 7 artifact
CocoaPods : 3 artifact
npm registry : 1 artifact
GitHub Releases: 2 artifactMari kita bedah bagian kunci dari kode di atas:
data class ArtifactOutput: model untuk satu artifact hasil build—target, jenis artifact (JAR/AAR/Framework/KLIB/JS/Metadata), nama file, ukuran, distribusi, dan daftar langkah build yang dijalankan.data class HasilBuild: agregat hasil build untuk satu versi. Menyimpan daftar artifact dan menyediakanringkasan()untuk laporan. MethodtotalUkuranKB()menghitung total ukuran semua artifact.class BuildPipeline: kelas yang mengelola pipeline build. Methodjalankan(targetDefinisi)menerima daftar target dengan ukuran, lalu menjalankan langkah umum + langkah spesifik per target.langkahBuild(target, tipe): mengembalikan daftar Gradle task per target. Untuk JVM:compileKotlinJvm,packageJvmJar,shadowJarRuntime. Untuk iOS:compileKotlinIosArm64,linkDebugFrameworkIosArm64,assembleIosArm64XCFramework. Tiga task iOS inilah yang dipakai Gradle untuk membangun framework.namaFile(target, tipe): menghasilkan nama file artifact berdasarkan konvensi Maven. JVM menghasilkankmp-util-1.0.0.jar, iOS menghasilkankmp-util-1.0.0-iosArm64.framework, metadata menghasilkankmp-util-1.0.0-metadata.jar.distribusi(target): menentukan repository distribusi per target. JVM dan Android ke Maven Central; iOS ke CocoaPods + Maven Central; JS ke npm registry; Native ke Maven Central.- Output menunjukkan 8 artifact: total ukuran 585 KB. Maven Central menerima 7 artifact (semua kecuali JS), CocoaPods menerima 3 artifact (iOS), npm menerima 1 (JS).
Strategi Distribusi #
Distribusi artifact KMP mengikuti pola ekosistem target. Maven Central adalah repository umum untuk JVM, Android, Native, dan metadata. CocoaPods atau Swift Package Manager adalah repository native untuk iOS. npm registry adalah repository untuk JavaScript.
./gradlew publishAllPublicationsToSonatypeRepository
# Setelah staging disetujui:
./gradlew closeAndReleaseSonatypeStagingRepository# Hasilkan podspec dari build.gradle.kts
./gradlew :lib:podPublish
# atau manual publikasi CocoaPods
pod trunk push KmpUtil.podspec./gradlew :lib:jsBrowserProductionWebpack
npm publish build/js/packages/kmp-utilCI/CD untuk Multi-target #
Pipeline CI/CD untuk KMP biasanya membangun semua target di setiap commit. GitHub Actions contohnya: lint → test commonTest di JVM → build artifact untuk semua target → upload artifact → publish ke Maven Central saat tag. Build iOS framework memerlukan runner macOS—Linux runner tidak dapat membangun iOS framework.
jobs:
build-jvm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { java-version: 21 }
- run: ./gradlew :lib:assembleJvmJar
build-ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- run: ./gradlew :lib:assembleIosArm64XCFrameworkReferensi Lanjutan #
- Publish libraries — dokumentasi publikasi dan distribusi artefak KMP ke target masing-masing
Penutup #
Deployment KMP melibatkan banyak artifact dan repository. Pipeline build mengikuti pola KMP—langkah umum dulu, lalu langkah spesifik per target. Distribusi ke Maven Central, CocoaPods, dan npm registry memungkinkan konsumen di setiap platform menambahkan library dengan satu baris dependency. Dengan ini, kita menutup section KMP dengan pemahaman lengkap dari konsep hingga distribusi.