Spec-Zone.ru › Kotlin 2

Руководство по совместимости Kotlin Multiplatform

В этом руководстве приводится краткий обзор несовместимых изменений, с которыми вы можете столкнуться при разработке проектов с Kotlin Multiplatform.

Информацию о Compose Multiplatform см. в разделе Что нового в Compose Multiplatform и на странице Совместимость Kotlin и Jetpack.

Текущая стабильная версия Kotlin — 2.4.20. Учитывайте цикл устаревания конкретного изменения применительно к версии Kotlin в ваших проектах, например:

  • При обновлении с Kotlin 1.7.0 до Kotlin 1.9.0 проверьте несовместимые изменения, вступившие в силу как в Kotlin 1.9.0, так и в Kotlin 1.7.0−1.8.22.

  • При обновлении с Kotlin 1.9.0 до Kotlin 2.0.0 проверьте несовместимые изменения, вступившие в силу как в Kotlin 2.0.0, так и в Kotlin 1.9.0−1.9.25.

Совместимость версий

При настройке проекта проверьте совместимость конкретной версии плагина Kotlin Multiplatform Gradle (она совпадает с версией Kotlin в вашем проекте) с версиями Gradle, Xcode и Android Gradle Plugin:

Версия плагина Kotlin Multiplatform

Gradle

Android Gradle Plugin

Xcode

2.4.20

7.6.3–9.7.0

8.5.2–9.3.1

26.4

2.4.0-2.4.10

7.6.3–9.5.0

8.5.2–9.1.0

26.4

2.3.20–2.3.21

7.6.3–9.3.0

8.2.2–9.0.0

26.0

2.3.10

7.6.3–9.0.0

8.2.2–9.0.0

26.0

2.3.0

7.6.3–9.0.0

8.2.2–8.13.0

26.0

2.2.21

7.6.3–8.14

7.3.1–8.11.1

26.0

2.2.20

7.6.3–8.14

7.3.1–8.11.1

16.4

2.2.0–2.2.10

7.6.3–8.14

7.3.1–8.10.0

16.3

2.1.21

7.6.3–8.12.1

7.3.1–8.7.2

16.3

2.1.20

7.6.3–8.11

7.4.2–8.7.2

16.0

2.1.0–2.1.10

7.6.3-8.10*

7.4.2–8.7.2

16.0

2.0.21

7.5-8.8*

7.4.2–8.5

16.0

2.0.20

7.5-8.8*

7.4.2–8.5

15.3

2.0.0

7.5-8.5

7.4.2–8.3

15.3

1.9.20

7.5-8.1.1

7.4.2–8.2

15.0

*Kotlin 2.0.20–2.0.21 и Kotlin 2.1.0–2.1.10 полностью совместимы с Gradle вплоть до версии 8.6. Также поддерживаются версии Gradle 8.7–8.10, за одним исключением: если вы используете плагин Kotlin Multiplatform Gradle, в многоплатформенных проектах могут появиться предупреждения об устаревании при вызове функции withJava() для целевой платформы JVM. Дополнительную информацию см. в разделе Наборы исходного кода Java, создаваемые по умолчанию.

Kotlin 2.0.0 и более поздние версии

В этом разделе описаны несовместимые изменения, которые завершают цикл устаревания и вступают в силу в Kotlin 2.0.0–2.4.20.

Переход на плагин Google для целевых платформ Android

Что изменилось?

До Kotlin 2.3.0 мы предоставляли поддержку целевой платформы Android с помощью плагинов com.android.application и com.android.library. Это было временное решение на период разработки командой Android в Google отдельного плагина, предназначенного для Kotlin Multiplatform.

Изначально мы использовали блок android, но позднее перешли на блок androidTarget, чтобы имя android можно было зарезервировать для нового плагина.

Теперь команда Android предоставляет плагин com.android.kotlin.multiplatform.library, который можно использовать с исходными блоками android.

В Kotlin 2.3.0 появляется предупреждение об устаревании, если в проектах Kotlin Multiplatform используется имя androidTarget. Если вам нужно больше времени для перехода на блок android, используйте Kotlin 2.3.10 с AGP 8.x, где это предупреждение не появляется.

Как теперь лучше поступить?

Перейдите на новый плагин com.android.kotlin.multiplatform.library. Переименуйте все вхождения блока androidTarget в android. Подробные инструкции по переходу см. в руководстве по миграции Google.

Когда изменения вступят в силу?

Ниже приведен цикл устаревания для плагина Kotlin Multiplatform Gradle:

  • 1.9.0: добавить предупреждение об устаревании при использовании имени android в проектах Kotlin Multiplatform

  • 2.1.0: повысить уровень этого предупреждения до ошибки

  • 2.2.0: удалить DSL целевой платформы android из плагина Kotlin Multiplatform Gradle

  • 2.3.0: становится доступен новый плагин Android; добавить предупреждение об устаревании при использовании имени androidTarget в проектах Kotlin Multiplatform.

  • 2.3.10: отменить предупреждение об устаревании при использовании имени androidTarget в проектах Kotlin Multiplatform.

Устаревшее встраивание биткода

Что изменилось?

