How to use a java 8 library with android? - java

I'm trying to use a library that uses java 8 in my android project. I cannot find a way to make this work. I've tried to use retro lambda but it has not helped. I keep getting the error: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version(0034.0000)
I've researched this and learned it's because there is java 8 syntax in the included library. I've been compiling with java 8 sdk and am using android studio 08.2. Help!
The library is:https://github.com/robrua/Orianna

Solution 1
Wait for android to support Java8.
Solution 2
Use an earlier version of the library that isn't Java8 and/or ask the developer of the library to provide one/ the last Java6 (or Java7 for kitcat upwards) library.
Solution 3
This is some kind of hack and I haven't tested or even used it!
Use retrolambda to backport the Java8-bytecode to Java6. On the homepage of retrolambda you find some documentation about it.
Downloads of retrolambda are here.
Probably you will have to unzip the library jar to a folder and the run a command like the following:
java -Dretrolambda.inputDir=<extracted_classfiles>
-Dretrolambda.classpath=<extracted_classfiles>
-Dretrolambda.bytecodeVersion=50
-javaagent:retrolambda.jar
-jar retrolambda.jar
Maybe you have to extend the classpath depending on the dependencies of the library.
Then you have to copy the resulting jar-file into your android-project's lib folder.
It is also possible to program Java8 for android.
If retrolambda doesn't work maybe you can find another tool to backport Java8-bytecode to Java6-bytecode.

Related

Is there a possibility to run a jar file within an android application with another jdk?

Im new to app development and was wondering if it would be possible to include another jdk. For example java 17 and run a jar that needs to be run in this exact version? I think termux has an api that you may use for these purposes but is there another possibility? These jars are only console based and without any gui.
I first tried to use the jar as a android library inside the app, which did not work since it was compiled in java version 17. I tried decompiling the jar and recompiling it with the version I was using. The problem is that all the libraries used are on other versions than I need them to be and so I could not recompile it. I also thought about writing the application in c# but I am not used to it at all, which would throw many new problems that I would be willing to take if it would be a possibility to work out my project.
Q: Is loading the code into your Android application an option?
A: No.
Android loads code from ".dex" files not ".class" files.
The ".class" files would need to be translated using dx.
The Android dx command doesn't understand Java 17 ".class" file format.
Also the code in the JAR is likely to depend on classes in the Java SE class library that the Android doesn't provide.
Q: What about running it in a separate Android VM?
A: No.
An Android VM requires ".dex" files; see above.
Also, the Java SE class library issue; see above.
Q: What about launching an OpenJDK or Oracle Java 17 JVM on the Android device to run the JAR?
A: In theory Yes, but in practice No. As far as I am aware, there is no port of OpenJDK Java SE to the Android OS platform.
Q: What about using Termux?
A: OK ... that might work. See Is it possible to install the JDK on an android device?.
I have no experience with this, and don't know what problems you may run into doing this. But I suspect that you wouldn't be able to distribute something that relies on Termux via the Google Playstore.
Another option is to download the source code1 for the application and try to build it in your Android dev environment
If the code uses Java classes / packages / libraries that are not available for Android, recode the relevant parts of the application to use Android equivalents instead.
Ditto if the code uses Java language features that are not yet supported in Android Java.
It probably won't be easy. It may turn out to be impractical.
1 - You said in a comment that the code your are trying to use is "open source". So the "download source and build it" option is available to you. I'm puzzled why you tried to decompile and recompile it instead ...

Android Studio - How does a library project used in an app follow with the app-release.apk

