2017-05-21 5 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)、Androidの旧バージョンではサポートされているJVMレベル(1.6)です。私は間違っている可能性がありますが、なぜこれがJVMの新しいバージョンをサポートしているので、Androidの最新バージョンが動作するのかを説明しています。

解決策は、Kotlinにバージョン1.6のJVMバイトコードを強制的に送信させるように単純にする必要がありますが、それを解決できないようです。 KotlinをAndroidに直接コンパイルすると、これはkotlin-android Gradleプラグインを使用して処理されているようです。残念ながら、このプラグインをコアモジュールに使用することはできません。なぜなら、Androidの依存関係がないからです。

私はこのようなhttps://kotlinlang.org/docs/reference/using-gradle.html#compiler-optionsに言及したビルド設定使用してJVMのバージョンを上書きしようとした:しかし、私がそれを置いGradleのファイルに関係なく動作していないようでした

compileKotlin { kotlinOptions { jvmTarget = "1.6" } }

を事実。 Intellijが試してみると、「kotlinOptionsのシンボルを解決できません」というエラーが表示されます。 Kotlinチームが何かを変更してドキュメントが更新されていない可能性があります。

私はのIntelliJモジュールの設定で手動Kotlinの設定を上書きすることができますが、それは私がGradleのプロジェクトを同期して良好な長期解決策ではありませんたびに上書きされます。このプロジェクトはIDEに依存しないように設計されています。

誰も私は、Androidの旧バージョンとの最大の互換性のためのコアモジュールを設定することができる方法を知っていますか?

これは、現在のLibGDXのデフォルトであると私は現在、9に設定された最小APIレベルを持っていますが、このような低い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例外が発生します。

更新:あなたはcomputeIfAbsentは()のみJDK 8

+0

こんにちは、アイデアに感謝以来の周りされているhttps://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-に位置javadocの見ることができます。私の編集を元の回答にチェックすると、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

良いピックアップ!私はそれを確認したと思ったが、私はそれを逃したに違いない。ポリフィルや交換品などで修正できるかどうかがわかります。 –

+0

JVM 1.7および1.8でのみサポートされているメソッドへの参照が削除されました。何らかの理由で、Intellijは、サポートされていない方法については、一部の場所でのみ警告し、他の箇所では警告しませんでした。 明確にするために、Kotlinが発行したバイトコードバージョンではありませんでしたが、私はJDK(1.8)の最新バージョンを使用してコードを作成していました。これは古いAndroid搭載デバイスで提供されていたJVMの以前のバージョンでは利用できなかったメソッドを使ったクラスをコンパイルできることを意味していました。 –

関連する問題