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

时间:2019-12-25 13:50:32

标签: kotlin kotlin-multiplatform

我正在尝试使用Kotlin Multiplatform功能(示例项目:https://github.com/dmitrykolesnikovich/accessJavaCode-issue)在Android和JVM目标之间共享Java代码

简而言之,“: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配置中,我定义了两个插件: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 个答案:

答案 0 :(得分:2)

~~~~编辑~~~~

另一个解决方法是在不失去为.aar生成Android存档library1的能力的情况下,根据原始拆分版本的预编译伪像,为该库创建新版本library1

所以您最终将获得一个多模块gradle项目,如下所示:

  • 已启用Java插件的library1-jvm
  • 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源文件放置在java源根目录的兄弟目录kotlin中。

java source roots

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

我还创建了pull request来解决您的问题。

该方法的缺点是您将无法为.aar生成一个Android存档library1,但是我想在您的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"
        }
    }
}