Panduan Kotlin Multiplatform (KMP) di kotlinlang.org/docs/multiplatform.html menjelaskan cara menulis satu kode Kotlin dan mengkompilasinya ke beberapa target: JVM, Android, iOS, JS, dan Native. KMP bukan framework UI lintas-platform seperti Flutter; KMP berbagi logika bisnis, sementara UI tetap native (Compose, SwiftUI, atau React). Pada chapter ini kita memetakan struktur proyek KMP, mendemokan mekanisme expect/actual lewat kontrak interface, dan menunjukkan kapan KMP tidak cocok dipakai.

Struktur Proyek KMP #

Proyek KMP terdiri dari modul shared/ dengan beberapa source set, ditambah modul aplikasi per target:

Source setTujuan
commonMain/Kode yang dipakai semua target; boleh deklarasi expect
jvmMain/Implementasi actual untuk backend JVM
androidMain/Implementasi actual untuk Android
iosMain/Implementasi actual untuk iOS (interop Swift)
jsMain/Implementasi actual untuk JavaScript

Tiap actual menyediakan implementasi kontrak expect yang dideklarasikan di commonMain. Kompilator memverifikasi bahwa setiap expect punya actual di setiap target yang dikonfigurasi.

Demo expect/actual via Interface #

Karena kompilator JVM tidak menerima expect/actual di luar proyek KMP, cuplikan berikut memodelkan kontrak tersebut lewat interface dan implementasi platform-specific. Pendekatan ini setara secara konseptual — di proyek KMP nyata, kompilator otomatis merakit interface dari deklarasi expect:

kotlin
// panduan_kotlin_multiplatform.kt
// Tour singkat Panduan Kotlin Multiplatform (KMP):
// https://kotlinlang.org/docs/multiplatform.html
//
// KMP memungkinkan kita menulis kode Kotlin sekali dan mengkompilasinya
// ke beberapa target: JVM (backend), Android, iOS, JS, Native.
//
// File ini mendemokan konsep expect/actual lewat interface dan implementasi
// platform-specific. Pendekatan ini setara secara konseptual dengan mekanisme
// expect/actual yang dipakai KMP, namun dapat dijalankan pada JVM biasa.

// 1. Common code — kontrak yang dipakai lintas platform
interface PlatformInfo {
    fun namaPlatform(): String
    fun sekarangEpochMillis(): Long
}

// 2. Common code — bisnis logika yang memakai kontrak platform
class SalamUniversal(private val platform: PlatformInfo) {
    fun sapa(nama: String): String = "Halo $nama dari ${platform.namaPlatform()}"
}

// 3. Common data class — bisa dipakai lintas platform
data class Metrik(val platform: String, val nilai: Double)

// 4. Common helper — fungsi murni tanpa dependensi platform
fun rataRata(angka: List<Double>): Double =
    if (angka.isEmpty()) 0.0 else angka.sum() / angka.size

// === JVM actual implementation (mewakili jvmMain source set) ===
object JvmPlatform : PlatformInfo {
    override fun namaPlatform(): String = "JVM (Kotlin 2.0.21)"
    override fun sekarangEpochMillis(): Long = 1700000000000L  // nilai beku
}

