Обмен кодом на платформах
С помощью Kotlin Multiplatform вы можете обмениваться кодом, используя механизмы, предоставляемые Kotlin:
Обмен кодом между всеми платформами, используемыми в вашем проекте. Используйте его для обмена общей бизнес-логикой, которая применима ко всем платформам.
Обмен кодом между некоторыми платформами в вашем проекте, но не всеми. Вы можете повторно использовать большую часть кода в похожих платформах, используя иерархическую структуру. Вы можете использовать сокращения для целевых платформ для общих комбинаций платформ или настроить иерархическую структуру вручную.
Если вам необходимо получить доступ к платформам API из общего кода, используйте механизм Kotlin ожидаемых и фактических объявлений.
Обмен кодом на всех платформах
Если у вас есть бизнес-логика, общая для всех платформ, вам не нужно писать одинаковый код для каждой платформы — просто поделитесь им в общем наборе исходных файлов.

Все наборы исходных файлов, специфичные для платформы, по умолчанию зависят от общего набора исходных файлов. Вам не нужно вручную указывать какие-либо dependsOn связи для наборов исходных файлов по умолчанию, таких как jvmMain, macosX64Main, и другие.
Если вам необходимо получить доступ к платформам API из общего кода, используйте механизм Kotlin ожидаемых и фактических объявлений.
Обмен кодом на похожих платформах
Часто необходимо создавать несколько нативных целей, которые потенциально могут повторно использовать много общей логики и API сторонних сервисов.
Например, в типичном многоплатформенном проекте, нацеленном на iOS, есть две цели, связанные с iOS: одна для устройств iOS ARM64, другая для эмулятора x64. У них есть отдельные наборы исходных файлов, специфичные для платформы, но на практике редко требуется разный код для устройства и эмулятора, и их зависимости в основном одинаковы. Таким образом, код, специфичный для iOS, можно использовать совместно.
Очевидно, в этой настройке желательно иметь общий набор исходных файлов для двух целей iOS с кодом Kotlin/Native, который по-прежнему может напрямую вызывать любые API, общие для устройства iOS и эмулятора.
В этом случае вы можете совместно использовать код между нативными целями в проекте, используя иерархическую структуру. С Kotlin 1.6.20 она включена по умолчанию. Подробнее см. Иерархическую структуру проекта.
Существует два способа создания иерархической структуры:
Использовать сокращения для целей, чтобы легко создать структуру иерархии для распространённых сочетаний нативных целей.
Узнайте больше о совместном использовании кода в библиотеках и использовании нативных библиотек в иерархической структуре.
Использовать сокращения для целей
В типичном многоплатформенном проекте с двумя целями iOS – iosArm64 и iosX64, иерархическая структура включает промежуточный набор исходных файлов (iosMain), который используется наборами исходных файлов, специфичными для платформы.
Плагин kotlin-multiplatform предоставляет сокращения для целей, для создания структур для распространённых комбинаций целей.
Сокращение для цели |
Цели |
|---|---|
|
|
|
|
|
|
Все сокращения создают похожие иерархические структуры в коде. Например, сокращение ios создаёт следующую иерархическую структуру:
kotlin {
sourceSets{
val commonMain by sourceSets.getting
val iosX64Main by sourceSets.getting
val iosArm64Main by sourceSets.getting
val iosMain by sourceSets.creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
}
}
}
kotlin {
sourceSets{
iosMain {
dependsOn(commonMain)
iosX64Main.dependsOn(it)
iosArm64Main.dependsOn(it)
}
}
}
Сокращения для целей и эмуляторы ARM64 (Apple Silicon)
Сокращения для целей ios, watchos, и tvos не включают цели эмулятора для платформ ARM64 (Apple Silicon): iosSimulatorArm64, watchosSimulatorArm64, и tvosSimulatorArm64. Если вы используете сокращения для целей и хотите скомпилировать проект для эмулятора Apple Silicon, внесите следующие изменения в скрипт сборки:
Добавьте необходимую цель эмулятора
*SimulatorArm64.Свяжите цель эмулятора с сокращением, используя зависимости наборов исходных файлов (
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)
}
}
}
Настройка иерархической структуры вручную
Чтобы создать иерархическую структуру вручную, добавьте промежуточный набор исходных файлов, который содержит общий код для нескольких целей, и создайте структуру наборов исходных файлов, включая промежуточный.
Например, если вы хотите использовать код совместно между нативными целями Linux, Windows и macOS – linuxX64M, mingwX64, и macosX64:
Добавьте промежуточный набор исходных файлов
desktopMain, который содержит общую логику для этих целей.Укажите иерархию наборов исходных файлов, используя отношение
dependsOn.
kotlin{
sourceSets {
val desktopMain by creating {
dependsOn(commonMain)
}
val linuxX64Main by getting {
dependsOn(desktopMain)
}
val mingwX64Main by getting {
dependsOn(desktopMain)
}
val macosX64Main by getting {
dependsOn(desktopMain)
}
}
}
kotlin {
sourceSets {
desktopMain {
dependsOn(commonMain)
}
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 ожидаемых и фактических объявлений.
Использование кода в библиотеках
Благодаря иерархической структуре проекта, библиотеки также могут предоставлять общие API для подмножества целей. Когда библиотека публикуется, API её промежуточных наборов исходных файлов включается в артефакты библиотеки вместе с информацией о структуре проекта. При использовании этой библиотеки, промежуточные наборы исходных файлов вашего проекта получают доступ только к тем API библиотеки, которые доступны для целей каждого набора исходных файлов.
Например, посмотрите на следующую иерархию наборов исходных файлов из репозитория kotlinx.coroutines:

Набор исходных файлов concurrent объявляет функцию runBlocking и компилируется для JVM и нативных целей. После того как библиотека kotlinx.coroutines обновлена и опубликована с иерархической структурой проекта, вы можете зависеть от неё и вызывать runBlocking из набора исходных файлов, который совместно используется между JVM и нативными целями, так как это соответствует «подписи целей» набора исходных файлов concurrent библиотеки.
Использование нативных библиотек в иерархической структуре
Вы можете использовать платформенно-зависимые библиотеки, такие как Foundation, UIKit, и POSIX в наборах исходных файлов, общих для нескольких нативных целей. Это поможет вам совместно использовать больше нативного кода без ограничений, накладываемых платформенно-специфическими зависимостями.
С Kotlin 1.6.20 использование платформенно-зависимых библиотек доступно в общих наборах исходных файлов по умолчанию. Дополнительные шаги не требуются — IntelliJ IDEA поможет вам определить общие объявления, которые вы можете использовать в общем коде. Подробнее см. Иерархическую структуру проекта.
В дополнение к встроенным библиотекам платформы в Kotlin/Native, этот подход также может обрабатывать настраиваемые cinterop библиотеки, делая их доступными в общих наборах исходных файлов. Для включения этой поддержки укажите дополнительный ключ kotlin.mpp.enableCInteropCommonization:
kotlin.mpp.enableCInteropCommonization=true
Что дальше?
Посмотрите примеры совместного использования кода с помощью механизма Kotlin определений expect и actual.
Узнайте больше о иерархической структуре проекта.
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform-share-on-platforms.html