Встраивание биткода устарело в Xcode 14 и было удалено в Xcode 15 для всех целевых платформ Apple. В связи с этим в Kotlin устаревают параметр embedBitcode для конфигурации фреймворка, а также аргументы командной строки -Xembed-bitcode и -Xembed-bitcode-marker.

Как теперь лучше поступить?

Если вы по-прежнему используете более ранние версии Xcode, но хотите перейти на Kotlin 2.0.20 или более позднюю версию, отключите встраивание биткода в проектах Xcode.

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 2.0.20: компилятор Kotlin/Native больше не поддерживает встраивание биткода

  • 2.1.0: DSL embedBitcode устаревает в плагине Kotlin Multiplatform Gradle с выдачей предупреждения

  • 2.2.0: предупреждение повышается до ошибки

  • 2.3.0: DSL embedBitcode удаляется

Наборы исходного кода Java создаются по умолчанию

Что изменилось?

Чтобы привести Kotlin Multiplatform в соответствие с предстоящими изменениями в Gradle, мы постепенно отказываемся от функции withJava(). Функция withJava() обеспечивала интеграцию с плагинами Java для Gradle, создавая необходимые наборы исходного кода Java. Начиная с Kotlin 2.1.20 эти наборы исходного кода Java создаются по умолчанию.

Как теперь лучше поступить?

Раньше для создания наборов исходного кода src/jvmMain/java и src/jvmTest/java требовалось явно использовать функцию withJava():

kotlin {
    jvm {
        withJava()
    }
}

Начиная с Kotlin 2.1.20, функцию withJava() можно удалить из скрипта сборки.

Кроме того, теперь Gradle запускает задачи компиляции Java, только если в проекте есть исходный код Java. Это приводит к выполнению диагностики проверки JVM, которая раньше не запускалась. Диагностика завершается ошибкой, если для задач KotlinJvmCompile или внутри compilerOptions явно настроена несовместимая целевая платформа JVM. Рекомендации по обеспечению совместимости целевых платформ JVM см. в разделе Проверка совместимости целевых платформ JVM связанных задач компиляции.

Если в вашем проекте используется версия Gradle выше 8.7 и он не зависит от плагинов Java для Gradle, таких как Java, Java Library или Application, либо от стороннего плагина Gradle, зависящего от плагина Java для Gradle, функцию withJava() можно удалить.

Если в проекте используется плагин Java для Gradle Application, рекомендуем перейти на новый экспериментальный DSL. Начиная с Gradle 8.7 плагин Application больше не будет работать с плагином Kotlin Multiplatform Gradle.

Если в многоплатформенном проекте вы хотите использовать плагин Kotlin Multiplatform Gradle вместе с другими плагинами Gradle для Java, см. раздел Устаревшая совместимость плагина Kotlin Multiplatform Gradle с плагинами Java.

Если вы используете плагин Gradle Java test fixtures с Kotlin 2.1.20 и версией Gradle выше 8.7, этот плагин не работает. Вместо этого перейдите на Kotlin 2.1.21, где эта проблема устранена.

Если у вас возникнут проблемы, сообщите о них в трекере задач или попросите о помощи в нашем открытом канале Slack.

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • Gradle >8.6: добавить предупреждение об устаревании для любой предыдущей версии Kotlin в многоплатформенных проектах, использующих функцию withJava().

  • Gradle 9.0: повысить уровень этого предупреждения до ошибки.

  • 2.1.20: добавить предупреждение об устаревании при использовании функции withJava() с любой версией Gradle.

Объявление нескольких схожих целевых платформ

Что изменилось?

Мы не рекомендуем объявлять несколько схожих целевых платформ в одном проекте Gradle. Например:

kotlin {
    jvm("jvmKtor")
    jvm("jvmOkHttp") // Not recommended and produces a deprecation warning
}

Один из распространенных вариантов — объединить два связанных фрагмента кода. Например, в проекте Gradle :shared может потребоваться использовать jvm("jvmKtor") и jvm("jvmOkHttp") для реализации сетевого взаимодействия с помощью библиотек Ktor или OkHttp:

// shared/build.gradle.kts:
kotlin {
    jvm("jvmKtor") {
        attributes.attribute(/* ... */)
    }
    jvm("jvmOkHttp") {
        attributes.attribute(/* ... */)
    }

    sourceSets {
        val commonMain by getting
        val commonJvmMain by sourceSets.creating {
            dependsOn(commonMain)
            dependencies {
                // Shared dependencies
            }
        }
        val jvmKtorMain by getting {
            dependsOn(commonJvmMain)
            dependencies {
                // Ktor dependencies
            }
        }
        val jvmOkHttpMain by getting {
            dependsOn(commonJvmMain)
            dependencies {
                // OkHttp dependencies
            }
        }
    }
}

Такая реализация требует нетривиальной настройки:

  • Необходимо настроить атрибуты Gradle на стороне :shared и на стороне каждого потребителя. Иначе Gradle не сможет разрешить зависимости в таких проектах, поскольку без дополнительной информации неясно, следует ли предоставить потребителю реализацию на основе Ktor или OkHttp.

  • Необходимо вручную настроить набор исходного кода commonJvmMain.

  • Для настройки используются несколько низкоуровневых абстракций и API Gradle и плагина Kotlin Gradle.

