如何在 Android 和 JVM 目标之间共享 Java 代码(使用 Kotlin Multiplatform)?
Posted
技术标签:
【中文标题】如何在 Android 和 JVM 目标之间共享 Java 代码(使用 Kotlin Multiplatform)?【英文标题】:How to share Java code between Android and JVM targets (with Kotlin Multiplatform)? 【发布时间】:2020-04-16 03:23:30 【问题描述】:我正在尝试使用 Kotlin 多平台功能在 android 和 JVM 目标之间共享 Java 代码(示例项目:https://github.com/dmitrykolesnikovich/accessJavaCode-issue)
简单地说,“:library1”和“:library2”都是针对 JVM 和 Android 的 Kotlin 多平台库。 “:library2”依赖于“:library1”。他们都使用 Kotlin 和 Java。 ":library2" 旨在成为 1) Android 应用程序和 2) 桌面 (JavaFX) 应用程序的依赖项。这就是为什么 1)AAR 工件和 2)JAR 工件都需要(?) - 所以我使用 1)Android 目标和 2)JVM 目标用于“:library1”和“:library2”。
问题是,当我在 ":library1" 中有 Java 代码时
public class JavaCode // JavaCode.java
“:library2”中的 Kotlin 代码依赖于“:library1”
class AccessJavaCode : JavaCode() // AccessJavaCode.kt
Android 目标可以识别 Java,但 JVM 目标不能:
> Task :library2:compileKotlinJvm FAILED
e: AccessJavaCode.kt: (3, 38): Unresolved reference: JavaCode
在 gradle config 中我定义了两个插件:kotlin-multiplatform
和 com.android.library
:
apply plugin: "kotlin-multiplatform"
apply plugin: "com.android.library"
kotlin
targets
jvm()
android()
sourceSets
jvmMain
dependencies
api kotlin("stdlib-common")
api kotlin("stdlib-jdk8")
androidMain
dependsOn jvmMain
android
compileSdkVersion 28
sourceSets
main
java.srcDirs += "src/jvmMain/kotlin" // Android target recognizes Java with this
manifest.srcFile "src/androidMain/AndroidManifest.xml"
我很确定我的 gradle 文件很简单。非常感谢你们的帮助。
【问题讨论】:
库 1 是纯 java 库 2 是 android 库? ":library1" 和 ":library2" 都是针对 JVM 和 Android 的 Kotlin 多平台库。他们都使用 Kotlin 和 Java。 ":library2" 旨在成为 1) Android 应用程序和 2) 桌面 (JavaFX) 应用程序的依赖项。这就是为什么 1)AAR 工件和 2)JAR 工件都需要(?) - 所以我使用 1)Android 目标和 2)JVM 目标用于 ":library1" 和 ":library2"。 好的,但我的问题是这些库是使用 android 还是 java fx 框架,还是它们只是使用标准的 java 代码操作。您是否打算让其中一个库创建 Fragment 或类似的东西? 请帮忙:blog.gradle.org/alignment-with-gradle-module-metadata @DmitryKolesnikovich 不确定这是否有帮助:discuss.kotlinlang.org/t/… 【参考方案1】:~~~~编辑~~~~
在不失去为library1
生成android 存档.aar
的能力的情况下,另一个解决方法是根据原始library1
的拆分版本的预编译人工制品制作同一库的新版本。
所以你最终会得到一个多模块的 gradle 项目,如下所示:
library1-jvm 启用了 java 插件 library1-android 启用了 android 插件 library1 将依赖于预构建的 library1-jvm.jar 和 library1-android.aar您可以使用任何您喜欢的方式发布这些人工制品,但local maven repo
应该可以正常工作!
这意味着替换:
kotlin
targets
jvm()
android()
sourceSets
jvmMain
dependencies
api kotlin("stdlib-common")
api kotlin("stdlib-jdk8")
androidMain
dependsOn jvmMain
与:
kotlin
targets
jvm()
android()
sourceSets
jvmMain
dependencies
api kotlin("stdlib-common")
api kotlin("stdlib-jdk8")
api "com.company:library-jvm:1.0.0"
androidMain
dependsOn jvmMain
dependencies
api "com.company:library-android:1.0.0"
这样,您在最终的library1
中根本不需要 java 插件,因为所有 java 代码都已经在单独的步骤中构建。
因此library1
可以同时保留JVM
和Android
目标
~~~~~~~~~~~~~
为了解决您的问题,您需要:
拆分您的 build.gradle 配置以便每个库有一个配置,这是必需的,因为您不能同时为同一个 Gradle 项目启用 java 插件和 android,否则您将得到以下结果Error: The 'java' plugin has been applied, but it is not compatible with the Android plugins
如果您希望 JVM 目标识别您的 Java 源文件,请在您的 library1
项目中启用 java 插件。
Java 源文件需要放在kotlin
源根目录的兄弟目录java
中。
更多信息:java-support-in-jvm-targets 的 Kotlin 文档
我还创建了一个pull request 来解决您的问题。
这种方法的缺点是您将无法为library1
生成android 存档.aar
,但我想在您的android 项目中使用java 存档.jar
应该不成问题.
library1/build.gradle:
apply plugin: "kotlin-multiplatform"
kotlin
jvm
withJava()
sourceSets
jvmMain
dependencies
api kotlin("stdlib-common")
api kotlin("stdlib-jdk8")
library2/build.gradle:
apply plugin: "kotlin-multiplatform"
apply plugin: "com.android.library"
kotlin
jvm()
android()
sourceSets
jvmMain.dependencies
api project(":library1")
androidMain
dependsOn jvmMain
android
compileSdkVersion 28
sourceSets
main
java.srcDirs += "src/jvmMain/kotlin"
manifest.srcFile "src/androidMain/AndroidManifest.xml"
【讨论】:
但是如果 ":library1" 必须有 android 特定的类呢?有什么办法可以解决吗? (您的解决方案是我自己认为的,但这对我来说并不理想,所以我决定问一下) 我不明白您如何让library1
包含一些特定于android 的代码,并期望导出的.jar
在任何JVM 上运行。这是一个破碎的架构......
我在androidMain
源集中有android 特定代码。这就是导出的.jar
不会有任何android 特定代码的方式。
好的,我明白了,但不幸的是,截至目前kotlin 1.3.61
,没有办法将jvm withJava
和android
目标放在同一个kotlin-multiplatform
项目中。你最终会得到Error: The 'java' plugin has been applied, but it is not compatible with the Android plugins
让我们continue this discussion in chat。以上是关于如何在 Android 和 JVM 目标之间共享 Java 代码(使用 Kotlin Multiplatform)?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Eclipse Swing/maven 和 Androidstudio/gradle 项目之间共享代码?
如何在主机和来宾机器之间的共享 nfs 目录中映射符号链接目标路径?