Comparta un module de Kotlin con un proyecto de Android y de escritorio

Tengo un juego en el que estoy trabajando que usa el framework de juegos LibGDX. Actualmente, las plataforms a las que me dirijo son Desktop (PC, Mac, Linux) a través de un tarro independiente de plataforma y Android.

El proyecto está alojado en https://github.com/NoxHarmonium/project-whiplash. Siéntase libre de echarle un vistazo si lo necesita.

La mayor parte del código está en un module llamado core y está escrito completamente en Kotlin. Este module está vinculado a los proyectos de escritorio y Android.

Esto funciona bien para las versiones de Android 7.1+ y para escritorio. Para todas las otras versiones de Android obtengo un montón de excepciones java.lang.NoClassDefFoundError en funciones anónimas como esta:

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

Muestra de exception:

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

Parece ser causado por una incompatibilidad con la JVM que Kotlin busca de forma pnetworkingeterminada (1.8) y el nivel de JVM que soportan las versiones anteriores de Android (1.6). Podría estar equivocado, pero esto explica por qué funciona la última versión de Android, ya que admite una versión posterior de la JVM.

La solución debería ser tan simple como forzar a Kotlin a emitir código de bytes JVM como la versión 1.6 pero parece que no puedo resolverlo. Si comstack Kotlin directamente en un Android, esto parece que se maneja mediante el uso del kotlin-android . Lamentablemente, no puedo usar este complemento para el module principal porque no debería tener ninguna dependencia de Android.

Traté de anular la versión de JVM usando la configuration de compilation que se menciona en https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options como esta:

compileKotlin { kotlinOptions { jvmTarget = "1.6" } }

Sin embargo, no parecía funcionar, independientemente del file Gradle en el que lo colocara. De hecho, aparece el error "No se puede resolver el símbolo 'kotlinOptions'" mostrado por Intellij cuando lo bash. Es posible que el equipo de Kotlin haya cambiado algo y la documentation no se haya actualizado.

Puedo anular la configuration de Kotlin manualmente en la configuration del module de Intellij, pero se anula cada vez que sincronizo el proyecto de gradle y no es una buena solución a largo ploop. El proyecto está diseñado para ser IDE independiente.

¿Alguien sabe cómo podría configurar el module central para una compatibilidad máxima con las versiones anteriores de Android?

Actualmente tengo el nivel mínimo de API establecido en 9, ya que este es el valor pnetworkingeterminado actual de LibGDX, pero estoy dispuesto a establecerlo más alto si sería demasiado difícil orientarlo a un nivel de API tan bajo.

Editar 1:

Acabo de extraer el file jar producido por el module central y examiné los files de class con la herramienta javap .

Ejecuté el siguiente command en un file de class aleatorio

java -verbose foo.class

y emite text con el siguiente text

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

usando esta pregunta ¿ Lista de numbers de la versión principal del formatting de file de la class de Java? Determiné que el file de class está realmente dirigido a JVM 1.6.

Por lo tanto, mi teoría original es incorrecta y existe otra razón por la cual las versiones anteriores de Android no pueden cargar las classs generadas por Kotlin lambdas.

Parece que está utilizando una funcionalidad que solo existe en la biblioteca JDK 8. Específicamente, el método computeIfAbsent () en la class Map.

Debido a esto, aunque su código se haya comstackdo hasta la compatibilidad con JVM 1.6, la implementación subyacente en los dispositivos Android no count con esa funcionalidad y, por lo tanto, con el motivo de la exception NoClassDefFoundError que estaba viendo.

Actualizado: Puede ver en el javadoc ubicado en https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function- que el computeIfAbsent () solo ha existido desde JDK 8

  • java.lang.NoClassDefFoundError: kotlin / jvm / internal / Intrinsics en libgdx
  • libGDX no puede realizar acción
  • Gradle tomando time al frente aparentemente sin hacer nada
  • Extraña java.lang.ClassCastException al usar la llamada
  • ¿Cuál es la diferencia entre get y call en Kotlin?
  • libGDX no puede dibujar spline
  • Error ': android: transformKotlinClassesWithJillForDebug'. Al comstackr una aplicación para Android escrita en Kotlin + LibGDX
  • Android: FirstPersonCameraController: Multitouch
  • ¿Cómo puedo comstackr el código de Kotlin a JavaScript para usar en mi aplicación web LibGDX?