Как теперь лучше поступить?

Настройка сложна, потому что реализации на основе Ktor и OkHttp находятся в одном проекте Gradle. Во многих случаях эти части можно вынести в отдельные проекты Gradle. Ниже приведен общий план такого рефакторинга:

  1. Замените две дублирующиеся целевые платформы в исходном проекте одной целевой платформой. Если у этих целевых платформ есть общий набор исходного кода, перенесите его исходный код и конфигурацию в набор исходного кода по умолчанию новой целевой платформы:

    // shared/build.gradle.kts:
    kotlin {
        jvm()
    
        sourceSets {
            jvmMain {
                // Copy the configuration of jvmCommonMain here
            }
        }
    }
    
  2. Добавьте два новых проекта Gradle, обычно вызвав include в файле settings.gradle.kts. Например:

    include(":okhttp-impl")
    include(":ktor-impl")
    
  3. Настройте каждый новый проект Gradle:

    • Скорее всего, вам не потребуется применять плагин kotlin("multiplatform"), поскольку эти проекты компилируются только для одной целевой платформы. В этом примере можно применить kotlin("jvm").

    • Перенесите содержимое исходных наборов, относящихся к целевым платформам, в соответствующие проекты, например из jvmKtorMain в ktor-impl/src.

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

    • Добавьте зависимость нового проекта Gradle от исходного проекта.

    // ktor-impl/build.gradle.kts:
    plugins {
        kotlin("jvm")
    }
    
    dependencies {
        project(":shared") // Add dependency on the original project
        // Copy dependencies of jvmKtorMain here
    }
    
    kotlin {
        compilerOptions {
            // Copy compiler options of jvmKtorMain here
        }
    }
    

Хотя такой подход требует больше усилий при первоначальной настройке, он не использует низкоуровневые сущности Gradle и плагина Kotlin Gradle, поэтому итоговую сборку проще использовать и поддерживать.

К сожалению, мы не можем предоставить подробные инструкции по миграции для каждого случая. Если приведенные выше инструкции вам не подходят, опишите свой вариант использования в этом запросе YouTrack.

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 1.9.20: добавить предупреждение об устаревании при использовании нескольких схожих целевых платформ в проектах Kotlin Multiplatform

  • 2.1.0: сообщать об ошибке в таких случаях, за исключением целевых платформ Kotlin/JS; подробнее об этом исключении см. запрос в YouTrack

Устаревшая поддержка многоплатформенных библиотек, опубликованных в устаревшем режиме

Что изменилось?

Ранее мы объявили устаревшим устаревший режим в проектах Kotlin Multiplatform, который предотвращает публикацию «устаревших» бинарных файлов, и рекомендовали перенести проекты на иерархическую структуру.

Чтобы продолжить постепенный отказ от «устаревших» бинарных файлов в экосистеме, начиная с Kotlin 1.9.0 мы также не рекомендуем использовать устаревшие библиотеки. Если проект зависит от устаревших библиотек, вы увидите следующее предупреждение:

The dependency group:artifact:1.0 was published in the legacy mode. Support for such dependencies will be removed in the future

Как теперь лучше поступить?

Если вы используете многоплатформенные библиотеки, большинство из них уже перешло в режим «иерархической структуры», поэтому достаточно обновить версию библиотеки. Подробности см. в документации соответствующих библиотек.

Если библиотека пока не поддерживает бинарные файлы, не относящиеся к устаревшему режиму, свяжитесь с ее сопровождающими и сообщите им об этой проблеме совместимости.

Если вы автор библиотеки, обновите плагин Kotlin Gradle до последней версии и убедитесь, что вы исправили устаревшие свойства Gradle.

Команда Kotlin стремится помочь экосистеме выполнить переход, поэтому, если у вас возникнут проблемы, создайте запрос в YouTrack.

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 1.9.0: добавить предупреждение об устаревании для зависимостей от устаревших библиотек

  • 2.0.0: повысить уровень предупреждения для зависимостей от устаревших библиотек до ошибки

  • >2.0.0: удалить поддержку зависимостей от устаревших библиотек; использование таких зависимостей может привести к сбоям сборки

Устаревшие свойства Gradle для поддержки иерархической структуры

Что изменилось?

В ходе развития Kotlin поддержка иерархической структуры постепенно добавлялась в многоплатформенные проекты. Она позволяет создавать промежуточные наборы исходного кода между общим набором исходного кода commonMain и набором для конкретной платформы, например jvmMain.

На переходный период, пока цепочка инструментов была недостаточно стабильной, были добавлены несколько свойств Gradle, позволяющих гибко включать и отключать эту возможность.

Начиная с Kotlin 1.6.20 поддержка иерархической структуры проекта включена по умолчанию. Однако эти свойства сохранили, чтобы можно было отключить ее при возникновении блокирующих проблем. После обработки всех отзывов мы начинаем полностью отказываться от этих свойств.

Теперь следующие свойства объявлены устаревшими:

  • kotlin.internal.mpp.hierarchicalStructureByDefault

  • kotlin.mpp.enableCompatibilityMetadataVariant

  • kotlin.mpp.hierarchicalStructureSupport

  • kotlin.mpp.enableGranularSourceSetsMetadata

  • kotlin.native.enableDependencyPropagation

