Android: Use precompiled libraries? - android

Every time I add a library to my Android project the compilation process gets slower. Is there a way to cache the (library) dex files so only the application gets recompiled every time? Ideally the build process should check whether the library JAR has changed, if it hasn't it should reuse the prexisting dex file.
I am using nbandroid but I assume the Eclipse build suffers from the same problem.

The Build process (especially at dex step) in Android SDK (regardless of which IDE is in used) is quite inflexible. The only command usage of dx.jar AFAIK is something like below:
[INFO] C:\Program Files\Java\jdk1.6.0_21\jre\bin\java -Xmx1024M, -jar, C:\Program Files\Android\android-sdk\platform-tools\lib\dx.jar, --dex, --output=C:\workspace\myproject\target\classes.dex, C:\workspace\myproject\target\classes, C:\workspace\myproject\libs\common-lib.jar, ... ...
From here you can see that compiled classes with external jar libraries are dexed at project build time.
Is there a way to cache the (library) dex files so only the application gets recompiled every time?
Jar libraries get dexed, not recompiled by Android SDK every time you build your project. I don't think Android SDK provide another command usage of dx.jar which you can use to dex only the complied class without external jar libraries then merged into the pre-existing classes.dex (perhaps generated from last time).
It is not possible at project build time, however, it is probably off topic but you may interested in this blog talked about dynamically loading jar libraries at runtime, worth to check it out.

I'm using Eclipse and have a few projects with 2-3MB of libraries, did not notice any slowdown except when compiling and signing final APK with proguard. Looks like Eclipse does not recompile libraries every time.

Related

LibC++_shared is Present in APK but Not Found When Loading Libraries During Execution?

I'm working on an Android project with a pre-compiled .so file for OpenCV. The original distribution I used as my base (courtesy of QuickBird Studios) contains 2 .so files: libopencv_java4 and libc++_shared. The two .so files are taken from a .aar library which I had to unpack in order to address a known, long-standing issue in the OpenCV Android implementation. These two SOs are stored in the same folder in my project tree, as seen here. The other ABIs share identical structure to arm64-v8a.
When compiling the APK with Intellij IDEA (v2022.1.3), the APK analyzer shows that both .so files have been packaged in to lib/{ABI}, as can be seen here (in this case, the ABI is arm64-v8a). So far, so good.
However, when I go to load the OpenCV library (which calls upon libc++_shared), I receive the following error:
W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found: needed by {omitted}/base.apk/lib/arm64-v8a/libopencv_java4.so in namespace classloader-namespace
I've attempted building the APK without including libstdc++_shared, under the pretense that Gradle claims to be able to include the C++ shared libraries automatically. This failed with the same error message as above, with no libc++_shared.so in the APK.
I've also attempted to create a dummy native C++ file, in order to get libc++_shared added via CMake during the Gradle build process. This also failed with the above error. I did not think to check the APK during this attempt.
In a previous iteration of this project (before I discovered the bug in the OpenCV Android implementation), I was able to compile and run without issue by including the .aar file as an external library.
Between each of the above attempts, I've performed a full Gradle cache invalidation to make sure I'm not keeping broken files from previous tries.
I'm completely flummoxed. Did I break something when I unpacked the .aar to fix the bug? How can I get Android to acknowledge what's inside the APK?
I had the same issue after upgrading the Gradle plugin. the nonsense disappear after I also upgrade the Gradle build tool.
dependencies {
//after upgrad from 3.5.1 the link error disappear
classpath "com.android.tools.build:gradle:3.5.4"
...
}

Packaging external .so files into Android .apk files using Gradle

Recently, I ported my existing Android project from an ancient Gradle version to Gradle 6.6 and Android Studio's Gradle plugin 4.0.1. This project uses an external native library (.so file) that gets used in the Java code via JNI. This .so library has a dependency on libc++_shared.so because it is written in C++.
I realized that if I just copy the .so file into the corresponding platform folder (arm64-v8a, armeabi-v7a, x86, x86_64) within the jniLibs Gradle packages it "properly" into my .apk file.
By "properly" I mean that it automatically adds libc++_shared.so, which my library has a dependency on, as well as my own library to the .apk file. In addition, if I additionally set jniDebuggable to true in the build.gradle file it will also add the gdbserver library which is required to be able to attach the native code debugger.
Now, this is exactly what I want. The problem is that I cannot find any documentation that describes this behavior. The best source I could find is this but it does not mention anything about dependencies being packaged automatically. So, I don't know whether that is an officially supported way of doing things.
I suspect that there is a part of Android's Gradle based build process that automatically analyzes the files in the jniLibs folder and acts accordingly. It would be great to know a bit more to be aware what is really going on.
Does anyone have a reference that confirms my above observations or know which Gradle task (or whatever) accomplishes this? It would also be good to know in which Android Gradle plugin version this behavior was introduced.
Edit:
This answer to another SO question led me to the Android source file https://android.googlesource.com/platform/tools/build/+/master/builder/src/main/java/com/android/builder/internal/packaging/Packager.java
which seems to be the code that packages the .so files and gdbserver into the .apk file. But I have no explanation why libc++_shared.so gets packaged as well.

dexedLibs folder in android project

