I just read the new blog post of #eric lafortune about Jack and Jill's new compiler on Android.
http://www.saikoa.com/blog/the_upcoming_jack_and_jill_compilers_in_android
And as I am working intensively on a bunch of new technologies built on byte code weaving for Android, I am wondering if anyone has any idea if byte code weaving would still work with this new tool chain.
From the article you mentioned:
Since the toolchain still supports both java source code and java
bytecode, existing libraries can be used without problems. Even tools
that generate or process bytecode during the build process, such as
Dagger, should be fine, with the proper integration.
Bytecode weaving is just bytecode generation/processing, so I think the answer to your question is "yes".
I'm wondering this myself, but it seems that Kotlin will be a second-class citizen with the new jack and jill compiler unless JetBrains makes an explicit statement that it won't: Android N Java 8 features (Jack compiler) and Kotlin interop
EDIT: no longer true because Kotlin is a first class citizen and the Jack & Jill project are dead.
Related
I'm a kotlin and Java developer, and recently I started analyzing the bytecode generated by kotlin. And I found out a lot of wrapper code and other stuff that the compiler generates in order to translate what I have coded in Kotlin to Java.
So, my question is:
Imagine that I have an app that its code is 100% written in kotlin. Dependencies and the main app. All Kotlin.
Does this mean that a different compiler will be used in order to avoid Java compatible bytecode?
Or is there any optimization done by the compiler in this kind of scenarios?
Many Thanks.
I know about Kotlin Native but I think it will only be applied to Android in the future.
The only way you're going to avoid Java bytecode with Kotlin is to use Kotlin Native, and you won't be able to use the Android SDK in that case.
Kotlin JVM, as the name implies, compiles to JVM bytecode; it's one of the main draws of using it. If it compiled to something different, it would be Kotlin Native.
To answer your bullets:
No, the same compiler is used whether or not you have Java source files.
Probably not. Kotlin JVM is made to be almost completely interoperable with Java, and that's the same whether or not your project includes Java code.
Think about if you were creating an Android library in Kotlin. Would you really want it to automatically compile to something other than Java bytecode in that case? It wouldn't be able to be used in Java projects, defeating one of the main reasons Kotlin is so good as a Java alternative.
Also remember, you're using the Android SDK. Even if you have no dependencies in your build.gradle, you still reference the core SDK itself, which is Java. The SDK isn't included in your APK, but it's still used during compilation.
If you want something that avoids Java bytecode, use something like Flutter. It has its own SDK, and can bridge back to Java components. Of course, you can't completely avoid the JVM, because you still need some way for Android to install and open the app.
I am wondering if the ButterKnife framework which has Annotation Processors could work with scala sbt?
Scala doesn't seem to support the Java annotation processing tool As shown is this answer
During my quest to solve this problem, I added some research links to my original question post. The AndroidAnnotations annotation processor generates source code (Java files). Annotation processors, in general, seem to operate at the source code level (and not class files). I am expecting AndroidAnnotations to generate Java code from Scala source files. Scala doesn't seem to support the Java annotation processing tool. So my answer to this question would be: it is not possible to use AndroidAnnotations with Scala source code. However, AndroidAnnotations may still be used in the Java source code in a Scala mixed-source project.
this is an old answer but I doubt that any thing has changed then.
but in scala, you can use an even better method to bind your layout using TYPED RESOURCES (TR)
I have a game that I am working on that uses the LibGDX game framework. Currently the platforms I am targeting are Desktop (PC, Mac, Linux) via a platform independent jar and Android.
The project is hosted at https://github.com/NoxHarmonium/project-whiplash Feel free to take a look if you need to.
The bulk of the code is in a module called core and is written entirely in Kotlin. This module is linked into both the Desktop and Android projects.
This works fine for Android versions 7.1+ and for desktop. For all other versions of Android I get a pile of java.lang.NoClassDefFoundError exceptions on anonymous functions such as this:
val objectObservable = this.observableCache.computeIfAbsent(assetRef, fun(assetRef: AssetRef): Observable<T> {
return Async.start(fun(): T {
...
}).observeOn(this.eventLoopScheduler)
})
Exception Sample:
java.lang.NoClassDefFoundError: com.projectwhiplash.utils.assets.LibGdxDataManager$objectMapFromYaml$objectMapObservable$1
It seems to be caused by an incompatibility with the JVM that Kotlin targets by default (1.8) and the JVM level that older versions of Android support (1.6). I could be wrong but this explains why the latest version of Android works as it supports a later version of the JVM.
The solution should be as simple as forcing Kotlin to emit JVM byte code as version 1.6 but I can't seem to work it out. If you compile Kotlin directly into an Android, this seems to be handled by using the kotlin-android Gradle plugin. Unfortunately I can't use this plugin for the core module because it should not have any Android dependencies.
I tried to override the JVM version using the build settings mentioned at https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options like this:
compileKotlin {
kotlinOptions {
jvmTarget = "1.6"
}
}
However, it did not seem to work no matter which Gradle file I placed it in. In fact I get a "Cannot resolve symbol 'kotlinOptions'" error shown by Intellij when I try it. It is possible that the Kotlin team have changed something and the documentation has not been updated.
I can override the Kotlin settings manually in the Intellij module settings but it gets overridden every time I sync the gradle project and is not a good long term solution. The project is designed to be IDE independent.
Does anyone know how I could set up the core module for max compatibility with older versions of Android?
I currently have the minimum API level set to 9 as this is the current LibGDX default but I'm willing to set this higher if it would be too difficult to target such a low API level.
Edit 1:
I just extracted the jar file produced by the core module and examined the class files using the javap tool.
I ran the following command on a random class file
java -verbose foo.class
and it output text with the following text
...
minor version: 0
major version: 50
...
using this question List of Java class file format major version numbers? I determined that the class file is actually targeting JVM 1.6.
Therefore my original theory is wrong and there is another reason why older Android versions cannot load classes generated by Kotlin lambdas.
It looks like you are using functionality that only exists within the JDK 8 library. Specifically the computeIfAbsent() method on the Map class.
Because of this, even though your code has been compiled down to JVM 1.6 compatibility, the underlying implementation on Android devices is missing that functionality and thus the reason for the NoClassDefFoundError exception you were seeing.
Updated: You can see in the javadoc located at https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function- that the computeIfAbsent() has only been around since JDK 8
Now with announcement of Jack Google clarified the foreseeable future of Java in relation to Android. But what are the implications to Scala and other JVM-based languages developers. In particular:
Scala does it's magic due to own compiler that produces Java bytecode. But Jack toolchain doesn't deal with bytecode. Will generated bytecode gain any optimization benefits of Jack processing?
Starting from Scala 12 only Java 8+ is supported. That is the generated bytecode is Java 8+ too. Can Jack utilize Java 8 bytecode (without or with limitations)?
Can newly supported Java 8 features be used for developing for older Android versions (minSdkVersion < 'N') or i should maintain separate branch for each Java version? (it is not clear from documentation).
All these questions boil down to one: Can Scala be used for Android development in future without sacrificing the benefits of new Scala features and new Android tool chain?
Related reading:
Java 8 Language Features
Jack (Java Android Compiler Kit)
New Android Tool Chain - Jack and Jill
The Jack and Jill build system (slides)
Hello World, meet our new experimental toolchain
Scala 2.12 roadmap
please share related links in comments or answers
Related questions:
Android N Java 8 features (Jack compiler) and Kotlin interop
Related:
scala-on-android group discussion
Please vote for Jack tool feature request:
Support for Java 8 bytecode (libraries) by Jill
Support Java 8 language features
EDIT:
I'm trying to reason about (NOT to answer) my question hoping that experts will correct me if i'm wrong.
Below is a hypothetical flow of Jack build with some extra blocks that was added basing on my logic and what i have learned from available docs.
Base assumption is that Dalvik supports up to Java 7 bytecode instructions. If that is correct Java 8 instructions can not be directly passed to Dalvik, they should be somehow transformed to Java 7. (May be something similar to that Scala compiler always does).
Than the question is where is that transformation happens? Seems Jill can't process Java 8 bytecode as for now, so that possibly happens in block (3) of hypothetical flow. If that is correct than only Java source project files are subject to transformation and the answer to 2-nd question is - No. Java 8 classes from libraries can not be utilized until Jill will be able to do it (if it's possible at all). That is we can not use Scala 12+.
If all code optimization is performed in block (6) than the answer to 1-st question is - Yes. Scala code being converted to library .jar can benefit from Jack optimizations. But preliminarily it should be transformed to .jayce (AST-like representation) that will increase build time.
And finally Jack produces .dex Dalvik bytecode to maintain compatibility with older Dalvik runtimes (ART consumes Dalvik bytecode too). So the answer to 3-d question is: Yes, Java 8 features can be used. But only in project Java sources. App is still compatible with any runtime. But Java 8 advantages are dropped due to converting to Java 7 (Dalvik bytecode).
It’s important to understand that there is 2 tool introduced:
Jack: A new compiler to replace the complicated javac + proguard + dx
Jill: A library linker that will be able to link currently compiled libraries (.class) and more.
See http://tools.android.com/tech-docs/jackandjill
So it sounds like there is 2 separate problem here:
Scala compatibility:
Scala will not be supported by Jack, as Jack compiles Java source code.
However Scala 2.11 compiles to Java 1.6 bytecode and therefore Jill will be able to pick that code and convert to jack files to feed the Jack compiler.
See Android N Java 8 features (Jack compiler) and Kotlin interop (Kotlin as the same issue as Scala as it’s a JVM language)
Java 8, and therefore Scala 2.12+, compatibility:
This part is under development, if Jack/Jill supports Java 8, then it will also support Scala 2.12+ (through Jill). If not, Java 8 developers are in the same boat as Scala 2.12 developers.
In the case Jack supports Java 8 but not Jill, then Java 8 libraries developers will be in the same boat as Scala 2.12 developers.
See https://www.guardsquare.com/blog/DroidconLondon2015
Joan is correct, but I think Jill will have support for Java 8 at some point to, otherwise it will be impossible to use Java 8 in android libraries that will be consumed by android apps, as they package their code in a jar files inside of aar and I don't see this format change happening anywhere soon. Anyway we can only guess, as Google is currently a blackbox in respect to those kinds of changes.
Revising since new info is out in 2017: jack toolchain is now deprecated and old dex/javac stack will receive java8 support so nothing will change for scala now.
Google just announced that the Jack toolchain will deprecate the Jack toolchain and Android adds "support for Java 8 language features directly into the current javac and dx set of tools"
Source: https://android-developers.googleblog.com/2017/03/future-of-java-8-language-feature.html
We know how much our Android developer community cares about good support for Java 8 language features, and we're changing the way we support them.
and:
We've decided to add support for Java 8 language features directly into the current javac and dx set of tools, and deprecate the Jack toolchain.
Is it possible to use AndroidAnnotations with the Scala programming language and the Gradle build system? When I try to integrate AndroidAnnotations into my existing Android/Scala/Gradle project, then compilation fails because the generated underscore classes (e.g. MyActivity_) cannot be found.
Here are some useful starting points and references:
http://www.scala-lang.org/node/4773 (2010-01-06)
http://www.scala-lang.org/sid/5 (2010-01-27)
http://code.google.com/p/androidannotations/wiki/Configuring (2011-07-28)
http://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/ch08.html#d0e2816 (2010?)
Java 6 annotation processing configuration with Ant (2010-09-05)
http://download.oracle.com/javase/6/docs/technotes/tools/solaris/javac.html#processing
http://ant.apache.org/manual/Tasks/apt.html
Generating JPA2 Metamodel from a Gradle build script (2011-06-22)
http://download.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html
During my quest to solve this problem, I added some research links to my original question post. The AndroidAnnotations annotation processor generates source code (Java files). Annotation processors in general seem to operate at the source code level (and not class files). I am expecting AndroidAnnotations to generate Java code from Scala source files. Scala doesn't seem to support the Java annotation processing tool. So my answer to this question would be: it is not possible to use AndroidAnnotations with Scala source code. However, AndroidAnnotations may still be used in the Java source code in a Scala mixed-source project.
Regarding Gradle (without Scala), it seems that someone managed to use it with AndroidAnnotations, here: Adapt AndroidAnnotations Maven settings to Gradle