Как теперь лучше поступить?

  • Удалите эти свойства из файлов gradle.properties и local.properties.

  • Не задавайте их программно в скриптах сборки Gradle или плагинах Gradle.

  • Если устаревшие свойства задаются сторонним плагином Gradle, используемым в вашей сборке, попросите сопровождающих плагина не задавать эти свойства.

Поскольку с Kotlin 1.6.20 поведение цепочки инструментов Kotlin по умолчанию не зависит от таких свойств, мы не ожидаем серьезных последствий. Большинство изменений будет заметно сразу после повторной сборки проекта.

Если вы автор библиотеки и хотите подстраховаться, проверьте, что потребители могут использовать вашу библиотеку.

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 1.8.20: выводить предупреждение при использовании устаревших свойств Gradle

  • 1.9.20: повысить уровень этого предупреждения до ошибки

  • 2.0.0: удалить устаревшие свойства; плагин Kotlin Gradle игнорирует их использование

Если маловероятные проблемы все же возникнут после удаления этих свойств, создайте запрос в YouTrack.

Устаревший API предустановок целевых платформ

Что изменилось?

На самых ранних этапах разработки в Kotlin Multiplatform появился API для работы с так называемыми предустановками целевых платформ. Каждая предустановка по сути представляла собой фабрику целевых платформ Kotlin Multiplatform. Этот API оказался во многом избыточным, поскольку функции DSL, такие как jvm() или iosSimulatorArm64(), решают те же задачи, но значительно проще и лаконичнее.

Чтобы уменьшить путаницу и предоставить более ясные рекомендации, все API, связанные с предустановками, теперь объявлены устаревшими в публичном API плагина Kotlin Gradle. К ним относятся:

  • Свойство presets в org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

  • Интерфейс org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset и все его наследники

  • Перегрузки fromPreset

Как теперь лучше поступить?

Вместо них используйте соответствующие целевые платформы Kotlin, например:

Раньше

Теперь

kotlin {
    targets {
        fromPreset(presets.iosArm64, 'ios')
    }
}
kotlin {
    iosArm64()
}

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 1.9.20: выводить предупреждение при любом использовании API, связанного с предустановками

  • 2.0.0: повысить уровень этого предупреждения до ошибки

  • 2.2.0: удалить API, связанный с предустановками, из публичного API плагина Kotlin Gradle; исходный код, в котором он по-прежнему используется, завершит компиляцию с ошибками «unresolved reference», а бинарные файлы (например, плагины Gradle) могут завершиться ошибками связывания, если их не перекомпилировать с последними версиями плагина Kotlin Gradle

Устаревшие сокращения целевых платформ Apple

Что изменилось?

Мы объявляем устаревшими сокращения целевых платформ ios(), watchos() и tvos() в DSL Kotlin Multiplatform. Они были предназначены для частичного создания иерархии наборов исходного кода для целевых платформ Apple. Однако их оказалось сложно расширять, и иногда они вызывали путаницу.

Например, сокращение ios() создавало целевые платформы iosArm64 и iosX64, но не включало целевую платформу iosSimulatorArm64, необходимую для работы на компьютерах с чипами Apple M. Однако это сокращение было сложно изменить, не вызвав проблем в существующих проектах пользователей.

Как теперь лучше поступить?

Теперь плагин Kotlin Gradle предоставляет встроенный шаблон иерархии. Начиная с Kotlin 1.9.20 он включен по умолчанию и содержит предопределенные промежуточные наборы исходного кода для распространенных случаев использования.

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

Например, если в проекте есть целевые платформы iosArm64 и iosSimulatorArm64, плагин автоматически создаст промежуточные наборы исходного кода iosMain и iosTest. Если в проекте есть целевые платформы iosArm64 и macosArm64, будут созданы наборы исходного кода appleMain и appleTest.

Подробнее см. в разделе Иерархическая структура проекта

Когда изменения вступят в силу?

Ниже приведен планируемый цикл устаревания:

  • 1.9.20: выводить предупреждение при использовании сокращений целевых платформ ios(), watchos() и tvos(); вместо них по умолчанию включается шаблон иерархии

  • 2.1.0: выводить ошибку при использовании сокращений целевых платформ

  • 2.2.0: удалить DSL сокращений целевых платформ из плагина Kotlin Multiplatform Gradle

Неверная версия фреймворка iOS после обновления Kotlin

В чем проблема?

При использовании прямой интеграции изменения в коде Kotlin могут не отображаться в приложении iOS в Xcode. Прямая интеграция настраивается с помощью задачи embedAndSignAppleFrameworkForXcode, которая связывает фреймворк iOS из многоплатформенного проекта с приложением iOS в Xcode.

Это может произойти, если в многоплатформенном проекте вы обновите Kotlin с версии 1.9.2x до 2.0.0 (или вернетесь с 2.0.0 на 1.9.2x), затем внесете изменения в файлы Kotlin и попробуете собрать приложение: Xcode может ошибочно использовать предыдущую версию фреймворка iOS. Поэтому изменения не будут видны в приложении iOS в Xcode.