So I have noticed fairly recently a folder within my Phonegap/Android project (project/bin/dexedLibs) and this folder contains two .jar files. After scratching around the internet, I found one website in which the author says ADT version 21 puts "pre-dexed Libs" in the project to enable faster build times.
I did upgrade recently to ADT 21 and was just wondering if anybody else can give me more information on what these "pre-dexed Libs" really do? I haven't been able to find any other useful info on the net.
I have an Android project with about 20 external libraries. Before ADT 21, every time I changed source code it took ages to rebuild the app. Now it's quite fast!
I guess the reason is that, before ADT 21, it compiled the external libraries into dex code every time you hit the "Run" button in eclipse. Now it will compile the dex code for the external libraries only once (until they change) and use the prebuild libraries for later "Run"s.
I like that feature!
Be aware! I've just spent an hour to find out why I get the exception:
Caused by: java.lang.NoSuchMethodError:
The reason was because I changed my lib jar to new jar (the same name) with working method, and ADT 21 didn't prepare the new one in dexedLibs.
So just delete bin dir and Eclipse will recreate this.
The question is about 2 years old yet still of interest.
For people who browse here later: I just had trouble because I renamed a Cordova project from my.name.a3e to my.name.A3E and then the build process crashed. Came out that the dexed files in ant-build were not refreshed (case sensitivity). It worked fine after I deleted the ant-build folder, but the build took longer the first time after.
A dex file is a Dalvik EXecutable file, some compiled byte code that can be executed by the Dalvik virtual machine. Dalvik is a core component of Android, so that's why it is there.
http://sourceforge.net/projects/dexer/
http://developer.android.com/reference/dalvik/system/DexFile.html
http://fileinfo.com/extension/dex
Note that Eclipse project clean won't remove dexed libs.

Does slicing a large Android project into Android libraries improve build time?

I have a rather large Android project, and it takes considerable amounts of time for the sdk to do the resource-parsing / dexing / etc. I'd like to improve this somehow.
I've read that Android library projects can contain resources now too. So we can also put Activities, Fragments, etc. in them.
Does this mean, that if I export parts of my large project into library projects which I reference from the main project, then I don't have to rebuild the already built (and not modified) libraries again, when I rebuild the main project? So I only have to do the resource-parsing / dexing / etc. for the modified libraries and possibly the main project, decreasing the overall build time in most cases.
Does this mean, that if I export parts of my large project into library projects which I reference from the main project, then I don't have to rebuild the already built (and not modified) libraries again, when I rebuild the main project?
Partially no, Android Library Project is not built directly, it is always built along with the dependent Main Project, when SDK compile/build the Main Project, SDK tools compile the Library Project into a temporary JAR file and uses it in the main project. whenever you re-build your Main Project, the referenced Library Project is re-built as a part of main project build life cycle, even though nothing changed in Library Project. Check out timestamp of the temporary JAR generated under your app-lib/bin folder for evidence, it always get changed every time yo build Main Project.
Quoting from official dev guide:
However, a library project differs from an standard Android application project in that you cannot compile it directly to its own .apk and run it on an Android device. Similarly, you cannot export the library project to a self-contained JAR file, as you would do for a true library. Instead, you must compile the library indirectly, by referencing the library in the dependent application and building that application.
When you build an application that depends on a library project, the SDK tools compile the library into a temporary JAR file and uses it in the main project, then uses the result to generate the .apk. In cases where a resource ID is defined in both the application and the library, the tools ensure that the resource declared in the application gets priority and that the resource in the library project is not compiled into the application .apk. This gives your application the flexibility to either use or redefine any resource behaviors or values that are defined in any library.
Android Library Project is different from regular java library project. where you can compile and build everything into and jar library once, and start import/use the class from reference jar dependencies in main project. Currently Android Library Project is designed on source-based mechanism, not compiled-code based library mechanism, as mentioned in this Android blog, although self-contained jar distribution is promised in future release (unfortunately not in neither r15, r16, r17 nor r18 yet).
Yes... The build system rebuilds what needs to be built unless you build Clean.
I wouldn't expect huge time savings here.
In my experience, the slowest step of compilation is actually the dexing of the output files, which can not be performed incrementally, so moving your code into libraries will not speed things up. Similarly, incremental compilation (when it works — it often doesn't with the Android toolchain) will work equally well with unchanged files spread over a bunch of projects as will unchanged files in a single project.
Of course, the best way to find the answer for your actual use case is to experiment on your actual code base. And there may also be code maintainability benefits to splitting your project up into independent modules.

Android adding external libraries to project

I have a project that I would like to add external libraries to (and have them packaged with the application) but I am not sure it is happening. I read on this link:
https://developer.android.com/guide/appendix/faq/commontasks.html
how to, but they do not show up in any of the /data/data/project directories. Does anyone know how I can confirm that the libraries were in fact added to the project for use at runtime? Thanks.
If you include jars as External Jars under your project's Java Build Path, then the classes will be converted to Dalvik format and be made available in your project's classes.dex file, packaged into the .apk.
To confirm they are available, attempt to use something from the jar (Eclipse should suggest the relevant import when you first supply a class name) build and run the app and see if it works? If it works in development (e.g. from 'run' in Eclipse) then it will also work when the app is built in release and distributed as an APK.
You can also place jar under one of your source folders (perhaps creating special "libs" one) and adding it to build path.
Be warned - external libraries (which are compiled against some version or other of the libraries in a Java JDK) may sometimes have problems when running under android. This is because the Dalvik runtime has its own Java framework libraries, which provide most (but not all) of the Java APIs in the standard JDK Java framework libraries.
You should really recompile any external library against the android libraries so that you can see any missing APIs at compile time - and fix the issues there and then. Otherwise you run the risk of runtime errors under Dalvik when you call the external library from your Android app. See http://geekswithblogs.net/cyberycon/archive/2011/05/17/using-external-libraries-with-android.aspx
for more details.

Categories

Resources