# Kotlin Multiplatform 2026: Code für Android und iOS teilen > Wie Kotlin Multiplatform 2026 Geschäftslogik zwischen Android und iOS teilt: Gradle-Setup, expect/actual, Ktor, Compose Multiplatform und KMP-Interviewfragen. - Published: 2026-06-26 - Updated: 2026-07-06 - Author: SharpSkill - Tags: Kotlin Multiplatform, KMP, Android, iOS, Cross-platform - Reading time: 10 min --- Kotlin Multiplatform (KMP) ermöglicht es, mit einer einzigen Kotlin-Codebasis die Geschäftslogik von Android- und iOS-Apps zu betreiben, während jede Plattform ihre vollständig native Oberfläche, Performance und ihren SDK-Zugriff behält. 2026 ist KMP kein Experiment mehr: Die Technologie ist stabil, wird offiziell von [Google](https://developer.android.com/kotlin/multiplatform) unterstützt und läuft produktiv bei Netflix, McDonald's, Forbes und Cash App. Dieser ausführliche Beitrag zeigt, wie das Code-Sharing tatsächlich funktioniert, wie sich ein gemeinsames Modul konfigurieren lässt und welche Kompromisse vor einem KMP-Interview verstanden werden sollten. > **Was KMP tatsächlich teilt** > > Kotlin Multiplatform teilt kompilierte Logik, keine Laufzeitumgebung. Gemeinsamer Kotlin-Code wird für Android zu JVM-Bytecode und für iOS (über LLVM) zu einer nativen Binärdatei kompiliert. Es gibt keine JavaScript-Brücke, keine eingebettete Webview und keine Reflection-Schicht, sodass geteilter Code auf beiden Plattformen mit nativer Geschwindigkeit läuft. ## Wie Kotlin Multiplatform Code teilt, ohne native Performance zu opfern Der Kernmechanismus ist eine Hierarchie von Source-Sets. `commonMain` enthält plattformunabhängigen Kotlin-Code: Networking, Serialisierung, Geschäftsregeln und View-Models. Plattform-Source-Sets wie `androidMain` und `iosMain` enthalten Code, der auf Plattform-APIs zugreift. Der Compiler erzeugt aus `commonMain` plus `androidMain` ein JVM-Artefakt für Android und aus `commonMain` plus `iosMain` ein natives Framework für iOS. Kotlin Multiplatform setzt 2026 darauf, das zu teilen, was wirklich von einer einzigen Quelle der Wahrheit profitiert: Modelle, API-Clients, Caching und Validierung. Die Oberfläche kann mit Compose Multiplatform geteilt oder Bildschirm für Bildschirm vollständig nativ mit SwiftUI belassen werden. Dieses Modell ("die Logik teilen, die UI wählen") ist der Grund, warum Teams KMP einführen, ohne bestehende Apps neu zu schreiben. Kotlin Multiplatform ist eine Kotlin-Technologie, die ein gemeinsames Modul zu mehreren Zielen kompiliert (Android auf der JVM, iOS als nativ, dazu Desktop und Web), sodass die Geschäftslogik einmal geschrieben wird, während jede Plattform ihre native Oberfläche und vollen SDK-Zugriff behält. Google unterstützt die Technologie inzwischen als erstklassige Option, und Jetpack-Bibliotheken wie Room, DataStore, ViewModel und Paging bieten KMP-Artefakte an. Zu entscheiden, was in das gemeinsame Modul gehört, ist die wichtigste architektonische Entscheidung in einem KMP-Projekt. Die folgende Tabelle zeigt, wie die meisten Produktionsteams 2026 die Grenze ziehen: Alles unterhalb der Präsentationsschicht ist ein starker Kandidat zum Teilen, während alles, was plattformspezifische UX-Konventionen berührt, meist nativ bleibt. | Schicht | In commonMain teilen? | Grund | |-------|---------------------|--------| | Datenmodelle und DTOs | Ja | Identischer API-Vertrag auf beiden Plattformen | | Networking und Caching | Ja | Ein HTTP-Stack, eine Fehlerquelle | | Geschäftsregeln und Validierung | Ja | Die Domäne unterscheidet sich nicht je Betriebssystem | | View-Models und State | Meistens | Compose und SwiftUI nutzen beide den geteilten State | | UI-Rendering | Optional | Geteilt mit Compose oder nativ je Bildschirm | | Plattform-APIs (Kamera, Biometrie) | Nein | Stattdessen über expect/actual bereitstellen | Der Nutzen skaliert damit, wie viel von der unteren Hälfte dieser Tabelle eine App abdeckt. Datenlastige Produkte mit schlanken Oberflächen teilen am meisten, hochgradig maßgeschneiderte, animationsgetriebene Apps am wenigsten. Kein Extrem ist falsch, weshalb sich KMP eher für eine schrittweise Einführung als für ein Alles-oder-nichts-Rewrite eignet. ## Das gemeinsame Modul in Gradle konfigurieren Ein KMP-Modul deklariert seine Ziele und Source-Sets in Kotlin DSL. Die folgende `build.gradle.kts` richtet Android und die drei iOS-Architekturen ein (physisches Gerät, Intel-Simulator, Apple-Silicon-Simulator) und stellt die iOS-Ausgabe als Framework namens `Shared` bereit. ```kotlin // shared/build.gradle.kts plugins { kotlin("multiplatform") kotlin("plugin.serialization") id("com.android.library") } kotlin { // Android target compiles commonMain + androidMain to JVM bytecode androidTarget() // Three iOS targets: device, Intel sim, Apple Silicon sim listOf(iosArm64(), iosX64(), iosSimulatorArm64()).forEach { target -> target.binaries.framework { baseName = "Shared" // becomes "import Shared" in Swift isStatic = true } } sourceSets { commonMain.dependencies { implementation("io.ktor:ktor-client-core:3.3.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") } androidMain.dependencies { implementation("io.ktor:ktor-client-okhttp:3.3.0") } iosMain.dependencies { implementation("io.ktor:ktor-client-darwin:3.3.0") } } } ``` Jedes Ziel bindet eine plattformspezifische Ktor-Engine ein (`okhttp` unter Android, `darwin` unter iOS), während der geteilte Code nur von der gemeinsamen `ktor-client-core`-API abhängt. Der vollständige Optionsumfang findet sich in der [Kotlin-Multiplatform-Dokumentation](https://kotlinlang.org/docs/multiplatform.html). ## Plattformspezifischen Code mit expect und actual schreiben Manche Logik kann nicht in `commonMain` liegen, weil sie eine Plattform-API benötigt. Der `expect`/`actual`-Mechanismus deklariert die Signatur im gemeinsamen Code und liefert eine konkrete Implementierung pro Ziel, aufgelöst zur Kompilierzeit ohne Laufzeitkosten. ```kotlin // commonMain/kotlin/Platform.kt // commonMain declares what it needs but cannot implement here expect class Platform() { val name: String val osVersion: String } // Shared logic can now depend on Platform freely fun analyticsUserAgent(): String { val platform = Platform() return "SharpSkill/" + platform.name + " " + platform.osVersion } ``` Die Android-Implementierung liest aus der `Build`-Klasse, die iOS-Implementierung aus `UIDevice`. Beide erfüllen denselben Vertrag, sodass `commonMain` nie weiß, mit welcher es gerade spricht. ```kotlin // androidMain/kotlin/Platform.kt import android.os.Build // actual supplies the Android-specific implementation actual class Platform actual constructor() { actual val name: String = "Android" actual val osVersion: String = Build.VERSION.RELEASE } ``` ```kotlin // iosMain/kotlin/Platform.kt import platform.UIKit.UIDevice // actual uses UIKit directly, no Objective-C bridging code required actual class Platform actual constructor() { actual val name: String = "iOS" actual val osVersion: String = UIDevice.currentDevice.systemVersion } ``` Kotlin/Native liefert typisierte Bindings für das gesamte iOS-SDK, sodass `UIDevice`, `NSUserDefaults` und Foundation-Typen aus Kotlin ohne handgeschriebenen Glue-Code aufrufbar sind. ## Networking- und Serialisierungslogik teilen Networking ist der Code mit dem höchsten Nutzen beim Teilen, weil die API-Verträge auf beiden Plattformen identisch sind. Ein einzelner [Ktor](https://ktor.io/docs/)-Client plus `kotlinx.serialization` ersetzt zwei parallele Implementierungen. Die `suspend`-Funktionen setzen auf [Kotlin-Coroutines](/blog/android/mastering-kotlin-coroutines), die sich auf beiden Seiten sauber auf `async`/`await` abbilden lassen. ```kotlin // commonMain/kotlin/data/InterviewRepository.kt import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.get import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.Serializable // One serializable model, zero duplication across platforms @Serializable data class Question(val id: String, val prompt: String, val difficulty: String) // One HttpClient, one JSON parser, one repository for both apps class InterviewRepository { private val client = HttpClient { install(ContentNegotiation) { json() } } suspend fun fetchQuestions(tech: String): List = client.get("https://api.sharpskill.dev/questions/" + tech).body() } ``` Dieses Repository, seine Retry-Logik und seine Datenmodelle werden einmal geschrieben. Ein im Parser behobener Fehler ist auf Android und iOS gleichzeitig behoben, und genau hier zahlt sich der Einrichtungsaufwand von KMP aus. Dasselbe Muster erstreckt sich auf eine gemeinsame Datenbank mit SQLDelight, geteilten Key-Value-Speicher und geteilte Dependency Injection mit Koin, sodass die gesamte Datenschicht in `commonMain` hinter Schnittstellen liegen kann, von denen die UI abhängt. Ein häufiger Fehler ist der Versuch, zu früh zu viel zu teilen. Der pragmatische Weg besteht darin, mit einem Repository zu beginnen, die Build- und CI-Pipeline auf beiden Plattformen abzusichern und dann mit wachsendem Vertrauen Funktion für Funktion zu verschieben. ## Geteilte UI mit Compose Multiplatform bauen Compose Multiplatform erreichte im Mai 2025 den stabilen Status auf iOS (Version 1.8.0) und lag Mitte 2026 bei 1.11.0, mit nativer Texteingabe und standardmäßig aktivem Concurrent Rendering. Ein `@Composable` in `commonMain` rendert auf beiden Plattformen, und geteilte View-Models passen natürlich zu einer [MVVM- oder MVI-Architektur](/blog/android/mvvm-vs-mvi-architecture). ```kotlin // commonMain/kotlin/ui/QuestionList.kt import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.foundation.layout.padding // This list renders identically on Android and iOS @Composable fun QuestionList(questions: List) { LazyColumn { items(questions) { question -> Card(modifier = Modifier.padding(8.dp)) { Text(text = question.prompt, modifier = Modifier.padding(16.dp)) } } } } ``` Das Teilen der UI ist optional und erfolgt pro Bildschirm. Ein Team kann die gesamte Oberfläche mit [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform) teilen, für die gesamte App bei SwiftUI bleiben und nur die Logik teilen oder beides mischen. Bildschirme, die von plattformspezifischer UX abhängen, etwa Widgets oder App Clips, bleiben meist nativ. ## Geteilten Code aus Swift auf iOS nutzen Das gemeinsame Modul kompiliert zu einem Framework, das Swift wie jede andere Bibliothek importiert. Der historische Reibungspunkt waren Kotlin-`suspend`-Funktionen und `Flow`, die als umständliche Callback-APIs auftauchten. [SKIE](https://skie.touchlab.co/) von Touchlab löst das, indem es idiomatisches Swift generiert: `suspend` wird zu nativem `async`/`await` und `Flow` wird zu `AsyncSequence`. ```swift // iosApp/ContentView.swift import SwiftUI import Shared // the KMP framework, baseName = "Shared" struct ContentView: View { @State private var questions: [Question] = [] private let repository = InterviewRepository() var body: some View { List(questions, id: \.id) { question in Text(question.prompt) } .task { // With SKIE, the Kotlin suspend fun is a Swift async fun questions = (try? await repository.fetchQuestions(tech: "android")) ?? [] } } } ``` Das iOS-Team schreibt gewöhnliches Swift und SwiftUI. Es nutzt geteilte Modelle und Repositories genauso wie ein natives Swift-Package, wodurch KMP für den Großteil der iOS-Codebasis unsichtbar bleibt. Zwei Schwachstellen sind in einem Interview weiterhin erwähnenswert. Erstens die Build-Zeiten: Die Kotlin/Native-Kompilierung ist langsamer als ein reiner Swift-Build, auch wenn der Gradle-Build-Cache und die Verteilung eines vorgefertigten XCFramework die täglichen Kosten abmildern. Zweitens verbessert sich das Debugging über die Grenze zwischen Swift und Kotlin, ist aber noch nicht so nahtlos wie das Bleiben in einer einzigen Sprache, was ein weiterer Grund ist, warum Teams die geteilte Oberfläche bewusst begrenzen, statt sie ausufern zu lassen. ## Kotlin-Multiplatform-Interviewfragen, mit denen zu rechnen ist Da KMP-Interviewfragen zunehmend in Android- und Mobile-Rollen auftauchen, lohnt es sich, einige wiederkehrende Fragen zusammen mit einer breiteren [Android-Interviewvorbereitung](/technologies/android) zu üben: - **Wie unterscheidet sich expect/actual von einer Schnittstelle?** expect/actual wird zur Kompilierzeit pro Ziel aufgelöst, ohne Laufzeit-Dispatch, und kann eine Klasse, Funktion, Property oder ein Typealias hinterlegen. Eine Schnittstelle wird dynamisch zur Laufzeit aufgelöst. expect/actual eignet sich für Plattform-APIs, Schnittstellen für Polymorphie innerhalb des geteilten Codes. - **Wie handhabt Kotlin/Native Speicher und Threading?** Seit Kotlin 1.7.20 hat der neue Speichermanager das alte Object-Freezing-Modell abgelöst, sodass geteilter veränderlicher State und Coroutines über Threads hinweg weitgehend so funktionieren wie auf der JVM. - **Kann eine bestehende App KMP schrittweise einführen?** Ja. Das gemeinsame Modul wird als AAR für Android und als XCFramework für iOS ausgeliefert, sodass ein Repository oder eine Funktion nach der anderen migriert werden kann, ohne ein Rewrite. - **Wann sollte die UI nativ bleiben, statt Compose Multiplatform zu nutzen?** Wenn ein Bildschirm auf plattformspezifische UX setzt oder wenn das iOS-Team die Präsentationsschicht besitzt und lieber selbst kontrolliert. > **Toolchain im Jahr 2026** > > Als Zielsetzung dienen Kotlin 2.3 mit dem K2-Compiler, Ktor 3.x für Networking, SQLDelight für eine gemeinsame Datenbank und Koin für Dependency Injection. Für die iOS-Interoperabilität sollte SKIE früh eingebunden werden; es nachträglich einzubauen, nachdem die Swift-Schicht geschrieben ist, ist deutlich schmerzhafter. ## Fazit Kotlin Multiplatform ist 2026 ein pragmatischer Weg, doppelte Logik zwischen Android und iOS zu reduzieren, ohne native UI oder Performance aufzugeben: - Die Logik teilen, die eine einzige Quelle der Wahrheit hat (Modelle, Networking, Validierung), und pro Bildschirm zwischen nativer oder Compose-UI wählen. - `expect`/`actual` für Plattform-APIs nutzen; es wird zur Kompilierzeit aufgelöst, ohne Laufzeit-Overhead. - Networking einmal mit Ktor und `kotlinx.serialization` schreiben, sodass Korrekturen auf beiden Plattformen gleichzeitig ankommen. - Schrittweise über ein AAR und ein XCFramework einführen, statt sich auf ein Rewrite festzulegen. - SKIE von Anfang an einbinden, damit Swift `suspend` und `Flow` als natives `async`/`await` und `AsyncSequence` nutzt. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/android/kotlin-multiplatform-2026