KotlinMiddleSystem design
Что такое Kotlin Multiplatform (KMP) и Compose Multiplatform?
KMP — технология Kotlin для компиляции общего кода в Android, iOS, JVM, JS и WASM. Compose Multiplatform расширяет это UI-фреймворком на основе Jetpack Compose для всех платформ.
Kotlin Multiplatform (KMP)
KMP позволяет писать общий код на Kotlin и компилировать его в разные таргеты. Каждый таргет компилируется нативно:
- Android — компилируется в JVM bytecode через
androidTarget(). - iOS — компилируется в нативный бинарник через LLVM (
iosArm64(),iosSimulatorArm64()). - JVM — для десктоп и серверного кода.
- JS / WASM — для веб-таргетов.
Главная идея: бизнес-логика один раз, UI — нативно на каждой платформе (до появления Compose Multiplatform).
Структура KMP-проекта
// build.gradle.kts
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.android.library)
}
kotlin {
androidTarget {
compilations.all { kotlinOptions.jvmTarget = "17" }
}
iosArm64()
iosSimulatorArm64()
sourceSets {
commonMain.dependencies {
implementation("io.ktor:ktor-client-core:2.3.12")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:2.3.12")
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.12")
}
}
}
}
expect/actual механизм
Для платформо-специфичных API используется expect/actual:
// commonMain: объявляем интерфейс
expect fun getPlatformName(): String
expect class DatabaseDriver {
fun createDriver(): SqlDriver
}
// androidMain: реализация для Android
actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"
actual class DatabaseDriver {
actual fun createDriver(): SqlDriver =
AndroidSqliteDriver(AppDatabase.Schema, context, "app.db")
}
// iosMain: реализация для iOS
actual fun getPlatformName(): String = UIDevice.currentDevice.systemName()
actual class DatabaseDriver {
actual fun createDriver(): SqlDriver =
NativeSqliteDriver(AppDatabase.Schema, "app.db")
}
Compose Multiplatform
Compose Multiplatform (от JetBrains) расширяет Jetpack Compose на все таргеты. Shared UI код компилируется в нативный рендеринг на каждой платформе:
- Android — использует стандартный Jetpack Compose.
- iOS — рендерит через Metal (не UIKit-враппер).
- Desktop — через Skia (skiko).
- Web (WASM) — через Skia в WebAssembly.
// Shared UI в commonMain
@Composable
fun JobCard(job: Job, onClick: () -> Unit) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable(onClick = onClick),
elevation = CardDefaults.cardElevation(4.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = job.title, style = MaterialTheme.typography.headlineSmall)
Text(text = job.company, style = MaterialTheme.typography.bodyMedium)
job.salary?.let {
Text(text = "$it USD/mo", color = MaterialTheme.colorScheme.primary)
}
}
}
}
// Android: обычный setContent
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { JobListScreen() }
}
}
// iOS: через ComposeUIViewController
fun MainViewController() = ComposeUIViewController { JobListScreen() }
Когда использовать KMP vs Compose Multiplatform
- KMP без Compose — когда нужна только общая логика (API, БД, analytics), а UI строится нативно (SwiftUI на iOS).
- Compose Multiplatform — когда хотите и логику, и UI разделить; подходит для B2B-приложений, внутренних инструментов.
- Только Android — Jetpack Compose без KMP, если нет iOS-требований.
Подводные камни
- Kotlin/Native GC отличается от JVM GC — утечки памяти на iOS не диагностируются JVM-инструментами, нужны Instruments + Xcode.
- Compose Multiplatform на iOS не поддерживает все Material 3 компоненты —
DatePicker,TimePickerмогут отсутствовать в конкретной версии. - expect/actual для классов (не только функций) ограничен до Kotlin 2.0 — до этой версии expect class не может иметь тело.
- SQLDelight — де-факто стандарт для KMP БД, но миграции нужно писать вручную в SQL, без ORM-удобств Room.
- iOS-фреймворк из KMP экспортируется как единый .xcframework — Objective-C interop не поддерживает Kotlin generics напрямую.
- Hot reload (Live Preview) в Compose Multiplatform работает только для Android и Desktop; iOS требует пересборки.
- Время сборки KMP-проекта значительно выше моноплатформенного — incremental build для iOS через Kotlin/Native медленнее JVM-таргета в 3–5 раз.
- CocoaPods интеграция (
cocoapods { }блок в Gradle) добавляет зависимость от Ruby-среды на машине разработчика.
Common mistakes
- Объяснять «KMP и Compose Multiplatform» только как синтаксис и не описывать поведение runtime/compiler.
- Игнорировать важный риск: Риск - обещать один UI без учета navigation, accessibility, lifecycle и нативных интеграций конкретной платформы.
- Давать пример без edge case: отмены, null, recomposition, platform boundary или ошибки.
What the interviewer is testing
- Формулирует суть темы «KMP и Compose Multiplatform» своими словами и связывает ее с кодом.
- Называет механизм: KMP лучше начинать с общей бизнес-логики, моделей, networking и persistence; общий UI требует отдельной оценки platform UX и maturity.
- Видит production-последствие: Риск - обещать один UI без учета navigation, accessibility, lifecycle и нативных интеграций конкретной платформы.