Spec-Zone.ru › Kotlin 2

Иерархическая структура проекта

Проекты 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 находит в шаблоне подходящие общие наборы исходного кода и создаёт их. Полученная иерархия выглядит так:

An example of using the default hierarchy template

Цветные наборы исходного кода действительно создаются и присутствуют в проекте, а серые наборы из шаблона по умолчанию игнорируются. Например, плагин 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 { }
    }
}

В этом примере наборы исходного кода apple и native компилируются только для целевых платформ iosArm64 и iosSimulatorArm64. Несмотря на названия, они имеют доступ ко всему API iOS. Это может показаться нелогичным для таких наборов исходного кода, как native, поскольку можно ожидать, что в них будут доступны только API, имеющиеся на всех нативных целевых платформах. В будущем это поведение может измениться.

Дополнительная настройка

Возможно, вам потребуется внести изменения в шаблон иерархии по умолчанию. Если ранее вы вручную добавили промежуточные наборы исходного кода с помощью вызовов 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.

Решение:

  1. В файле build.gradle(.kts) общего модуля повторно примените шаблон, явно вызвав applyDefaultHierarchyTemplate().

  2. Настройте дополнительные наборы исходного кода вручную с помощью 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 и настроив все наборы исходного кода вручную.

Сейчас мы работаем над API для создания собственных шаблонов иерархии. Он пригодится проектам, конфигурация иерархии которых значительно отличается от шаблона по умолчанию.

Этот API пока не готов, но если вы хотите попробовать его, ознакомьтесь с блоком applyHierarchyTemplate {} и объявлением KotlinHierarchyTemplate.default в качестве примера. Обратите внимание: API всё ещё разрабатывается. Он может быть не протестирован и может измениться в будущих выпусках.

Полный шаблон иерархии

Когда вы объявляете целевые платформы, для которых компилируется проект, плагин выбирает из шаблона общие наборы исходного кода на основе указанных целевых платформ и создаёт их в проекте.

Default hierarchy template

В этом примере показана только производственная часть проекта; суффикс Main опущен (например, используется common вместо commonMain). Однако для исходного кода *Test всё устроено так же.

Настройка вручную

Вы можете вручную добавить промежуточный набор исходного кода в структуру наборов исходного кода. В нём будет храниться общий код для нескольких целевых платформ.

Например, вот что нужно сделать, если вы хотите использовать общий код для нативных целевых платформ Linux, Windows и macOS (linuxX64, mingwX64 и macosArm64):

  1. В файл build.gradle(.kts) общего модуля добавьте промежуточный набор исходного кода myDesktopMain, в котором будет содержаться общая логика для этих целевых платформ.

  2. Настройте иерархию наборов исходного кода с помощью отношения 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)
            }
        }
    }
    

Полученная иерархическая структура будет выглядеть так:

Manually configured hierarchical structure

Общий набор исходного кода можно использовать для следующих сочетаний целевых платформ:

  • JVM или Android + Web + Native

  • JVM или Android + Native

  • Web + Native

  • JVM или Android + Web

  • Native

В настоящее время Kotlin не поддерживает совместное использование набора исходного кода для следующих сочетаний:

  • Несколько целевых платформ JVM

  • Целевые платформы JVM + Android

  • Несколько целевых платформ JS

Если вам нужно обращаться к API, специфичным для платформы, из общего набора исходного кода для нативных платформ, IntelliJ IDEA поможет обнаружить общие объявления, которые можно использовать в общем коде для нативных платформ. В остальных случаях используйте механизм Kotlin для ожидаемых и фактических объявлений.

16 марта 2026 г.
Использование API, специфичных для платформыДобавление зависимостей от библиотек Multiplatform

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API