I'm using a library (https://github.com/PhilJay/MPAndroidChart) for plotting data in an android app. When app-release.apk is created by the program it is ready to be installed on the tablet I use for testing.
What is puzzling to me is how the parts of the library, which i use, follow with the release. In other scenarios, for example in Visual Studio and c# - program being installed on Window machine, libraries require dll files to be installed and registered on each targeted machine. In my scenario the library is written specifically for Android, but if I somehow managed to include a c++ or a c# library in my Android app using tools like libstdc++ or MONO, would it work the same way when it comes down to app-realease.apk?
Are all classes in a library included in the app-release.apk or just the parts that I use?
Thanks in advance and please let me know if the question is unclear before downvoting it!
Normally, when you build your APK, all the libs you have imported (jars) are included and transformed to dex files, as the rest of your code. So, yes all the classes are included, even if you don't use them.
You can use Proguard to remove them from the APK. Look at this post :
Use Proguard for stripping unused Support lib classes

Java 6 service using/calling java8 library

Our service still uses Java 6 for compile and run. We need to use a library that is compiled with Java 8. Upon including the dependency in gradle we as expected see errors such as "class file has wrong version"
For android development gradle has something like gradle-retrolambda. Is there any generic gradle client that helps convert this library's bytecode compatible to java 6? or is there any other option other than our service upgrading to java8?
Thanks!

Converting Java to .NET library using IKVMC - Warning IKVMC0108: not a class file

