Иерархическая структура проекта
Проекты Kotlin Multiplatform поддерживают иерархические структуры наборов исходного кода. Это означает, что вы можете организовать иерархию промежуточных наборов исходного кода для совместного использования общего кода некоторыми, но не всеми поддерживаемыми целевыми платформами. Использование промежуточных наборов исходного кода помогает:
Предоставлять определённый API для некоторых целевых платформ. Например, библиотека может добавить API для нативных платформ в промежуточный набор исходного кода для целевых платформ Kotlin/Native, но не для Kotlin/JVM.
Использовать определённый API для некоторых целевых платформ. Например, вы можете воспользоваться богатым API, который библиотека Kotlin Multiplatform предоставляет для некоторых целевых платформ, входящих в промежуточный набор исходного кода.
Использовать в проекте библиотеки, зависящие от платформы. Например, вы можете получить доступ к зависимостям, специфичным для iOS, из промежуточного набора исходного кода для iOS.
Инструментарий Kotlin гарантирует, что каждый набор исходного кода имеет доступ только к тому API, который доступен для всех целевых платформ, для которых компилируется этот набор исходного кода. Это предотвращает ситуации, когда используется API, специфичный для Windows, а затем выполняется компиляция для macOS, что приводит к ошибкам компоновки или неопределённому поведению во время выполнения.
Рекомендуемый способ настройки иерархии наборов исходного кода — использовать шаблон иерархии по умолчанию. Шаблон охватывает наиболее распространённые случаи. Если у вас более сложный проект, вы можете настроить иерархию вручную. Это более низкоуровневый подход: он гибче, но требует больше усилий и знаний.
Шаблон иерархии по умолчанию
Плагин Kotlin Gradle содержит встроенный шаблон иерархии по умолчанию. В нём заданы предварительно определённые промежуточные наборы исходного кода для некоторых распространённых сценариев. Плагин автоматически создаёт эти наборы исходного кода в зависимости от целевых платформ, указанных в проекте.
Рассмотрим следующий файл build.gradle(.kts) в модуле проекта, содержащем общий код:
kotlin {
android()
iosArm64()
iosSimulatorArm64()
}
kotlin {
android()
iosArm64()
iosSimulatorArm64()
}
Когда в коде вы объявляете целевые платформы android, iosArm64 и iosSimulatorArm64, плагин Kotlin Gradle находит в шаблоне подходящие общие наборы исходного кода и создаёт их. Полученная иерархия выглядит так:
Цветные наборы исходного кода действительно создаются и присутствуют в проекте, а серые наборы из шаблона по умолчанию игнорируются. Например, плагин Kotlin Gradle не создал набор исходного кода watchos, поскольку в проекте нет целевых платформ watchOS.
Если добавить целевую платформу watchOS, например watchosArm64, будет создан набор исходного кода watchos, а код из наборов исходного кода apple, native и common также будет скомпилирован для watchosArm64.
Плагин Kotlin Gradle предоставляет типобезопасные и статические средства доступа ко всем наборам исходного кода из шаблона иерархии по умолчанию, поэтому вы можете обращаться к ним без конструкций by getting или by creating в отличие от настройки вручную.
Если попытаться обратиться к набору исходного кода в файле build.gradle(.kts) общего модуля, не объявив предварительно соответствующую целевую платформу, появится предупреждение:
kotlin {
android()
iosArm64()
iosSimulatorArm64()
sourceSets {
iosMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
}
// Warning: accessing source set without declaring the target
linuxX64Main { }
}
}
kotlin {
android()
iosArm64()
iosSimulatorArm64()
sourceSets {
iosMain {
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
}
}
// Warning: accessing source set without declaring the target
linuxX64Main { }
}
}
Дополнительная настройка
Возможно, вам потребуется внести изменения в шаблон иерархии по умолчанию. Если ранее вы вручную добавили промежуточные наборы исходного кода с помощью вызовов dependsOn, использование шаблона иерархии по умолчанию отменяется и появляется следующее предупреждение:
The Default Kotlin Hierarchy Template was not applied to '<project-name>':
Explicit .dependsOn() edges were configured for the following source sets:
[<... names of the source sets with manually configured dependsOn-edges...>]
Consider removing dependsOn-calls or disabling the default template by adding
'kotlin.mpp.applyDefaultHierarchyTemplate=false'
to your gradle.properties
Learn more about hierarchy templates: https://kotl.in/hierarchy-template
Чтобы решить эту проблему, настройте проект одним из следующих способов:
Создайте дополнительные наборы исходного кода в шаблоне иерархии по умолчанию
Измените наборы исходного кода, созданные шаблоном иерархии по умолчанию
Замена настройки вручную
Случай. Все ваши промежуточные наборы исходного кода уже предусмотрены шаблоном иерархии по умолчанию.
Решение. В файле build.gradle(.kts) общего модуля удалите все вызовы dependsOn(), выполненные вручную, и наборы исходного кода с конструкциями by creating. Список всех наборов исходного кода по умолчанию см. в полном шаблоне иерархии.
Создание дополнительных наборов исходного кода
Случай. Вы хотите добавить наборы исходного кода, которых пока нет в шаблоне иерархии по умолчанию, например набор для целевых платформ macOS и JVM.
Решение:
В файле
build.gradle(.kts)общего модуля повторно примените шаблон, явно вызвавapplyDefaultHierarchyTemplate().-
Настройте дополнительные наборы исходного кода вручную с помощью
dependsOn():kotlin { jvm() macosArm64() iosArm64() iosSimulatorArm64() // Apply the default hierarchy again. It'll create, for example, the iosMain source set: applyDefaultHierarchyTemplate() sourceSets { // Create an additional jvmAndMacos source set: val jvmAndMacos by creating { dependsOn(commonMain.get()) } macosArm64Main.get().dependsOn(jvmAndMacos) jvmMain.get().dependsOn(jvmAndMacos) } }kotlin { jvm() macosArm64() iosArm64() iosSimulatorArm64() // Apply the default hierarchy again. It'll create, for example, the iosMain source set: applyDefaultHierarchyTemplate() sourceSets { // Create an additional jvmAndMacos source set: jvmAndMacos { dependsOn(commonMain.get()) } macosArm64Main { dependsOn(jvmAndMacos.get()) } jvmMain { dependsOn(jvmAndMacos.get()) } } }
Изменение наборов исходного кода
Случай. У вас уже есть наборы исходного кода с теми же именами, что и у наборов, создаваемых шаблоном, но они используются совместно другими группами целевых платформ в проекте. Например, набор исходного кода nativeMain используется только совместно целевыми платформами для настольных компьютеров: linuxX64, mingwX64 и macosArm64.
Решение. Сейчас изменить заданные по умолчанию отношения dependsOn между наборами исходного кода шаблона невозможно. Также важно, чтобы реализация и значение наборов исходного кода, например nativeMain, были одинаковыми во всех проектах.
Однако вы можете сделать одно из следующего:
Найти другие подходящие вам наборы исходного кода — в шаблоне иерархии по умолчанию или среди созданных вручную.
Полностью отказаться от шаблона, добавив
kotlin.mpp.applyDefaultHierarchyTemplate=falseв файлgradle.propertiesи настроив все наборы исходного кода вручную.
Полный шаблон иерархии
Когда вы объявляете целевые платформы, для которых компилируется проект, плагин выбирает из шаблона общие наборы исходного кода на основе указанных целевых платформ и создаёт их в проекте.
Настройка вручную
Вы можете вручную добавить промежуточный набор исходного кода в структуру наборов исходного кода. В нём будет храниться общий код для нескольких целевых платформ.
Например, вот что нужно сделать, если вы хотите использовать общий код для нативных целевых платформ Linux, Windows и macOS (linuxX64, mingwX64 и macosArm64):
В файл
build.gradle(.kts)общего модуля добавьте промежуточный набор исходного кодаmyDesktopMain, в котором будет содержаться общая логика для этих целевых платформ.-
Настройте иерархию наборов исходного кода с помощью отношения
dependsOn. СвяжитеcommonMainсmyDesktopMain, а затемmyDesktopMainс каждым набором исходного кода целевой платформы:kotlin { linuxX64() mingwX64() macosArm64() sourceSets { val myDesktopMain by creating { dependsOn(commonMain.get()) } linuxX64Main.get().dependsOn(myDesktopMain) mingwX64Main.get().dependsOn(myDesktopMain) macosArm64Main.get().dependsOn(myDesktopMain) } }kotlin { linuxX64() mingwX64() macosArm64() sourceSets { myDesktopMain { dependsOn(commonMain.get()) } linuxX64Main { dependsOn(myDesktopMain) } mingwX64Main { dependsOn(myDesktopMain) } macosArm64Main { dependsOn(myDesktopMain) } } }
Полученная иерархическая структура будет выглядеть так:
Общий набор исходного кода можно использовать для следующих сочетаний целевых платформ:
JVM или Android + Web + Native
JVM или Android + Native
Web + Native
JVM или Android + Web
Native
В настоящее время Kotlin не поддерживает совместное использование набора исходного кода для следующих сочетаний:
Несколько целевых платформ JVM
Целевые платформы JVM + Android
Несколько целевых платформ JS
Если вам нужно обращаться к API, специфичным для платформы, из общего набора исходного кода для нативных платформ, IntelliJ IDEA поможет обнаружить общие объявления, которые можно использовать в общем коде для нативных платформ. В остальных случаях используйте механизм Kotlin для ожидаемых и фактических объявлений.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/multiplatform-hierarchy.html