如何在 Android 和 JVM 目标之间共享 Java 代码(使用 Kotlin Multiplatform)?

Dmi*_*ich 9 kotlin kotlin-multiplatform

我正在尝试使用 Kotlin Multiplatform 功能在 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 工件都需要 (?) - 所以我为“:library1”和“:library2”使用 1) Android 目标和 2) JVM 目标。

问题是,当我在 ":library1" 中有 Java 代码时

public class JavaCode {} // JavaCode.java
Run Code Online (Sandbox Code Playgroud)

“:library2”中的 Kotlin 代码依赖于“:library1”

class AccessJavaCode : JavaCode() // AccessJavaCode.kt
Run Code Online (Sandbox Code Playgroud)

Android 目标可以识别 Java,但 JVM 目标不是:

> Task :library2:compileKotlinJvm FAILED
e: AccessJavaCode.kt: (3, 38): Unresolved reference: JavaCode
Run Code Online (Sandbox Code Playgroud)

在 gradle 配置中,我定义了两个插件: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"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我很确定我的 gradle 文件很简单。非常感谢你们的帮助。

Gom*_*ino 3

~~~~ 编辑 ~~~~

在不失去生成 android 存档的能力的情况.aarlibrary1解决该问题的另一个方法是根据原始library1.

所以你最终会得到一个多模块 gradle 项目,如下所示:

  • 启用了 java 插件的library1-jvm
  • 启用了 android 插件的library1-android
  • library1 依赖于预构建的library1-jvm.jar 和library1-android.aar

您可以使用任何您喜欢的方式来发布这些文物,但 alocal maven repo应该可以正常工作!

这意味着更换:

kotlin {
    targets {
        jvm()
        android()
    }
    sourceSets {
        jvmMain {
            dependencies {
                 api kotlin("stdlib-common")
                 api kotlin("stdlib-jdk8")
            }
        }
        androidMain {
            dependsOn jvmMain
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和:

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"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,您在 Final 中根本不需要 java 插件library1,因为所有 java 代码都已在单独的步骤中构建。

因此library1可以同时保留JVMAndroid目标

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

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

  • 拆分你的 build.gradle 配置,以便每个库有一个配置,这是必需的,因为你不能同时为同一个 Gradle 项目启用 java 插件和 android,否则你最终会得到以下结果Error: The 'java' plugin has been applied, but it is not compatible with the Android plugins
  • library1如果您希望 JVM 目标识别您的 Java 源文件,请在项目中启用 java 插件。
  • Java 源文件需要放置在源根目录java的同级目录中kotlin

java源代码根源

更多信息:java-support-in-jvm-targets的 Kotlin 文档

我还创建了一个拉取请求来解决您的问题。

这种方法的缺点是您将无法为 生成 android 存档.aarlibrary1但我想在您的 android 项目中使用 java 存档.jar应该不是问题。

库1/build.gradle:

apply plugin: "kotlin-multiplatform"

kotlin {
    jvm {
        withJava()
    }

    sourceSets {
        jvmMain {
            dependencies {
                api kotlin("stdlib-common")
                api kotlin("stdlib-jdk8")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

库2/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"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)