Kotlin MultiplatformJuniorTechnical
Что такое структура source set: commonMain, androidMain, iosMain?
Source sets — это логические наборы исходников с зависимостями. commonMain компилируется для всех платформ, androidMain/iosMain — только для своей. Иерархия настраивается в kotlin {} блоке build.gradle.kts.
Что такое source set
Source set — это именованный набор директорий с кодом (kotlin/) и ресурсами (resources/), плюс список зависимостей. Каждый source set компилируется для определённого набора таргетов. Ключевое свойство: source set может зависеть от другого (директива dependsOn), формируя иерархию.
Стандартная иерархия source sets
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
// Иерархия формируется автоматически при использовании
// стандартных имён. Вручную её можно расширить:
sourceSets {
// Базовый — компилируется для ВСЕХ платформ:
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}
}
// Только для Android:
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-okhttp:2.3.12")
}
}
// Промежуточный для ВСЕХ iOS-таргетов:
val iosMain by creating {
dependsOn(commonMain)
dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.12")
}
}
// Конкретные iOS-таргеты наследуют iosMain:
val iosX64Main by getting { dependsOn(iosMain) }
val iosArm64Main by getting { dependsOn(iosMain) }
val iosSimulatorArm64Main by getting { dependsOn(iosMain) }
}
}
Структура директорий на диске
shared/
src/
commonMain/
kotlin/
com/example/shared/
models/User.kt // доступно везде
repos/UserRepository.kt
resources/
androidMain/
kotlin/
com/example/shared/
actual/PlatformUtils.android.kt // actual-реализация
iosMain/
kotlin/
com/example/shared/
actual/PlatformUtils.ios.kt // actual-реализация
commonTest/
kotlin/
com/example/shared/
UserRepositoryTest.kt // тесты запустятся на всех платформах
androidUnitTest/
kotlin/
iosTest/
kotlin/
expect/actual в контексте source sets
// commonMain: объявляем ожидание
expect class PlatformLogger {
fun log(message: String)
}
// androidMain: даём реализацию
actual class PlatformLogger {
actual fun log(message: String) {
android.util.Log.d("App", message)
}
}
// iosMain: даём реализацию
actual class PlatformLogger {
actual fun log(message: String) {
println(message) // NSLog через println в Kotlin/Native
}
}
Kotlin 1.9.20+ Hierarchy Template
Начиная с Kotlin 1.9.20, при использовании стандартных имён таргетов (iosX64, iosArm64, iosSimulatorArm64) промежуточный iosMain создаётся автоматически. Явный dependsOn больше не нужен:
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
// iosMain создаётся автоматически — код пишем сюда:
sourceSets {
iosMain.dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.12")
}
}
}
Подводные камни
- Написать
actual-реализацию вiosX64MainвместоiosMain— при добавленииiosArm64компиляция упадёт с ошибкой «expect has no actual»; - Добавить Android-зависимость в
commonMain— iOS-таргет не скомпилируется; зависимость обязана идти вandroidMain; - Забыть про
commonTestи писать тесты только вjvmTest— логика в commonMain остаётся непротестированной на iOS; - Создавать слишком много промежуточных source sets (например,
mobileMain) без реальной необходимости — усложняет граф зависимостей; - Дублировать код в
iosX64MainиiosArm64MainвместоiosMain— нарушает принцип единственного источника истины; - Использовать
by creatingвместоby gettingдля уже существующего source set — Gradle создаёт новый пустой, игнорируя существующий.
Common mistakes
- Объяснять «source sets commonMain/androidMain/iosMain» только как синтаксис и не описывать поведение runtime/compiler.
- Игнорировать важный риск: Путаница source sets часто проявляется как unresolved reference или скрытая platform dependency в common коде.
- Давать пример без edge case: отмены, null, recomposition, platform boundary или ошибки.
What the interviewer is testing
- Формулирует суть темы «source sets commonMain/androidMain/iosMain» своими словами и связывает ее с кодом.
- Называет механизм: commonMain компилируется во все targets, androidMain видит Android API, iosMain видит Apple/Native API.
- Видит production-последствие: Путаница source sets часто проявляется как unresolved reference или скрытая platform dependency в common коде.