Используйте подпроекты Gradle с мультиплатформой Kotlin

Я использую мультиплатформу Kotlin (JVM & JS), которая в IDEA создает три проекта: demo, demo-js и demo-jvm.

Я хотел бы разделить общий код на несколько подпроектов/подмодулей. Скажем, я добавляю commonmod; как мне его скомпилировать?

Ошибка прямо сейчас для gradle run -p demo-jvm:

demo/demo-js/src/main/kotlin/demo/commonmod/example.kt: (3, 12): Actual function 'getPlatform' has no corresponding expected declaration

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


В качестве минимального, но все же большого примера у меня есть:

demo/settings.gradle:

rootProject.name = 'demo'

include 'demo-jvm', 'demo-js', 'commonmod'

демонстрация/build.gradle:

buildscript { ... }

apply plugin: 'kotlin-platform-common'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version"
    compile project(':commonmod')
}

demo/demo-jvm/settings.gradle:

rootProject.name = 'demo'

demo/demo-jvm/build.gradle:

buildscript { ... }

apply plugin: 'kotlin-platform-jvm'
apply plugin: 'application'

repositories {
    mavenCentral()
}

mainClassName = "demo.MainKt"

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    expectedBy project(":")
    testCompile "junit:junit:4.12"
    testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
}

demo/demo-js/settings.gradle:

rootProject.name = 'demo'

demo/demo-js/build.gradle:

buildscript { ... }

apply plugin: 'kotlin-platform-js'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
    expectedBy project(":")
    testCompile "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version"
}

demo/commonmod/settings.gradle:

rootProject.name = 'demo'

include 'demo-jvm', 'demo-js'

demo/commonmod/build.gradle:

buildscript { ... }

apply plugin: 'kotlin-platform-common'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version"
    compile project(':demo-js')
    compile project(':demo-jvm')
}

person Mark    schedule 10.01.2018    source источник
comment
Я не знаю, актуально ли это для вас, но этот проект содержит полный пример со всеми прибамбасами, которые могут вам понадобиться.   -  person Adam Arold    schedule 29.03.2018
comment
Выглядит интересно, особенно когда проблема №10 будет решена, спасибо!   -  person Mark    schedule 30.03.2018


Ответы (3)


Это заняло сумасшедшее количество времени, поэтому я надеюсь, что это будет полезно для кого-то!

На Github есть функциональный пример: kotlin_multiplatform_gradle_demo

Несколько источников помогли, но многое было методом проб и ошибок, поэтому, если что-то не так, пожалуйста, дайте мне знать!


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

├── alpha
│   ├── alpha-js
│   │   └── build.gradle
│   ├── alpha-jvm
│   │   └── build.gradle
│   ├── build.gradle
│   └── src
│       └── main
│           ├── kotlin
│           │   └── demo
│           │       └── alpha
│           │           └── main.kt
├── beta
│   ├── beta-js
│   │   ├── build.gradle
│   │   └── src
│   │       └── main
│   │           └── kotlin
│   │               └── demo
│   │                   └── beta
│   │                       └── platform.kt
│   ├── beta-jvm
│   │   ├── build.gradle
│   │   └── src
│   │       └── main
│   │           └── kotlin
│   │               └── demo
│   │                   └── beta
│   │                       └── platform.kt
│   ├── build.gradle
│   └── src
│       └── main
│           └── kotlin
│               └── demo
│                   └── beta
│                       └── platform.kt
├── build.gradle
└── settings.gradle

Общие модули (alpha и beta) нуждаются в модулях платформы для каждой платформы, по крайней мере, с `build.gradle``.

Файл settings.gradle импортирует все модули, включая платформенные.

Зависимости, например. от альфы до беты, объявляется в общем альфа-модуле и во всех модулях альфа-платформы.


Некоторые закономерности, которые я изучил:

  • Каждый «обычный» (общий) модуль имеет один платформенный модуль для каждой платформы.
  • Для общего модуля alpha модуль платформы javascript должен называться alpha-js (аналогично -jvm).
  • Если нет кода для конкретной платформы, этот модуль может быть просто файлом градиента в каталоге.
  • Модули платформы можно удобно разместить внутри общего каталога модулей (так alpha:alpha-js).
  • Общий модуль не должен относиться к модулям платформы; модули платформы имеют зависимость expectedBy project(":the_common_module").
  • Если модуль alpha зависит от beta, то

    • alpha must have dependencies { compile project(":beta") }
    • alpha-js должен иметь dependencies { compile project(":beta:beta-js") } (помимо expectedBy)
    • alpha-jvm должен иметь dependencies { compile project(":beta:beta-jvm") } (в дополнение к expectedBy) и т. д.
  • Только топовый модуль имеет settings.gradle, который включает ВСЕ подмодули (включая платформенные).

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

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

person Mark    schedule 11.01.2018
comment
Большое спасибо за эти инструкции, вы сэкономили мне много времени. Я думаю, мы должны создать запрос функции для поддержки зависимости проекта компиляции ('...') между двумя общими модулями. Вы не знаете, есть ли он уже? - person Andi; 06.03.2018
comment
я не знаю ни об одном - person Mark; 07.03.2018
comment
@Andi Ты не можешь использовать compile project(':alpha-common') в beta-common? По крайней мере, можно использовать compile "some.groupid:some.artifactid:1.0.0" - person Simon Forsberg; 15.04.2018
comment
Это ключевой элемент информации: Зависимости, например. из альфа-версии в бета-версию, объявляется в общем альфа-модуле и во всех альфа-модулях платформы. - person Steven Jeuris; 02.10.2018
comment
Возможно, я немного опоздал на вечеринку @SimonForsberg, но у меня есть ответ на ваш вопрос. Не можете ли вы использовать compile project(':alpha-common') в бета-common. Да, вы можете, но по мере того, как вы добавляете свою зависимость к общему модулю, добавляйте соответствующие модули, специфичные для платформы, к их фактической версии для конкретной платформы, которая есть у вашего общего модуля. Надеюсь, это поможет кому-то - person andylamax; 27.10.2018
comment
Правильно ли я понимаю, что этот ответ устарел на сегодняшний день? - person Egor Okhterov; 12.12.2019
comment
@Pixar Ответ недавно не проверялся мной, поэтому я не знаю. Я надеюсь, что за последние два года стало легче. Хотя сопутствующий Github все еще набирает звезды, поэтому я думаю, что некоторые из них все еще верны... - person Mark; 12.12.2019
comment
@Mark Я просто изо всех сил пытаюсь настроить свой проект уже неделю и не смог найти в Интернете ни одного работающего проекта, которому я мог бы подражать. - person Egor Okhterov; 12.12.2019
comment
@Pixar Да, это было сложно, по крайней мере, в 2018 году, я не знаю ни о каких новых источниках, обязательно опубликуйте свое решение, если найдете его. - person Mark; 12.12.2019

Для тех, кто пришел из поиска Google для:

«Фактическая функция/класс/сопутствующий объект/и т. д. не имеет соответствующего ожидаемого объявления»

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

person CampbellMG    schedule 09.10.2018
comment
Я пришел к этому из поиска этой ошибки. Ошибка означает, что компилятор не может найти функцию/класс, не зависящую от платформы, и т. д., для которой функция/класс actual является реализацией конкретной платформы. - person Joost de Vries; 05.05.2019

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

build.gradle.kts (:kmm_shared:feature_a)

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                api(project(":kmm_shared:domain"))
            }
        }
}

При этом нет необходимости, чтобы исходный набор Android также включал зависимость.

GL

person Braian Coronel    schedule 08.12.2020