与Android和桌面项目共享一个Kotlin模块
我有一个使用LibGDX游戏框架的游戏。 目前我所针对的平台是Desktop(PC,Mac,Linux),通过独立于平台的jar和Android。
该项目托管在https://github.com/NoxHarmonium/project-whiplash如果您需要,请随时查看。
大部分代码位于一个名为core
的模块中,完全由Kotlin编写。 该模块已链接到桌面和Android项目中。
这适用于Android版本7.1+和桌面。 对于所有其他版本的Android,我在匿名函数上得到一堆java.lang.NoClassDefFoundError
exception:
val objectObservable = this.observableCache.computeIfAbsent(assetRef, fun(assetRef: AssetRef): Observable { return Async.start(fun(): T { ... }).observeOn(this.eventLoopScheduler) })
exception示例:
java.lang.NoClassDefFoundError: com.projectwhiplash.utils.assets.LibGdxDataManager$objectMapFromYaml$objectMapObservable$1
这似乎是由于Kotlin默认的目标(1.8)与旧版Android支持的JVM级别(1.6)不兼容。 我可能是错的,但这解释了为什么最新版本的Android工作,因为它支持更高版本的JVM。
解决方案应该像强制Kotlin发射1.6版本的JVM字节码一样简单,但我似乎无法解决。 如果你直接将Kotlin编译成Android,这似乎是通过使用kotlin-android
Gradle插件来处理的。 不幸的是,我不能使用这个插件的核心模块,因为它不应该有任何Android的依赖。
我尝试使用https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options中提到的构建设置来覆盖JVM版本,如下所示:
compileKotlin { kotlinOptions { jvmTarget = "1.6" } }
然而,无论我把哪个Gradle文件放进去,它似乎都不起作用。事实上,当我尝试使用Intellij时,显示出“Can not resolve symbol’kotlinOptions’”错误。 Kotlin团队可能已经改变了一些东西,文档还没有更新。
我可以在Intellij模块设置中手动覆盖Kotlin设置,但每次同步gradle项目时都会覆盖Kotlin设置,这不是一个好的长期解决方案。 该项目旨在独立于IDE。
有谁知道如何设置核心模块,以最大限度地兼容老版本的Android?
我目前有最低的API级别设置为9,因为这是目前的LibGDX默认,但我愿意设置这个更高,如果太难以目标如此低的API级别。
编辑1:
我只是提取由核心模块生成的jar文件,并使用javap
工具检查类文件。
我在随机类文件上运行以下命令
java -verbose foo.class
并用下面的文本输出文本
... minor version: 0 major version: 50 ...
使用这个问题Java类文件格式主要版本号列表? 我确定类文件实际上是针对JVM 1.6的。
因此,我原来的理论是错误的,还有一个原因,为什么旧的Android版本不能加载由Kotlin lambda生成的类。
看起来您正在使用只存在于JDK 8库中的function。 特别是Map类中的computeIfAbsent()方法。
因此,即使您的代码已经被编译为JVM 1.6兼容性,但Android设备上的底层实现缺少该function,因此您看到了NoClassDefFoundErrorexception的原因。
更新:您可以在位于https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function的javadoc中看到computeIfAbsent()从JDK 8开始就已经存在了
- 如何覆盖gradle kotlin-dsl中的任务
- 如何使用Kotlin DSL配置AppEngine Gradle插件
- Beta由Crashlytics – 包似乎已损坏
- 找不到com.intellij.lang.properties.charset.Native2AsciiCharsetProvider
- 测试包不读取主包中定义的Kotlin类
- 如何为Kotlin和Gradle设置“sourceCompatibility”?
- Google Guava Invokedynamic要求–min-sdk-version> = 26
- Gradle – 以非零退出值完成1
- Gradle:从Groovy切换到Kotlin有什么好处?