There is Java tool (it is called Mallet)
http://mallet.cs.umass.edu/download.php
which I want to use in my .NET project.
To convert this tool to .NET library at first I've tried to build it in single .jar file using Apache Ant. I've done everything corresponding to instructions at link above.
Download Developer Release from Mercurial repository.
Download Apache Ant, install JDK, set JAVA_HOME var to use Apache Ant.
Using Ant I've built single mallet.jar file.
And then I would to convert mallet.jar to .NET library using IKVMC.
When converting, I've got a lot of warnings such as:
Warning IKVMC0108: not a class file "cc/mallet/util/tests/TestPriorityQueue$1.cl
ass", including it as resource
(class format error "51.0")
Despite of these warnings, mallet.dll was created. But when I try to reference to it from my .NET project, it looks "empty". It has not any classes or namespaces. I don't forget to reference to IKVM.OpenJDL.Core.
And this is unusual that I can't find any same problems in Google.
I think that problem is in warnings. And I have never worked with Ant and I don't understand all process exactly.
The class format version 51 was introduced with Java 7.
IKVM most likely doesn't support that version yet and the file name you quote (cc/mallet/util/tests/TestPriorityQueue$1.class) points at an anonymous inner class of TestPriorityQueue that certainly is needed for the library to work correctly.
My suggestion: compile Mallet using an older JDK or at least using the -source and -target switches set to 6 (to ensure that it's compile for Java 6).
FYI v8.1 (currently in RC) of IKVM supports Java 8:
http://weblog.ikvm.net/2015/08/26/IKVMNET81ReleaseCandidate0.aspx
http://sourceforge.net/p/ikvm/mailman/message/34502991/

Java 7 language features with Android

Just wondering if anyone has tried using new Java 7 language features with Android?
I know that Android reads the bytecode that Java spits out and turns it to dex. So I guess my question is can it understand the bytecode of Java 7?
If you are using Android Studio, the Java 7 language should be enabled automatically without any patches. Try-with-resource requires API Level 19+, and NIO 2.0 stuff are missing.
If you can't use Java 7 features, see #Nuno's answer on how to edit your build.gradle.
The following is for historical interest only.
A small part of Java 7 can certainly be used with Android (note: I have only tested on 4.1).
First of all, you could not use Eclipse's ADT because it is hard-coded that only Java compiler 1.5 and 1.6 are compliant. You could recompile ADT but I find there is no simple way to do that aside from recompiling the whole Android together.
But you don't need to use Eclipse. For instance, Android Studio 0.3.2, IntelliJ IDEA CE and other javac-based IDEs supports compiling to Android and you could set the compliance even up to Java 8 with:
File → Project Structure → Modules → (pick the module at the 2nd pane) → Language level → (choose "7.0 - Diamonds, ARM, multi-catch, etc.")
This only allows Java 7 language features, and you can hardly benefit from anything since a half of improvement also comes from the library. Features you could use are those which do not depend on the library:
Diamond operator (<>)
String switch
Multiple-catch (catch (Exc1 | Exc2 e))
Underscore in number literals (1_234_567)
Binary literals (0b1110111)
And these features cannot be used yet:
The try-with-resources statement — because it requires the non-existing interface "java.lang.AutoCloseable" (this can be used publicly in 4.4+)
The #SafeVarargs annotation — because "java.lang.SafeVarargs" does not exist
... "yet" :) It turns out that, although Android's library is targeting for 1.6, the Android source does contain interfaces like AutoCloseable and traditional interfaces like Closeable does inherit from AutoCloseable (SafeVarargs is really missing, though). We could confirm its existence via reflection. They are hidden simply because the Javadoc has the #hide tag, which caused the "android.jar" not to include them.
There is already as existing question How do I build the Android SDK with hidden and internal APIs available? on how to get those methods back. You just need to replace the existing "android.jar" reference of the current Platform with our customized one, then many of the Java 7 APIs will become available (the procedure is similar to that in Eclipse. Check Project Structure → SDKs.)
In additional to AutoCloseable, (only) the following Java 7 library features are also revealed:
Exception chaining constructors in ConcurrentModificationException, LinkageError and AssertionError
The static .compare() methods for primitives: Boolean.compare(), Byte.compare(), Short.compare(), Character.compare(), Integer.compare(), Long.compare().
Currency: .getAvailableCurrencies(), .getDisplayName() (but without .getNumericCode())
BitSet: .previousSetBit(), .previousClearBit(), .valueOf(), .toLongArray(), .toByteArray()
Collections: .emptyEnumeration(), .emptyIterator(), .emptyListIterator()
AutoCloseable
Throwable: .addSuppressed(), .getSuppressed(), and the 4-argument constructor
Character: .compare(), .isSurrogate(), .getName(), .highSurrogate(), .lowSurrogate(), .isBmpCodePoint() (but without .isAlphabetic() and .isIdeographic())
System: .lineSeparator() (undocumented?)
java.lang.reflect.Modifier: .classModifiers(), .constructorModifiers(), .fieldModifiers(), .interfaceModifiers(), .methodModifiers()
NetworkInterface: .getIndex(), .getByIndex()
InetSocketAddress: .getHostString()
InetAddress: .getLoopbackAddress()
Logger: .getGlobal()
ConcurrentLinkedDeque
AbstractQueuedSynchronizer: .hasQueuedPredecessors()
DeflaterOutputStream: the 3 constructors with "syncFlush".
Deflater: .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate() with 4 arguments
That's basically all. In particular, NIO 2.0 does not exist, and Arrays.asList is still not #SafeVarargs.
EDIT: At the time this was written, the latest release was Android 9 and Eclipse Indigo. Thing have changed since then.
Practical answer
Yes, I have tried. But this is not a great test as the compatibility was limited to level 6 with no way (no simple way at least) to really use java 7:
First I installed a JDK7 on a machine that had no other JDK installed - Eclipse and Android are not installed either:
Then I installed a brand new Eclipse Indigo and checked it was actually using the JDK 7 (well, as this is the only one and as this is the one I've selected I would have been surprised)
Then I installed the latest version of the Android SDK (EDIT: Honeycomb, API13, at the time this post was written). It found my JDK 7 and installed properly. The same for ADT.
But I had a surprise when trying to compile and run a Hello Word Android app. The compatibility was set to Java 6 with no way to force it to Java 7:
I tried with a non-Android project, a regular Java one, and I had the explanation. The compatibility level seems to be limited by Eclipse (see the message at bottom of the following image):
So I had Hello World working, and also other apps, more complicated and using SQLite, Listview, Sensor and Camera, but this only proves that the compatibility handling of Java 7 seems to be well done and working with Android.
So, did someone try with the good old Ant, to bypass the Eclipse limitation seen above?
Theroetical answer
Anyway, the SDK is designed to be used with Java 5 or 6, as explained here.
We may have something working with Java 7, but it would be working "by accident". The building of the DEX may work properly or not, and once the DEX built, it may work or not. This because using a non-qualified JDK gives unpredictable results by definition.
Even if someone has succesfully built an Android app under plain Java 7, this does not qualify the JDK. The same process applied to another application may fail, or the resulting application may have bugs tied to the use of that JDK. Not recommended.
For those who are involved on webapps development, this exactly the same as deploying a web application built under Java 5 or 6 under an application server qualified for Java 4 only (let's say Weblogic 8 for example). This may work, but this is not something that can be recommended for other purposes than trying.
Quote from dalvikvm.com:
dx, included in the Android SDK, transforms the Java Class files of Java classes compiled by a regular Java compiler into another class file format (the .dex format)
That means, the .java source file does not matter, it's only the .class bytecode.
As far as I know, only invokedynamic was added to the JVM bytecode in Java 7, the rest is compatible to Java 6. The Java language itself does not use invokedynamic. Other new features, like the switch statement using Strings or the multi-catch are just syntatic sugar and did not require byte code changes. For example, the multi-catch just copies the catch-block for each possible exception.
The only problem should be that the new classes introduced in Java 7 are missing in Android, like AutoCloseable, so I'm not sure if you can use the try-with-resources feature (somebody tried it?).
Any comments on that? Am I missing something?
As of the Android SDK v15, along with Eclipse 3.7.1, Java 7 is not supported for Android development. Setting the source compatibility to 1.7 mandates setting the generated .class file compatibility to 1.7, which leads to the following error by the Android compiler:
Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead. Please use Android Tools > Fix Project Properties.
To expand on the above answer by #KennyTM, if you are targeting 4.0.3 and above (minSdkVersion=15), you can use the hidden APIs by adding a few classes to your target's SDK android.jar.
Once you do this, you can use try-with-resources on any Closeable, as well as implement AutoCloseable in your own classes.
I've made a zip containing sources and binaries of all the classes that needed to be modified in android.jar to make these APIs available. You just need to unpack it and add the binaries to your android-sdk/platforms/android-NN/android.jar
You can download it from here: http://db.tt/kLxAYWbr
Also of note is that, in the past couple of months, Elliott Hughes has made a few commits to the Android tree: finished off AutoCloseable, added SafeVarargs, unhidden various APIs, fixed Throwable's protected constructor and added support for version 51 class files in dx. So, there is finally some progress going on.
Edit (April 2014):
With the release of SDK 19 it is no longer necessary to patch android.jar with the additional APIs.
The best method to use try-with-resources in Android Studio for an app that targets 4.0.3 and above (minSdkVersion=15) is add the following compileOptions to your build.gradle:
android {
compileSdkVersion 19
buildToolsVersion '19.0.3'
defaultConfig {
minSdkVersion 15
targetSdkVersion 19
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
Android Studio will complain that try-with-resources can't be used with this API level, but my experience is that it can. The project will build and run without issue on devices with 4.0.3 and above. I've experienced no issues with this, with an app that has been installed into 500k+ devices.
To ignore this warning, add the following to your lint.xml:
<issue id="NewApi">
<ignore regexp="Try-with-resources requires API level 19"/>
</issue>
It seems that getting this to work with pure ant is a bit of a kludge.
But it worked for me: http://www.informit.com/articles/article.aspx?p=1966024
In order to use Java 7 features in code build by Android's ant based build system, simply put the following in your custom_rules.xml in your projects root directory:
custom_rules.xml:
<project name="custom_android_rules">
<property name="java.target" value="1.7" />
<property name="java.source" value="1.7" />
</project>
Some people might be interested in this git project I've found, that seems to allow to run Java 7 on android.
https://github.com/yareally/Java7-on-Android
However too much of a risk if I add this in the current project I work on. So I'll wait until Google to officially support Java 7.

Categories

Resources