【问题标题】:How to share Java code between Android and JVM targets (with Kotlin Multiplatform)?如何在 Android 和 JVM 目标之间共享 Java 代码(使用 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-multiplatformcom.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 或类似的东西?
  • @DmitryKolesnikovich 不确定这是否有帮助:discuss.kotlinlang.org/t/…

标签: kotlin kotlin-multiplatform


【解决方案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 可以同时保留JVMAndroid 目标

~~~~~~~~~~~~~

为了解决您的问题,您需要:

  • 拆分您的 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 withJavaandroid 目标放在同一个kotlin-multiplatform 项目中。你最终会得到Error: The 'java' plugin has been applied, but it is not compatible with the Android plugins
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 2021-10-06
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
相关资源
最近更新 更多