Как обойти эту проблему?

  1. В Xcode очистите каталоги сборки с помощью команды Продукт | Очистить папку сборки.

  2. В терминале выполните следующую команду:

    ./gradlew clean
    
  3. Соберите приложение еще раз, чтобы убедиться, что используется новая версия фреймворка iOS.

Когда проблема будет устранена?

Мы планируем устранить эту проблему в Kotlin 2.0.10. Проверить, доступны ли предварительные версии Kotlin 2.0.10, можно в разделе Участие в программе раннего доступа Kotlin.

Подробнее см. в соответствующем запросе в YouTrack.

Kotlin 1.9.0−1.9.25

В этом разделе рассматриваются несовместимые изменения, для которых завершился цикл устаревания и которые вступают в силу в Kotlin 1.9.0−1.9.25.

Удаление API для непосредственного добавления наборов исходного кода Kotlin в компиляцию Kotlin

Что изменилось?

Доступ к KotlinCompilation.source удален. Такой код больше не поддерживается:

kotlin {
    jvm()
    js()
    iosArm64()
    iosSimulatorArm64()
    
    sourceSets {
        val commonMain by getting
        val myCustomIntermediateSourceSet by creating {
            dependsOn(commonMain)
        }
        
        targets["jvm"].compilations["main"].source(myCustomIntermediateSourceSet)
    }
}

Как теперь лучше поступить?

Вместо KotlinCompilation.source(someSourceSet) добавьте исходные файлы непосредственно в соответствующий набор исходного кода с помощью функции .srcDir(). Или создайте новый набор исходного кода, добавив связь dependsOn от набора исходного кода по умолчанию KotlinCompilation к someSourceSet. Также можно напрямую обратиться к исходному коду с помощью соглашений для наборов исходного кода: они удобны для работы в IDE и считаются наиболее надежным подходом. Наконец, можно использовать KotlinCompilation.defaultSourceSet.dependsOn(someSourceSet), который работает во всех случаях.

Изменить код выше можно одним из следующих способов:

kotlin {
    jvm()
    js()
    iosArm64()
    iosSimulatorArm64()

    sourceSets {
        val myCustomIntermediateSourceSet by creating {
            // The commonMain source set needs to be accessed with the 
            // .get() function
            dependsOn(commonMain.get())
        }

        // Option #1. Add your sources directly to the appropriate source
        // set:
        commonMain {
            kotlin.srcDir(layout.projectDirectory.dir("src/commonMain/my-custom-kotlin"))
        }

        // Option #2. Use the conventions provided with default
        // Kotlin Multiplatform targets for their main and test
        // source sets:
        jvmMain {
            dependsOn(myCustomIntermediateSourceSet)
        }

        // Option #3. A more generic solution. Use it if your build script 
        // requires a more advanced approach:
        targets["jvm"].compilations["main"].defaultSourceSet.dependsOn(myCustomIntermediateSourceSet)
    }
}

Когда изменения вступят в силу?

Цикл устаревания:

  • 1.9.0: при использовании KotlinCompilation.source появляется предупреждение об устаревании

  • 1.9.20: предупреждение становится ошибкой

  • 2.3.0: KotlinCompilation.source удаляется из плагина Kotlin Gradle, попытки использовать его приводят к ошибке «unresolved reference» при компиляции скрипта сборки

Переход с плагина kotlin-js Gradle на плагин kotlin-multiplatform Gradle

Что изменилось?

Начиная с Kotlin 1.9.0, плагин kotlin-js Gradle считается устаревшим. По сути, он дублировал функциональность плагина kotlin-multiplatform с целевой платформой js() и использовал ту же реализацию. Такое дублирование вызывало путаницу и увеличивало нагрузку на команду Kotlin по сопровождению. Рекомендуем перейти на плагин kotlin-multiplatform Gradle с целевой платформой js().

Как теперь лучше поступить?

  1. Удалите плагин kotlin-js Gradle из проекта и примените kotlin-multiplatform в файле settings.gradle.kts, если используете блок pluginManagement {}:

    // settings.gradle.kts:
    pluginManagement {
        plugins {
            // Remove the following line:
            kotlin("js") version "1.9.0"
        }
    
        repositories {
            // ...
        }
    }
    
    // settings.gradle.kts:
    pluginManagement {
        plugins {
            // Add the following line instead:
            kotlin("multiplatform") version "1.9.0"
        }
    
        repositories {
            // ...
        }
    }
    

    Если вы применяете плагины другим способом, инструкции по миграции см. в документации Gradle.

  2. Переместите исходные файлы из папок main и test в папки jsMain и jsTest в том же каталоге.

  3. Измените объявления зависимостей:

    • Рекомендуем использовать блок sourceSets {} и настраивать зависимости соответствующих наборов исходного кода: jsMain {} для зависимостей production-кода и jsTest {} для тестовых зависимостей. Подробнее см. в разделе Добавление зависимостей.

    • Однако, если вы хотите объявлять зависимости в блоке верхнего уровня, замените объявления api("group:artifact:1.0") на add("jsMainApi", "group:artifact:1.0") и так далее.

      В этом случае убедитесь, что блок dependencies {} верхнего уровня расположен после блока kotlin {}. Иначе возникнет ошибка «Configuration not found».

    Изменить код в файле build.gradle.kts можно одним из следующих способов:

    // build.gradle.kts:
    plugins {
        kotlin("js") version "1.9.0"
    }
    
    dependencies {
        testImplementation(kotlin("test"))
        implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0")
    }
    
    kotlin {
        js {
            // ...
        }
    }
    
    // build.gradle.kts:
    plugins {
        kotlin("multiplatform") version "1.9.0"
    }
    
    kotlin {
        js {
            // ...
        }
    
        // Option #1. Declare dependencies in the sourceSets {} block:
        sourceSets {
            val jsMain by getting {
                dependencies {
                    // No need for the js prefix here, you can just copy and paste it from the top-level block
                    implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0")
                }
           }
        }
    }
    
    dependencies {
        // Option #2. Add the js prefix to the dependency declaration:
        add("jsTestImplementation", kotlin("test"))
    }
    
  4. В большинстве случаев DSL, предоставляемый плагином Kotlin Gradle внутри блока kotlin {}, остается без изменений. Однако, если вы обращались к низкоуровневым сущностям Gradle, таким как задачи и конфигурации, по именам, теперь их нужно изменить, обычно добавив префикс js. Например, задачу browserTest теперь можно найти под именем jsBrowserTest.

