Spec-Zone.ru › Kotlin 1.9

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

Проекты Multiplatform поддерживают иерархические структуры. Это означает, что вы можете организовать иерархию промежуточных наборов исходных кодов для совместного использования общего кода между некоторыми, но не всеми, поддерживаемыми целевыми платформами. Использование промежуточных наборов исходных кодов имеет ряд важных преимуществ:

  • Если вы являетесь автором библиотеки и хотите предоставить специализированный API, вы можете использовать промежуточный набор исходных кодов для некоторых, но не всех, целевых платформ — например, промежуточный набор исходных кодов для Kotlin/Native, но не для Kotlin/JVM.

  • Если вы хотите использовать зависящие от платформы библиотеки в своем проекте, вы можете использовать промежуточный набор исходных кодов для использования этого конкретного API в нескольких целевых платформах. Например, вы можете получить доступ к зависимостям, специфичным для iOS, таким как Foundation, при совместном использовании кода на всех целевых платформах iOS.

  • Некоторые библиотеки недоступны для определенных платформ. В частности, родные библиотеки доступны только для наборов исходных кодов, которые компилируются в Kotlin/Native. Использование промежуточного набора исходных кодов решит эту проблему.

Инструментарий Kotlin гарантирует, что каждый набор исходных кодов имеет доступ только к API, который доступен для всех целевых платформ, для которых этот набор исходных кодов компилируется. Это предотвращает случаи, когда используется API, специфичный для Windows, а затем он компилируется для macOS, что приводит к ошибкам линковки или неопределенному поведению во время выполнения.

Существует 3 способа создания иерархии целевых платформ:

  • Указать все целевые платформы и включить стандартную иерархию

  • Использовать доступные сокращения целевых платформ для типовых случаев

  • Вручную объявить и подключить наборы исходных кодов

Стандартная иерархия

Стандартная иерархия целевых платформ является Экспериментальной. Она может быть изменена в будущих выпусках Kotlin без предварительного уведомления. Для скриптов Kotlin Gradle необходимо включить ее с помощью @OptIn(ExperimentalKotlinGradlePluginApi::class).

Начиная с Kotlin 1.8.20, вы можете настроить иерархию наборов исходных кодов в своих проектах Multiplatform с помощью стандартной иерархии целевых платформ. Это шаблон для всех возможных целевых платформ и их общих наборов исходных кодов, жестко закодированных в плагине Kotlin Gradle.

Настройка вашего проекта

Для настройки иерархии вызовите targetHierarchy.default() в блоке kotlin вашего файла build.gradle(.kts) и перечислите все необходимые целевые платформы. Например:

@OptIn(ExperimentalKotlinGradlePluginApi::class)
kotlin {
    // Enable the default target hierarchy:
    targetHierarchy.default()

    android()
    iosArm64()
    iosSimulatorArm64()
}

Когда вы объявляете конечные целевые платформы android, iosArm64, и iosSimulatorArm64 в вашем коде, плагин Kotlin Gradle находит подходящие общие наборы исходных кодов из шаблона и создает их для вас. Результирующая иерархия выглядит следующим образом:

Зеленые наборы исходных кодов фактически создаются и присутствуют в проекте, в то время как серые наборы из стандартного шаблона игнорируются. Плагин Kotlin Gradle не создал, например, набор watchos, потому что в проекте нет целевых платформ watchOS.

Если вы добавите целевую платформу watchOS, например watchosArm64, набор watchos будет создан, а код из наборов apple, native, и common будет скомпилирован для watchosArm64.

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

Настройка результирующей иерархии

Вы можете дополнительно настроить результирующую иерархию вручную с помощью отношения dependsOn. Для этого примените конструкцию by getting для наборов исходных кодов, созданных с помощью targetHierarchy.default().

Рассмотрим этот пример проекта с набором исходных кодов, используемым только для целевых платформ jvm и native.

@OptIn(ExperimentalKotlinGradlePluginApi::class)
kotlin {
    // Enable the default target hierarchy:
    targetHierarchy.default()

    jvm()
    iosArm64()
    // the rest of the necessary targets...

    sourceSets {
        val commonMain by getting

        val jvmAndNativeMain by creating {
            dependsOn(commonMain)
        }

        val nativeMain by getting {
            dependsOn(jvmAndNativeMain)
        }

        val jvmMain by getting {
            dependsOn(jvmAndNativeMain)
        }
    }
}

Удаление dependsOn отношений, которые автоматически создаются вызовом targetHierarchy.default(), может быть неудобным. В этом случае используйте вместо этого полностью ручную настройку.

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

