Используйте подпроекты 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'
demo / 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')
}
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
). - Если нет специфичного для платформы кода, этот модуль может быть просто файлом Gradle в каталоге.
- Модули платформы могут быть удобно размещены внутри общего каталога модулей (так
alpha:alpha-js
). - Общий модуль не должен ссылаться на модули платформы; модули платформы имеют зависимость
expectedBy project(":the_common_module")
, Если модуль
alpha
зависит отbeta
, затемalpha
должен иметь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, потому что он очень длинный.
Подмодули должны быть объявлены в рамках зависимостей с помощью наборов источников. Если подмодуль определен в общем наборе исходников, его не нужно определять в одной из конкретной платформы, но не наоборот.
build.gradle.kts (:kmm_shared:feature_a)
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api(project(":kmm_shared:domain"))
}
}
}
При этом нет необходимости, чтобы исходный набор Android также включал зависимость.
ГЛ
Для тех, кто приходит с поиском Google для:
"Фактическая функция / класс / объект-компаньон / и т.д. не имеет соответствующего ожидаемого объявления"
Попробуйте очистить и пересобрать проект, для меня это выявило ряд других ошибок, которые мешали сборке.