Когда изменения вступят в силу?

Цикл устаревания плагина kotlin-js Gradle:

  • 1.9.0: при использовании плагина kotlin-js появляется предупреждение об устаревании

  • 2.4.0: предупреждение становится ошибкой

Устаревшая предустановка jvmWithJava

Что изменилось?

targetPresets.jvmWithJava считается устаревшим, и его использование не рекомендуется.

Как теперь лучше поступить?

Вместо этого используйте целевую платформу jvm { withJava() }. Обратите внимание: после перехода на jvm { withJava() } потребуется изменить пути к каталогам с исходными файлами .java.

Например, если вы используете целевую платформу jvm с именем по умолчанию «jvm»:

Раньше

Теперь

src/main/java

src/jvmMain/java

src/test/java

src/jvmTest/java

Когда изменения вступят в силу?

Планируемый цикл устаревания:

  • 1.3.40: при использовании targetPresets.jvmWithJava появляется предупреждение

  • 1.9.20: предупреждение становится ошибкой

  • >1.9.20: API targetPresets.jvmWithJava удаляется; попытки его использовать приводят к сбою компиляции скрипта сборки

Несмотря на то, что весь API targetPresets считается устаревшим, для предустановки jvmWithJava действует другой график устаревания.

Устаревшая компоновка наборов исходного кода Android

Что изменилось?

Новая компоновка наборов исходного кода Android используется по умолчанию начиная с Kotlin 1.9.0. Поддержка устаревшей компоновки прекращается, и использование свойства Gradle kotlin.mpp.androidSourceSetLayoutVersion теперь вызывает предупреждение об устаревании.

Когда изменения вступят в силу?

Цикл устаревания:

  • <=1.9.0: при использовании kotlin.mpp.androidSourceSetLayoutVersion=1 выводится предупреждение; его можно подавить с помощью свойства Gradle kotlin.mpp.androidSourceSetLayoutVersion1.nowarn=true

  • 1.9.20: предупреждение становится ошибкой; эту ошибку нельзя подавить

  • 2.4.0: поддержка устаревшей компоновки наборов исходного кода Android прекращается, а свойство Gradle kotlin.mpp.androidSourceSetLayoutVersion=1 удаляется

Устаревшие commonMain и commonTest с пользовательским dependsOn

Что изменилось?

Наборы исходного кода commonMain и commonTest обычно представляют собой корневые наборы иерархий исходного кода main и test соответственно. Однако это поведение можно было переопределить, вручную настроив связи dependsOn для этих наборов исходного кода.

Поддержка такой конфигурации требует дополнительных усилий и знания внутренних механизмов многоплатформенной сборки. Кроме того, это снижает читаемость и повторное использование кода, поскольку приходится изучать конкретный скрипт сборки, чтобы убедиться, что commonMain является корнем иерархии набора исходного кода main.

Поэтому доступ к dependsOn в commonMain и commonTest теперь считается устаревшим.

Как теперь лучше поступить?

Предположим, вам нужно перейти на версию 1.9.20 для набора исходного кода customCommonMain, использующего commonMain.dependsOn(customCommonMain). В большинстве случаев customCommonMain участвует в тех же компиляциях, что и commonMain, поэтому можно объединить customCommonMain с commonMain:

  1. Скопируйте исходные файлы из customCommonMain в commonMain.

  2. Добавьте все зависимости customCommonMain в commonMain.

  3. Добавьте все настройки параметров компилятора из customCommonMain в commonMain.

В редких случаях customCommonMain может участвовать в большем количестве компиляций, чем commonMain. Такая конфигурация требует дополнительной низкоуровневой настройки скрипта сборки. Если вы не уверены, что это ваш случай, скорее всего, это не так.

Если это ваш случай, поменяйте эти наборы исходного кода местами: перенесите исходные файлы и настройки из customCommonMain в commonMain и наоборот.

Когда изменения вступят в силу?

Планируемый цикл устаревания:

  • 1.9.0: при использовании dependsOn в commonMain выводится предупреждение

  • >=1.9.20: при использовании dependsOn в commonMain или commonTest выводится ошибка