fun main() {
    println("=== Panduan Kotlin Multiplatform ===")
    println("Sumber: https://kotlinlang.org/docs/multiplatform.html")
    println()

    val platform: PlatformInfo = JvmPlatform

    println("--- 1. Identitas platform ---")
    println("Platform: ${platform.namaPlatform()}")
    println("Epoch millis (beku untuk determinisme): ${platform.sekarangEpochMillis()}")

    println()
    println("--- 2. SalamUniversal (common code) ---")
    val s = SalamUniversal(platform)
    println(s.sapa("Budi"))
    println(s.sapa("Siti"))

    println()
    println("--- 3. Metrik data class (common) ---")
    val metrik = listOf(
        Metrik("JVM", 1.5),
        Metrik("Android", 2.3),
        Metrik("iOS", 1.8)
    )
    metrik.forEach { println("  $it") }
    println("Rata-rata nilai: ${rataRata(metrik.map { it.nilai })}")

    println()
    println("--- 4. Struktur proyek KMP ---")
    val struktur = listOf(
        "shared/",
        "  src/",
        "    commonMain/kotlin/   -> kode yang dipakai semua target",
        "    jvmMain/kotlin/      -> actual untuk JVM (backend)",
        "    androidMain/kotlin/  -> actual untuk Android",
        "    iosMain/kotlin/      -> actual untuk iOS (Swift interop)",
        "    jsMain/kotlin/        -> actual untuk JavaScript",
        "  build.gradle.kts        -> deklarasi target",
        "androidApp/                -> modul aplikasi Android",
        "iosApp/                    -> proyek Xcode untuk iOS",
        "backend/                   -> modul server JVM"
    )
    struktur.forEach { println("  $it") }

    println()
    println("--- 5. Skenario pakai KMP ---")
    val skenario = listOf(
        "Mobile app lintas-platform (Android + iOS) dengan UI native",
        "Library utility dipakai di backend, Android, dan iOS",
        "SDK perusahaan dipakai lintas tim (web, mobile, server)",
        "Game dengan engine Unity/C++ interop Kotlin via Native"
    )
    skenario.forEach { println("  $it") }

    println()
    println("--- 6. Kapan TIDAK pakai KMP ---")
    val hindari = listOf(
        "Aplikasi Android saja — pakai Android Studio biasa",
        "Backend saja — pakai Ktor / Spring Boot standar",
        "Saat tim belum familiar — kurva belajar cukup curam",
        "Library Java berat yang tidak portabel"
    )
    hindari.forEach { println("  $it") }
}

Output yang Dihasilkan:

text
=== Panduan Kotlin Multiplatform ===
Sumber: https://kotlinlang.org/docs/multiplatform.html

--- 1. Identitas platform ---
Platform: JVM (Kotlin 2.0.21)
Epoch millis (beku untuk determinisme): 1700000000000

--- 2. SalamUniversal (common code) ---
Halo Budi dari JVM (Kotlin 2.0.21)
Halo Siti dari JVM (Kotlin 2.0.21)

--- 3. Metrik data class (common) ---
  Metrik(platform=JVM, nilai=1.5)
  Metrik(platform=Android, nilai=2.3)
  Metrik(platform=iOS, nilai=1.8)
Rata-rata nilai: 1.8666666666666665

--- 4. Struktur proyek KMP ---
  shared/
    src/
      commonMain/kotlin/   -> kode yang dipakai semua target
      jvmMain/kotlin/      -> actual untuk JVM (backend)
      androidMain/kotlin/  -> actual untuk Android
      iosMain/kotlin/      -> actual untuk iOS (Swift interop)
      jsMain/kotlin/        -> actual untuk JavaScript
    build.gradle.kts        -> deklarasi target
  androidApp/                -> modul aplikasi Android
  iosApp/                    -> proyek Xcode untuk iOS
  backend/                   -> modul server JVM

--- 5. Skenario pakai KMP ---
  Mobile app lintas-platform (Android + iOS) dengan UI native
  Library utility dipakai di backend, Android, dan iOS
  SDK perusahaan dipakai lintas tim (web, mobile, server)
  Game dengan engine Unity/C++ interop Kotlin via Native

--- 6. Kapan TIDAK pakai KMP ---
  Aplikasi Android saja — pakai Android Studio biasa
  Backend saja — pakai Ktor / Spring Boot standar
  Saat tim belum familiar — kurva belajar cukup curam
  Library Java berat yang tidak portabel

Perhatikan tiga kelompok yang dicetak: identitas platform dari JvmPlatform, salam universal yang memakai kontrak PlatformInfo, dan struktur direktori proyek KMP. JvmPlatform di sini mewakili implementasi actual dari jvmMain; di proyek KMP nyata, akan ada juga IosPlatform di iosMain, JsPlatform di jsMain, dst.

Kapan Pakai, Kapan Hindari #

KMP cocok saat kita berbagi logika bisnis lintas target: model data, validasi, parser, klien API, atau aturan domain. KMP tidak cocok saat proyek hanya menarget satu platform (Android saja cukup pakai Android Studio), saat tim belum familiar dengan gradle multi-target, atau saat proyek sangat bergantung pada library Java berat yang tidak portabel.

Referensi Lanjutan #

  • Kotlin Multiplatform — halaman utama dokumentasi Kotlin Multiplatform untuk berbagi kode antar target JVM, JS, Native, dan mobile

Selanjutnya #

Setelah memahami strategi lintas platform umum, langkah berikutnya adalah fokus ke target platform terbesar Kotlin: Android. Chapter berikutnya membahas panduan Android Kotlin — Activity lifecycle, ViewModel, dan stack Jetpack modern.