Nakonfigurujte první projekt KMP: Android, iOS a Desktop s Kotlin Multiplatform
Nastavení projektu Kotlin Multiplatform od nuly je jedním z nejtechničtějších kroků celé cesty KMP.
Na rozdíl od Fluttera kde flutter create vyrábí vše, co potřebujete, nebo React Native kde
Expo si poradí se složitostí, KMP vyžaduje solidní porozumění Gradle, struktuře zdrojové sady,
a očekávaný/skutečný mechanismus, než budete moci napsat první řádek sdílené logiky.
Tato příručka vás provede od vytvoření vašeho prázdného projektu k fungující aplikaci s kódem sdílené mezi Androidem a iOS, zobrazující každý krok konfigurace s podrobným vysvětlením. Na konci budete mít projekt se správnou strukturou, nakonfigurovaný katalog verzí Gradle a první očekávané/skutečné funkce fungují.
Předpoklady
- Android Studio Hedgehog (2023.1.1) nebo vyšší s nainstalovaným pluginem KMP
- Xcode 15+ (k sestavení aplikace pro iOS – pouze na macOS)
- JDK 17+ nakonfigurovaný jako JAVA_HOME
- Základní znalost Kotlina a Gradle
Krok 1: Vytvořte projekt pomocí průvodce KMP
Nejrychlejší způsob, jak začít, je použít Multiplatformní průvodce Kotlin k dispozici
na adrese kmp.jetbrains.com nebo přímo z Android Studio přes
Soubor → Nový → Nový projekt → Multiplatformní aplikace Kotlin.
# Alternativa da riga di comando con il KMP Wizard CLI (2026)
# Installa il plugin KMP di IntelliJ/Android Studio dal marketplace
# oppure usa il sito web:
# 1. Vai su https://kmp.jetbrains.com
# 2. Configura: nome progetto, package, target (Android, iOS, Desktop)
# 3. Scarica il progetto e aprilo in Android Studio
# Struttura generata dal wizard:
my-kmp-app/
├── composeApp/ # (se scegli Compose Multiplatform)
│ └── build.gradle.kts
├── shared/ # Il modulo condiviso principale
│ ├── src/
│ │ ├── commonMain/
│ │ ├── androidMain/
│ │ └── iosMain/
│ └── build.gradle.kts
├── androidApp/ # App Android standalone
│ └── build.gradle.kts
├── iosApp/ # App iOS standalone (Swift)
│ └── iosApp.xcodeproj
├── gradle/
│ └── libs.versions.toml # Version catalog
├── build.gradle.kts # Root build script
└── settings.gradle.kts
Krok 2: Katalog verzí (libs.versions.toml)
Il Katalog verzí Gradle centralizuje správu verzí všech závislosti projektu v jediném souboru TOML. Je to nejlepší postup doporučený společností JetBrains pro projekty KMP:
# gradle/libs.versions.toml
[versions]
kotlin = "2.0.20"
kotlinx-coroutines = "1.9.0"
kotlinx-serialization = "1.7.3"
ktor = "2.3.12"
sqldelight = "2.0.2"
koin = "3.5.6"
agp = "8.5.2"
compose-multiplatform = "1.7.0"
kotlinx-datetime = "0.6.1"
[libraries]
# Kotlin
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
# Coroutines
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
# Serialization
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
# Ktor
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
# SQLDelight
sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqldelight" }
sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-native-driver = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" }
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
# Koin DI
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
# DateTime
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
Krok 3: Skript sestavení sdíleného modulu
Il build.gradle.kts sdíleného modulu je nejdůležitější konfigurační soubor
projektu. Definuje cíle sestavení, zdrojové sady a závislosti každého z nich:
// shared/build.gradle.kts
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.sqldelight)
}
kotlin {
// Target Android
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}
// Target iOS (arm64 per device, x64 per simulator Intel, simulatorArm64 per M1/M2)
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "Shared"
isStatic = true
}
}
// Target Desktop JVM (opzionale)
jvm("desktop")
sourceSets {
// Codice comune a tutte le piattaforme
commonMain.dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.json)
implementation(libs.sqldelight.runtime)
implementation(libs.sqldelight.coroutines)
implementation(libs.koin.core)
implementation(libs.kotlinx.datetime)
}
// Test comuni
commonTest.dependencies {
implementation(libs.kotlin.test)
}
// Android-specific
androidMain.dependencies {
implementation(libs.ktor.client.okhttp)
implementation(libs.sqldelight.android.driver)
implementation(libs.kotlinx.coroutines.android)
}
// iOS-specific
val iosMain by getting {
// Su iOS non puoi usare "iosMain" direttamente se hai piu target iOS
// Usa una convenzione condivisa per i tre target iOS
}
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
// Source set condiviso per tutti i target iOS
create("iosMain") {
dependsOn(commonMain.get())
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
dependencies {
implementation(libs.ktor.client.darwin)
implementation(libs.sqldelight.native.driver)
}
}
}
}
android {
namespace = "com.example.mykmpapp.shared"
compileSdk = 35
defaultConfig {
minSdk = 26
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
sqldelight {
databases {
create("AppDatabase") {
packageName.set("com.example.mykmpapp.db")
}
}
}
Krok 4: Pochopení zdrojových sad
I zdrojová sada jsou základní strukturou KMP. Každá zdrojová sada je jedna
adresáře kódu Kotlin s jeho závislostmi a zdrojové sady mohou záviset na jiných
přes hierarchii dependsOn:
// Gerarchia dei source set tipica
commonMain
├── androidMain (usa librerie Android: OkHttp, Android SQLite)
├── iosMain (usa librerie Darwin: URLSession, iOS SQLite)
│ ├── iosX64Main
│ ├── iosArm64Main
│ └── iosSimulatorArm64Main
└── desktopMain (usa librerie JVM: OkHttp, SQLite JDBC)
// Tutti i source set "eredita" le dipendenze di commonMain
// androidMain puo usare tutto di commonMain + dipendenze Android-specific
V souborovém systému projektu odpovídá adresářová struktura zdrojovým sadám:
shared/src/
├── commonMain/
│ └── kotlin/
│ └── com/example/mykmpapp/
│ ├── data/
│ ├── domain/
│ └── Platform.kt # expect declaration
├── androidMain/
│ └── kotlin/
│ └── com/example/mykmpapp/
│ └── Platform.android.kt # actual per Android
└── iosMain/
└── kotlin/
└── com/example/mykmpapp/
└── Platform.ios.kt # actual per iOS
Krok 5: První očekávané/skutečné funkce
Mechanismus očekávat/skutečný a jak KMP řeší rozdíly mezi platformami.
expect deklarovat API v běžném kódu, actual implementuje to pro každého
platforma. Začněme klasickým příkladem: získání informací o aktuální platformě:
// commonMain/kotlin/com/example/mykmpapp/Platform.kt
expect class PlatformInfo() {
val name: String
val version: String
val isDebug: Boolean
}
// Funzione che usa l'implementazione platform-specific
fun greeting(): String = "Running on ${PlatformInfo().name} ${PlatformInfo().version}"
// androidMain/kotlin/com/example/mykmpapp/Platform.android.kt
import android.os.Build
actual class PlatformInfo {
actual val name: String = "Android ${Build.VERSION.RELEASE}"
actual val version: String = Build.VERSION.SDK_INT.toString()
actual val isDebug: Boolean = BuildConfig.DEBUG
}
// iosMain/kotlin/com/example/mykmpapp/Platform.ios.kt
import platform.UIKit.UIDevice
actual class PlatformInfo {
actual val name: String = UIDevice.currentDevice.systemName()
actual val version: String = UIDevice.currentDevice.systemVersion
actual val isDebug: Boolean = Platform.isDebugBinary
}
Druhý praktičtější příklad: generování UUID (které používá různá rozhraní API na platformě):
// commonMain: dichiarazione expect
expect fun generateUUID(): String
// androidMain: implementazione con java.util.UUID
actual fun generateUUID(): String = java.util.UUID.randomUUID().toString()
// iosMain: implementazione con NSUUID di iOS
import platform.Foundation.NSUUID
actual fun generateUUID(): String = NSUUID().UUIDString()
Krok 6: Nakonfigurujte aplikaci pro Android
Aplikace pro Android je standardní modul Gradle, který závisí na sdíleném modulu. Konfigurace a jednoduché:
// androidApp/build.gradle.kts
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.example.mykmpapp.android"
compileSdk = 35
defaultConfig {
applicationId = "com.example.mykmpapp"
minSdk = 26
targetSdk = 35
versionCode = 1
versionName = "1.0"
}
buildFeatures {
compose = true
}
}
dependencies {
// Dipende dal modulo shared
implementation(projects.shared)
// UI Android (Compose o View-based)
implementation(platform("androidx.compose:compose-bom:2026.01.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.activity:activity-compose:1.9.3")
}
Krok 7: Nakonfigurujte aplikaci pro iOS
Integrace iOS vyžaduje, abyste nakonfigurovali Xcode tak, aby zahrnoval zkompilovaný rámec KMP.
Sdílený modul je zkompilován do rámce iOS (Shared.xcframework), že
je propojen s aplikací Xcode:
# Script di build iOS da aggiungere come Xcode Build Phase:
# "Run Script" - da aggiungere in Build Phases di Xcode
cd "$SRCROOT/.."
# Compila il framework KMP per il target iOS corrente
if [ "$PLATFORM_NAME" = "iphonesimulator" ]; then
if [ "$ARCHS" = "arm64" ]; then
TARGET="iosSimulatorArm64"
else
TARGET="iosX64"
fi
else
TARGET="iosArm64"
fi
./gradlew "shared:link${TARGET}DebugFrameworkIos${TARGET^}" \
-Pkotlin.native.useEmbeddableCompilerJar=true
# Il framework viene copiato automaticamente da Gradle
V souboru Swift aplikace pro iOS se rámec importuje jako běžný rámec Swift:
// iosApp/ContentView.swift
import SwiftUI
import Shared // Il framework KMP compilato
struct ContentView: View {
@State private var greeting = ""
var body: some View {
VStack {
Text(greeting)
.padding()
Button("Refresh") {
greeting = Greeting().greeting()
}
}
.onAppear {
// Chiama il codice Kotlin dal framework condiviso
greeting = PlatformInfoKt.greeting()
}
}
}
Krok 8: První test sdíleného modulu
Ověřte, že vše funguje napsáním a spuštěním testu jednotky ve sdíleném modulu.
Testování v běžných hlavních použitích kotlin.test který funguje na všech platformách:
// commonTest/kotlin/com/example/mykmpapp/PlatformTest.kt
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class PlatformTest {
@Test
fun testPlatformInfoNotNull() {
val info = PlatformInfo()
assertNotNull(info.name)
assertNotNull(info.version)
}
@Test
fun testGreetingContainsPlatform() {
val greet = greeting()
assertTrue(greet.contains("Running on"), "Greeting dovrebbe contenere 'Running on'")
}
@Test
fun testUUIDFormat() {
val uuid = generateUUID()
// UUID formato: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
assertTrue(uuid.length == 36, "UUID dovrebbe avere 36 caratteri")
assertTrue(uuid.count { it == '-' } == 4, "UUID dovrebbe avere 4 trattini")
}
}
# Esegui i test sul target JVM (piu veloce, per CI)
./gradlew shared:jvmTest
# Esegui i test su Android (emulatore o device)
./gradlew shared:connectedAndroidTest
# Esegui i test iOS (solo su macOS)
./gradlew shared:iosSimulatorArm64Test
Běžné problémy a řešení
- Chyba "Kotlin/Native toolchain nenalezen": Ujistěte se, že máte JDK 17+ nakonfigurovaný jako JAVA_HOME a že Gradle si stáhl toolchain Kotlin/Native (první sestavení je z tohoto důvodu pomalejší).
-
chyba "skutečné prohlášení nenalezeno": Používáte
expectbez poskytnutí odpovídajícíactualpro všechny nakonfigurované cíle. Zkontrolujte, zda skutečná třída/funkce existuje ve všech zdrojových sadách konfigurovaných vkotlin { }. - Zastaralý rámec iOS: Po změnách v kódu Kotlin, vyčistěte sestavení Xcode (Cmd+Shift+K) a znovu zkompilujte. Rámec musí být překompilován pomocí Gradle dříve, než jej Xcode uvidí.
- Kompatibilita knihovny: Ne všechny Java knihovny fungují iOS. Vždy používejte knihovny s tagem „KMP“ nebo „Kotlin Multiplatform“ v souboru README.
Struktura závěrečného projektu
Na konci této konfigurace má váš projekt tuto provozní strukturu:
my-kmp-app/
├── gradle/
│ └── libs.versions.toml # Version catalog centralizzato
├── shared/ # Modulo KMP condiviso
│ ├── src/
│ │ ├── commonMain/kotlin/ # Logica condivisa
│ │ ├── commonTest/kotlin/ # Test condivisi
│ │ ├── androidMain/kotlin/ # Android-specific
│ │ └── iosMain/kotlin/ # iOS-specific
│ └── build.gradle.kts
├── androidApp/ # App Android
│ ├── src/main/...
│ └── build.gradle.kts
├── iosApp/ # App iOS (Xcode project)
│ ├── iosApp/
│ │ ├── ContentView.swift
│ │ └── iOSApp.swift
│ └── iosApp.xcodeproj
├── build.gradle.kts # Root (plugin declarations)
└── settings.gradle.kts # Moduli inclusi
Závěry a další kroky
Nastavili jste kompletní projekt KMP s Androidem, iOS a sdíleným modulem. Křivka Křivka učení Gradle a zdrojových sad je zpočátku strmá, ale struktura, kterou máte vytvořené a robustní a škálovatelné pro podnikové projekty.
Následující článek se ponoří doarchitektura sdíleného modulu: jak použít očekávat/skutečný pro složitější vzory, jak nastavit Koin pro závislost multiplatformní injekce a jak strukturovat kód, aby byl snadno testovatelný v izolaci.
Série: Kotlin Multiplatform — Jedna kódová základna, všechny platformy
- Článek 1: KMP v roce 2026 — Architektura, zřízení a ekosystém
- Článek 2 (tento): Nakonfigurujte první projekt KMP – Android, iOS a Desktop
- Článek 3: Architektura sdílených modulů – očekávaná/aktuální, rozhraní a DI
- Článek 4: Multiplatformní síť s klientem Ktor
- Článek 5: Multiplatformní vytrvalost s SQLDelight
- Článek 6: Compose Multiplatform – Sdílené uživatelské rozhraní pro Android a iOS
- Článek 7: State Management KMP — ViewModel a Kotlin Flows
- Článek 8: Testování KMP — Unit Test, Integration Test a UI Test
- Článek 9: Rychlý export – Idiomatic Interop s iOS
- Článek 10: CI/CD pro projekty KMP — GitHub Actions a Fastlane
- Článek 11: Případová studie — Fintech App s KMP ve výrobě







