Кроссплатформенная разработка мобильного приложения на Kotlin Multiplatform (KMM)
Kotlin Multiplatform вышел из Beta и получил статус Stable в ноябре 2023 — с KMP 1.9.20. Это не «пиши один раз — запускай везде» в смысле Flutter. KMP позволяет разделить бизнес-логику между iOS и Android, сохранив нативный UI на каждой платформе. Архитектурно: общий модуль на Kotlin компилируется в JVM bytecode для Android и в нативный фреймворк через Kotlin/Native для iOS (xcframework через Gradle task assembleXCFramework).
Главное следствие: никаких компромиссов в UI — SwiftUI на iOS, Jetpack Compose на Android. Никакого «одинакового внешнего вида на обеих платформах» — каждая платформа выглядит нативно. Shared layer — только commonMain: сетевой слой, бизнес-логика, доменные модели, локальная БД.
Что выносим в shared, что остаётся нативным
В commonMain: сетевые запросы через Ktor Client (io.ktor:ktor-client-core), сериализация через kotlinx.serialization, локальная БД через SQLDelight (генерирует типизированный Kotlin API из SQL-файлов), доменные модели, use cases, ViewModels через kotlinx.coroutines + StateFlow.
Остаётся нативным: UI полностью (SwiftUI / UIKit на iOS, Compose / XML на Android), работа с камерой, биометрия, push-уведомления (APNs vs FCM), нативные платёжные SDK. Доступ к платформозависимым API — через expect/actual механизм: в commonMain объявляем expect class PlatformSpecific, в androidMain и iosMain пишем actual реализации.
Типичная боль с Kotlin/Native — многопоточность. До KMP 1.7.20 любой объект, созданный в одном потоке, не мог быть доступен из другого — InvalidMutabilityException. С появлением нового MM (Memory Manager) в 1.7.20 это ограничение снято, но legacy-код может содержать паттерны с freeze(), которые теперь устарели. При аудите старых KMM-проектов это первое, что смотрим.
Интеграция на стороне iOS
xcframework подключается в Xcode через SPM (Swift Package Manager) или через Cocoapods с pod 'shared'. SPM-интеграция предпочтительна с XCode 15+: binaryTarget в Package.swift с локальным путём к xcframework. Обновление фреймворка — ./gradlew assembleXCFramework в Gradle, затем build в Xcode.
Вызов suspend-функций из Swift требует обёрток: напрямую Swift не вызывает Kotlin coroutines. Решение — KMMBridge от Touchlab или ручные обёртки через Kotlinx.coroutines + CoroutineScope на Kotlin-стороне, экспортирующие callback-based API. С Kotlin 1.9.20 есть экспериментальный @Throws + Swift async/await через kotlin.native.concurrent, но в продакшене требует тестирования.
Кейс. Финтех-приложение: iOS (SwiftUI + Combine) и Android (Compose + Flow) делят общую бизнес-логику — расчёт кредитных лимитов, валидация форм, кеширование через SQLDelight. Ktor Client настроен с OkHttp engine на Android и Darwin (NSURLSession) engine на iOS. Общий AuthInterceptor в commonMain добавляет JWT-токен в каждый запрос. Тесты shared-модуля — kotlin.test + runTest для корутин. CI — GitHub Actions: ./gradlew :shared:allTests запускает тесты под JVM и через K/N test runner на симуляторе iOS.
SQLDelight vs Room vs Realm
| БД | Shared support | Тип API | Подходит для |
|---|---|---|---|
| SQLDelight | Да (commonMain) | Typed Kotlin из SQL | KMP-проекты |
| Room | Android only | DAO + Kotlin | Только Android |
| Realm Kotlin | Да (commonMain) | Object-oriented | Реактивные приложения |
SQLDelight — наш выбор по умолчанию для KMP: SQL-схема одна, API генерируется под обе платформы.
Сроки
| Масштаб | Ориентировочные сроки |
|---|---|
| Shared бизнес-логика + нативный UI, MVP | 10–16 недель |
| Полноценный продукт с оффлайном | 5–9 месяцев |
| Миграция существующего Android-приложения | 3–6 месяцев |
Стоимость рассчитывается индивидуально. KMP требует команды с компетенциями в обеих нативных платформах — это ключевой фактор при оценке бюджета.







