Irbisa · Шпаргалка
Kotlin Multiplatform (KMP)
expect/actual, source set-ы, шаринг логики, ktor, SQLDelight, interop с iOS
Что такое Kotlin Multiplatform и что вы делите между Android и iOS?
Что такое объявления
expectиactualв KMP и когда интерфейс оказывается лучшим выбором?// commonMainexpect fun platformName(): String class Greeting { fun greet(): String = "Hello from ${platformName()}"}…Как устроены source sets в KMP (
commonMain,iosMain,appleMain) и как с ними связаны Gradle-таргеты?// shared/build.gradle.ktskotlin { androidTarget() // AGP 8; AGP 9 replaces it with kotlin { androidLibrary { } } iosArm64() iosSimulatorArm64() jvm()…Android и
iosArm64собираются, аiosSimulatorArm64падает из-за отсутствующегоactual: что не так в этой настройке?// shared/build.gradle.ktskotlin { androidTarget() iosArm64() iosSimulatorArm64()} // src/commonMain/kotlin/Platform.ktexpect fun deviceModel(): String // src/androidMain/kotlin/Platform.android.ktactual fun deviceModel(): String = android.os.Build.MODEL // src/iosArm64Main/kotlin/Platform.ios.ktactual fun deviceModel(): String = UIDevice.currentDevice.modelИз каких библиотек обычно состоит общий KMP-модуль и что должна предоставлять библиотека, чтобы её можно было использовать из
commonMain?// shared/build.gradle.ktscommonMain.dependencies { implementation(libs.ktor.client.core) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.koin.core)…Как тестировать общий KMP-модуль и почему в
commonTestнельзя использовать MockK?// commonTestclass CartViewModelTest { @Test fun appliesDiscountOnce() = runTest { val repo = FakeCartRepo(items = listOf(Item("sku-1", price = 100)))…KMP, Flutter или React Native: когда что выбирать?
Общему коду нужен iOS API, например Keychain: когда вызывать его из Kotlin, когда нужен cinterop, а когда Swift должен реализовать интерфейс?
// commonMain: the contract the shared code depends oninterface SecureStore { fun read(key: String): String? fun write(key: String, value: String)}…Найдите баг: на Android ответ 404 показывает сообщение об ошибке, а на iOS тот же ответ роняет приложение, несмотря на
do/catch.// commonMain: Swift calls it as `try await repo.loadProfile(id: id)` inside do/catchclass ApiException(val code: Int) : Exception("HTTP $code") class ProfileRepository(private val client: HttpClient) { suspend fun loadProfile(id: String): Profile { val response = client.get("users/$id") if (!response.status.isSuccess()) { throw ApiException(response.status.value) } return response.body() }}Как Swift использует KMP-модуль и где болит мост через Objective-C?
Насколько высоко по стеку может подняться общий код в KMP: можно ли делить ViewModel и навигацию или они остаются нативными?
// commonMain: one ViewModel, bound by both platformsdata class CounterUi(val count: Int = 0, val isLoading: Boolean = false) class CounterViewModel(private val repo: CounterRepo) : ViewModel() { private val _state = MutableStateFlow(CounterUi()) val state: StateFlow<CounterUi> = _state.asStateFlow()…Найдите баг в этом хелпере, который отдаёт общий
Flowв Swift, и исправьте его.// commonMain: lets Swift observe a Flow through a plain callbackclass FlowWatcher<T : Any>(private val flow: Flow<T>) { fun watch(onEach: (T) -> Unit) { val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) scope.launch { flow.collect { onEach(it) } } }} // Swift: CartViewModel, called from the screen's onAppear// func onAppear() { cartWatcher.watch { items in self.items = items } }Почему многомодульные KMP-проекты отдают iOS один umbrella-фреймворк и что контролирует
export()?// shared/build.gradle.kts: the umbrella module the iOS app importskotlin { listOf(iosArm64(), iosSimulatorArm64()).forEach { target -> target.binaries.framework { baseName = "Shared" export(project(":feature:profile")) // Swift sees these types in full…Что KMP добавляет к времени сборки и размеру iOS-приложения и как держать и то и другое под контролем?
// shared/build.gradle.ktskotlin { listOf(iosArm64(), iosSimulatorArm64()).forEach { target -> target.binaries.framework { baseName = "Shared" isStatic = true…Команда выпускает один продукт на Android и iOS. Как решить, стоит ли внедрять KMP?
Как внедрить KMP в два существующих нативных приложения без большого переписывания?