Новый подход к предварительным объявлениям

Что изменилось?

Команда JetBrains изменила подход к предварительным объявлениям в Kotlin, чтобы сделать их поведение более предсказуемым:

  • Импортировать предварительные объявления можно только из пакетов cnames или objcnames.

  • Преобразование типов к соответствующему предварительному объявлению C и Objective-C и обратно необходимо выполнять явно.

Как теперь лучше поступить?

  • Рассмотрим библиотеку C с library.package, в которой объявлено предварительное объявление cstructName. Раньше его можно было импортировать непосредственно из библиотеки с помощью import library.package.cstructName. Теперь для этого можно использовать только специальный пакет предварительных объявлений: import cnames.structs.cstructName. То же относится к objcnames.

  • Рассмотрим две библиотеки objcinterop: одна использует objcnames.protocols.ForwardDeclaredProtocolProtocol, а другая содержит его фактическое определение:

    // First objcinterop library
    #import <Foundation/Foundation.h>
    
    @protocol ForwardDeclaredProtocol;
    
    NSString* consumeProtocol(id<ForwardDeclaredProtocol> s) {
        return [NSString stringWithUTF8String:"Protocol"];
    }
    
    // Second objcinterop library
    // Header:
    #import <Foundation/Foundation.h>
    @protocol ForwardDeclaredProtocol
    @end
    // Implementation:
    @interface ForwardDeclaredProtocolImpl : NSObject <ForwardDeclaredProtocol>
    @end
    
    id<ForwardDeclaredProtocol> produceProtocol() {
        return [ForwardDeclaredProtocolImpl new];
    }
    

    Раньше объекты можно было беспрепятственно передавать между ними. Теперь для предварительного объявления требуется явное приведение типа as:

    // Kotlin code:
    fun test() {
        consumeProtocol(produceProtocol() as objcnames.protocols.ForwardDeclaredProtocolProtocol)
    }
    

    Преобразовать тип к objcnames.protocols.ForwardDeclaredProtocolProtocol можно только из соответствующего реального класса. В противном случае возникнет ошибка.

Когда изменения вступят в силу?

Начиная с Kotlin 1.9.20, преобразование типов к соответствующим предварительным объявлениям C и Objective-C и обратно необходимо выполнять явно. Кроме того, импортировать предварительные объявления теперь можно только с помощью специальных пакетов.

Kotlin 1.7.0−1.8.22

В этом разделе рассматриваются несовместимые изменения, для которых завершился цикл устаревания и которые вступают в силу в Kotlin 1.7.0−1.8.22.

Устаревшая совместимость плагина Kotlin Multiplatform Gradle с плагинами Java для Gradle

Что изменилось?

Из-за проблем совместимости плагина Kotlin Multiplatform Gradle с плагинами Gradle Java, Java Library и Application теперь при применении этих плагинов к одному проекту выводится предупреждение об устаревании. Предупреждение также появляется, если другой плагин Gradle в вашем многоплатформенном проекте применяет плагин Java для Gradle. Например, плагин Spring Boot Gradle автоматически применяет плагин Application.

Мы добавили это предупреждение об устаревании из-за фундаментальных проблем совместимости между моделью проекта Kotlin Multiplatform и плагинами экосистемы Java в Gradle. Плагины экосистемы Java в Gradle сейчас не учитывают, что другие плагины могут:

  • Публиковать артефакты или выполнять компиляцию для целевой платформы JVM иначе, чем плагины экосистемы Java.

  • Использовать в одном проекте две разные целевые платформы JVM, например JVM и Android.

  • Иметь сложную структуру многоплатформенного проекта с несколькими целевыми платформами, отличными от JVM.

К сожалению, в настоящее время Gradle не предоставляет API для решения этих проблем.

Ранее в Kotlin Multiplatform мы использовали обходные решения, упрощающие интеграцию с плагинами экосистемы Java. Однако эти решения так и не устранили проблемы совместимости, а после выпуска Gradle 8.8 использовать их стало невозможно. Подробнее см. в задаче в YouTrack.

Хотя мы пока не знаем, как именно решить эту проблему совместимости, мы намерены и дальше поддерживать некоторую форму компиляции исходного кода Java в ваших проектах Kotlin Multiplatform. Как минимум мы будем поддерживать компиляцию исходных файлов Java и использование плагина java-base Gradle в многоплатформенных проектах.

Как теперь лучше поступить?

Если вы видите это предупреждение об устаревании в многоплатформенном проекте, рекомендуем:

  1. Определить, действительно ли вам нужен плагин Java для Gradle в проекте. Если нет, рассмотрите возможность его удаления.

  2. Проверить, используется ли плагин Java для Gradle только для одной задачи. Если да, возможно, вы сможете без особых усилий удалить плагин. Например, если задача использует плагин Java для Gradle, чтобы создать JAR-файл с Javadoc, вместо этого можно определить задачу Javadoc вручную.

Если же вы хотите использовать в многоплатформенном проекте и плагин Kotlin Multiplatform Gradle, и эти плагины Java для Gradle, рекомендуем:

  1. Создать отдельный подпроект в проекте Gradle.

  2. Применить плагин Java для Gradle в отдельном подпроекте.

  3. Добавить в отдельный подпроект зависимость от родительского многоплатформенного проекта.

