Поделитесь модулем Kotlin с проектом Android и Desktop

У меня есть игра, над которой я работаю, которая использует платформу игр LibGDX. В настоящее время платформами, на которых я нацелен, являются Desktop (ПК, Mac, Linux) через платформу, независимую банку и Android.

Проект размещен на странице https://github.com/NoxHarmonium/project-whiplash. Не стесняйтесь смотреть, если вам нужно.

Основная часть кода находится в модуле, называемом core и полностью написана в Kotlin. Этот модуль связан как с проектами Desktop, так и с 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) и уровень JVM на более старые версии поддержки Android (1.6). Я мог ошибаться, но это объясняет, почему последняя версия Android работает, поскольку она поддерживает более позднюю версию JVM.

Решение должно быть таким же простым, как заставить Kotlin испускать байт-код JVM в версии 1.6, но я не могу его обработать. Если вы компилируете Kotlin прямо в Android, это, похоже, обрабатывается с помощью kotlin-android Gradle. К сожалению, я не могу использовать этот плагин для основного модуля, потому что он не должен иметь никаких зависимостей от Android.

Я попытался переопределить версию JVM, используя настройки сборки, указанные в https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options следующим образом:

compileKotlin { kotlinOptions { jvmTarget = "1.6" } }

Тем не менее, он, похоже, не работал независимо от того, какой файл Gradle я разместил. На самом деле я получаю сообщение «Can not resolve symbol» kotlinOptions », показанное Intellij при попытке. Возможно, команда Kotlin что-то изменила, и документация не была обновлена.

Я могу переопределить настройки Kotlin вручную в настройках модуля Intellij, но он переустанавливается каждый раз, когда я синхронизирую проект градиента и не являюсь хорошим долгосрочным решением. Проект рассчитан на независимость от IDE.

Кто-нибудь знает, как я могу настроить основной модуль для максимальной совместимости со старыми версиями Android?

В настоящее время у меня минимальный уровень API, равный 9, поскольку это текущий по умолчанию вариант LibGDX, но я готов установить его выше, если будет слишком сложно настроить такой низкий уровень API.

Изменить 1:

Я просто извлек файл jar, созданный основным модулем, и рассмотрел файлы классов с javap инструмента javap .

Я выполнил следующую команду в файле случайных классов

java -verbose foo.class

и выводит текст со следующим текстом

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

используя этот вопрос Список основных номеров версии файла класса Java? Я решил, что файл класса на самом деле нацелен на JVM 1.6.

Поэтому моя оригинальная теория ошибочна, и есть еще одна причина, по которой старые версии Android не могут загружать классы, созданные Kotlin lambdas.

Похоже, вы используете функциональность, которая существует только в библиотеке JDK 8. В частности, метод computeIfAbsent () в классе Map.

Из-за этого, несмотря на то, что ваш код был скомпилирован до совместимости с JVM 1.6, в базовой реализации на устройствах Android отсутствует эта функциональность и, следовательно, причина исключения NoClassDefFoundError, которое вы видели.

Обновлено: вы можете видеть в javadoc, расположенном по адресу https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-, что computeIfAbsent () существует только с JDK 8

Intereting Posts