Этот API еще не готов, но если вы хотите его попробовать, обратите внимание на блок targetHierarchy.custom { ... } и объявление targetHierarchy.default() в качестве примера. Имейте в виду, что этот API все еще находится в разработке. Он может не пройти все тесты и может измениться в будущих выпусках.

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

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

Default target hierarchy

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

Сокращения целевых платформ

Плагин Kotlin Multiplatform предоставляет некоторые предопределённые сокращения целевых платформ для создания структур для распространённых комбинаций целевых платформ:

Сокращение целевой платформы

Целевые платформы

ios

iosArm64, iosX64

watchos

watchosArm32, watchosArm64, watchosX64

tvos

tvosArm64, tvosX64

Все сокращения создают похожие иерархические структуры в коде. Например, вы можете использовать сокращение ios() для создания проекта Multiplatform с 2-мя целевыми платформами iOS, iosArm64 и iosX64, и общим набором исходных кодов:

kotlin {
    ios() // iOS device and simulator targets; iosMain and iosTest source sets
}

В этом случае иерархическая структура включает промежуточные наборы исходных кодов iosMain и iosTest, которые используются наборами исходных кодов, специфичными для платформы:

Code shared for iOS targets

Полученная иерархическая структура будет эквивалентна коду ниже:

kotlin {
    iosX64()
    iosArm64()
    
    sourceSets {
        val commonMain by getting
        val iosX64Main by getting
        val iosArm64Main by getting
        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
        }
    }
}
kotlin {
    iosX64()
    iosArm64()
    
    sourceSets {
        iosMain {
            dependsOn(commonMain)
            iosX64Main.dependsOn(it)
            iosArm64Main.dependsOn(it)
        }
    }
}

Сокращения целевых платформ и симуляторы ARM64 (Apple Silicon)

Сокращения целевых платформ ios, watchos, и tvos не включают целевые платформы симуляторов ARM64 (Apple Silicon): iosSimulatorArm64, watchosSimulatorArm64, и tvosSimulatorArm64. Если вы используете сокращения целевых платформ и хотите скомпилировать проект для симулятора Apple Silicon, внесите следующие изменения в скрипт сборки:

  1. Добавьте необходимую целевую платформу симулятора *SimulatorArm64.

  2. Подключите целевую платформу симулятора к сокращению с помощью отношения dependsOn между наборами исходных кодов.

kotlin {
    ios()
    // Add the ARM64 simulator target
    iosSimulatorArm64()

    val iosMain by sourceSets.getting
    val iosTest by sourceSets.getting
    val iosSimulatorArm64Main by sourceSets.getting
    val iosSimulatorArm64Test by sourceSets.getting

    // Set up dependencies between the source sets
    iosSimulatorArm64Main.dependsOn(iosMain)
    iosSimulatorArm64Test.dependsOn(iosTest)
}
kotlin {
    ios()
    // Add the ARM64 simulator target
    iosSimulatorArm64()

    // Set up dependencies between the source sets
    sourceSets {
        // ...
        iosSimulatorArm64Main {
            dependsOn(iosMain)
        }
        iosSimulatorArm64Test {
            dependsOn(iosTest)
        }
    }
}
END_OF_DOCUMENT_MARKER ```

Ручная настройка

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

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

Manually configured hierarchical structure
  1. Добавьте промежуточный набор исходных файлов desktopMain, который содержит общий код для этих платформ.

  2. Укажите иерархию наборов исходных файлов, используя отношение dependsOn.

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

kotlin {
    linuxX64()
    mingwX64()
    macosX64()
  
    sourceSets {
        val desktopMain by creating {
            dependsOn(commonMain.get())
        }
        val linuxX64Main by getting {
            dependsOn(desktopMain)
        }
        val mingwX64Main by getting {
            dependsOn(desktopMain)
        }
        val macosX64Main by getting {
            dependsOn(desktopMain)
        }
    }
}
kotlin {
    linuxX64()
    mingwX64()
    macosX64()
  
    sourceSets {
        desktopMain {
            dependsOn(commonMain.get())
        }
        linuxX64Main {
            dependsOn(desktopMain)
        }
        mingwX64Main {
            dependsOn(desktopMain)
        }
        macosX64Main {
            dependsOn(desktopMain)
        }
    }
}

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

  • JVM или Android + JS + Native

  • JVM или Android + Native

  • JS + Native

  • JVM или Android + JS

  • Native

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

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

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

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

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

Последнее изменение: 13 апреля 2023 г.
Подключение к платформа-специфичным API Макет набора исходных файлов Android

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform-hierarchy.html

Spec-Zone.ru

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