Отдельный подпроект не должен быть многоплатформенным проектом и должен использоваться только для настройки зависимости от многоплатформенного проекта.

Например, у вас есть многоплатформенный проект с названием my-main-project, и вы хотите использовать плагин Java Library для Gradle.

После создания подпроекта, назовем его subproject-A, структура родительского проекта должна выглядеть так:

.
├── build.gradle
├── settings.gradle.kts
├── subproject-A
    └── build.gradle.kts
    └── src
        └── Main.java

В файле build.gradle.kts подпроекта примените плагин Java Library в блоке plugins {}:

plugins {
    id("java-library")
}
plugins {
    id('java-library')
}

В файле build.gradle.kts подпроекта добавьте зависимость от родительского многоплатформенного проекта:

dependencies {
    implementation(project(":my-main-project")) // The name of your parent multiplatform project
}
dependencies {
    implementation project(':my-main-project') // The name of your parent multiplatform project
}

Теперь родительский проект настроен для работы с обоими плагинами.

Новый подход к автоматически создаваемым целевым платформам

Что изменилось?

Создаваемые Gradle автоматически аксессоры целевых платформ больше не доступны в блоке kotlin.targets {}. Вместо них используйте метод findByName("targetName").

Обратите внимание: такие аксессоры по-прежнему доступны в случае kotlin.targets {}, например kotlin.targets.linuxX64.

Как теперь лучше поступить?

Раньше

Теперь

kotlin {
    targets {
        configure(['windows',
            'linux']) {
        }
    }
}
kotlin {
    targets {
        configure([findByName('windows'),
            findByName('linux')]) {
        }
    }
}

Когда изменения вступят в силу?

В Kotlin 1.7.20 при использовании аксессоров целевых платформ в блоке kotlin.targets {} появляется ошибка.

Подробнее см. в соответствующей задаче в YouTrack.

Изменения входных и выходных данных задач компиляции Gradle

Что изменилось?

Задачи компиляции Kotlin больше не наследуют задачу Gradle AbstractCompile с входными данными sourceCompatibility и targetCompatibility, поэтому они недоступны в скриптах пользователей Kotlin.

Другие несовместимые изменения в задачах компиляции:

Как теперь лучше поступить?

Раньше

Теперь

Входные данные SourceTask.stableSources больше недоступны.

Вместо них используйте входные данные sources. Методы setSource() также остаются доступными.

Входные данные sourceFilesExtensions удалены.

Задачи компиляции по-прежнему реализуют интерфейс PatternFilterable. Используйте его методы для фильтрации исходных файлов Kotlin.

Выходные данные Gradle destinationDir: File считаются устаревшими.

Вместо них используйте выходные данные destinationDirectory: DirectoryProperty.

Свойство classpath задачи KotlinCompile считается устаревшим.

Теперь все задачи компиляции используют входные данные libraries для списка библиотек, необходимых для компиляции.

Когда изменения вступят в силу?

В Kotlin 1.7.20 входные данные становятся недоступны, выходные данные заменяются, а свойство classpath считается устаревшим.

Подробнее см. в соответствующей задаче в YouTrack.

Новые имена конфигураций зависимостей компиляции

Что изменилось?

Конфигурации компиляции, созданные плагином Kotlin Multiplatform Gradle, получили новые имена.

В целевой платформе проекта Kotlin Multiplatform есть две компиляции по умолчанию: main и test. Для каждой из этих компиляций предусмотрен собственный набор исходного кода по умолчанию, например jvmMain и jvmTest. Раньше имена конфигурации тестовой компиляции и ее набора исходного кода по умолчанию совпадали. Это могло приводить к конфликту имен и проблемам при включении конфигурации с атрибутами для конкретной платформы в другую конфигурацию.

Теперь к именам конфигураций компиляции добавлен суффикс Compilation, поэтому проекты и плагины со старыми жестко заданными именами конфигураций больше не компилируются.

Имена конфигураций зависимостей соответствующего набора исходного кода не изменились.

Как теперь лучше поступить?

Раньше

Теперь

Зависимости компиляции jvmMain

jvm<Scope>
jvmCompilation<Scope>
dependencies {
    add("jvmImplementation",
        "foo.bar.baz:1.2.3")
}
dependencies {
    add("jvmCompilationImplementation",
        "foo.bar.baz:1.2.3")
}

Зависимости набора исходного кода jvmMain

jvmMain<Scope>

Зависимости компиляции jvmTest

jvmTest<Scope>
jvmTestCompilation<Scope>

Зависимости набора исходного кода jvmTest

jvmTest<Scope>

Доступны области Api, Implementation, CompileOnly и RuntimeOnly.

Когда изменения вступят в силу?

В Kotlin 1.8.0 при использовании старых имен конфигураций в жестко заданных строках появляется ошибка.

Подробнее см. в соответствующей задаче в YouTrack.

7 сентября 2026 г.
klibs.io, каталог библиотек для Kotlin MultiplatformСтруктура набора исходников Android

© 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-compatibility-guide.html

Spec-Zone.ru

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