与Android和桌面项目共享Kotlin模块

时间:2017-05-21 11:10:08

标签: android intellij-idea gradle libgdx kotlin

我正在开发一款使用LibGDX游戏框架的游戏。目前我所定位的平台是桌面(PC,Mac,Linux),通过独立于平台的jar和Android。

项目在https://github.com/NoxHarmonium/project-whiplash举办。如果需要,请随时查看。

大部分代码都在一个名为core的模块中,完全用Kotlin编写。此模块链接到桌面和Android项目。

这适用于Android版本7.1+和桌面版。对于所有其他版本的Android,我在匿名函数上获得了大量java.lang.NoClassDefFoundError例外,例如:

val objectObservable = this.observableCache.computeIfAbsent(assetRef, fun(assetRef: AssetRef): Observable<T> {
  return Async.start(fun(): T {
    ...
  }).observeOn(this.eventLoopScheduler)
})

例外示例:

java.lang.NoClassDefFoundError: com.projectwhiplash.utils.assets.LibGdxDataManager$objectMapFromYaml$objectMapObservable$1

这似乎是由于默认情况下Kotlin所针对的JVM不兼容(1.8)以及旧版Android支持的JVM级别(1.6)。我可能错了,但这解释了为什么最新版本的Android工作,因为它支持更高版本的JVM。

解决方案应该像强制Kotlin发布JVM字节代码一样简单,因为版本1.6但我似乎无法解决它。如果您将Kotlin直接编译到Android中,这似乎可以通过使用kotlin-android Gradle插件来处理。不幸的是,我不能将此插件用于核心模块,因为它不应该有任何Android依赖项。

我尝试使用https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options中提到的构建设置覆盖JVM版本,如下所示:

compileKotlin { kotlinOptions { jvmTarget = "1.6" } }

然而,无论我把它放在哪个Gradle文件中它似乎都不起作用。实际上我得到了一个&#34;无法解析符号&#39; kotlinOptions&#39;&#34;我尝试时Intellij显示错误。 Kotlin团队可能已经改变了一些内容并且文档尚未更新。

我可以在Intellij模块设置中手动覆盖Kotlin设置,但每次同步gradle项目时它都会被覆盖,这不是一个好的长期解决方案。该项目旨在独立于IDE。

有谁知道如何设置核心模块以最大限度地兼容旧版Android?

我目前将最低API级别设置为9,因为这是当前的LibGDX默认值,但如果要将这么低的API级别定位太难,我愿意将其设置得更高。

编辑1:

我刚刚提取了核心模块生成的jar文件,并使用javap工具检查了类文件。

我在随机类文件

上运行以下命令

java -verbose foo.class

并输出带有以下文字的文字

... minor version: 0 major version: 50 ...

使用此问题List of Java class file format major version numbers?我确定类文件实际上是针对JVM 1.6。

因此我的原始理论是错误的,并且还有另一个原因导致旧的Android版本无法加载Kotlin lambdas生成的类。

1 个答案:

答案 0 :(得分:1)

看起来您正在使用仅存在于JDK 8库中的功能。特别是Map类上的computeIfAbsent()方法。

正因为如此,即使您的代码已经编译为JVM 1.6兼容性,Android设备上的底层实现也缺少该功能,因此您看到了NoClassDefFoundError异常的原因。

更新:您可以在位于https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-的javadoc中看到computeIfAbsent()仅在JDK 8之后出现