2017-05-21 42 views
1

我有一個使用LibGDX遊戲框架的遊戲。目前我的平臺是通過獨立於平臺的jar和Android的桌面(PC,Mac,Linux)。與Android和桌面項目共享一個Kotlin模塊

該項目託管在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

這似乎與JVM的不兼容引起的Kotlin的默認目標是1.8(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" } }

但是,它似乎並沒有工作,無論哪個搖籃文件,我把它放在事實上。當我嘗試使用Intellij時,顯示「Can not resolve symbol'kotlinOptions'」錯誤。 Kotlin團隊可能已經改變了一些東西,文檔還沒有更新。

我可以在Intellij模塊設置中手動覆蓋Kotlin設置,但每次我同步gradle項目時都會被覆蓋,並且不是一個好的長期解決方案。該項目旨在獨立於IDE。

有誰知道我可以如何設置核心模塊以最大程度地兼容舊版Android?

我目前的最低API級別設置爲9,因爲這是目前的LibGDX默認設置,但是我願意將此設置得更高,如果難以定位這樣的低API級別。

編輯1:

我只提取由核心模塊所產生的jar文件,並使用javap工具檢查的類文件。

我跑了一個隨機類文件

java -verbose foo.class

,並用這個問題List of Java class file format major version numbers?以下文本

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

輸出文本我決定下面的命令該類文件實際上是針對JVM 1.6的。

因此,我最初的理論是錯誤的,還有另一個原因,爲什麼較舊的Android版本無法加載由Kotlin lambda生成的類。

回答

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

+0

您好,感謝您的想法看。如果您查看我的編輯原始答案,您會發現我發現Kotlin實際上正在生成針對JVM 1.6的二進制文件。在1.1.2的更改日誌中,他們說:「對於編譯器生成的代碼,Java 1.6的兼容性仍然是默認的,我們沒有計劃放棄對生成Java 1.6兼容字節碼的支持。」 [來源](https://blog.jetbrains.com/kotlin/2017/04/kotlin-1-1-2-is-out/)所以它一定是另一個問題! –

+0

好的皮卡!我以爲我檢查過,但我一定錯過了。我會看看我是否可以用polyfill或更換或其他東西來修復它。 –

+0

刪除對僅支持JVM 1.7和1.8的方法的引用。出於某種原因,Intellij只警告某些地方不支持的方法,而不是其他方面。 爲了澄清,這不是Kotlin發出的字節碼版本,而是我使用最新版本的JDK(1.8)來構建我的代碼的事實。這意味着它可以編譯使用舊版Android設備上提供的早期版本的JVM中不可用的方法的類。 –