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.
Related
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"
...
}
I have added a library under Android aosp vendor folder and successfully created shared lib (lets say, libmyvendor.so) files. And verified that .so files are created under both system/lib and system/lib64. Flashed on a device and working fine here.
To debug my ndk application, I have copied .so files into Android's path sdk/ndk/{versionNumber}/platforms/android-28/arch-x86/usr/lib. Also in archx86_64/usr/lib64 folder. Did invalidate and restart Android Studio. Now I'm trying to find or add libmyvendor library in my ndk application using cmake function
find_library(mVendor libmyvendor)
Tried myvendor instead of libmyvendor. In both cases, cmake couldn't find it.
Then tried copying libmyvendor.so files into ndk application (under jniLibs/x86/ and x86_64/ ). Compiled but app crash at runtime saying
UnSatifiedLinkError: dlopen failed library 'libcrypto.so' not found
Where libcrypto.so is needed as a dependent to libmyvendor project. And I'm stuck here.
As per my assumption, libmyvendor is part of system libs. NDK should be capable of finding it using find_library(), just like we find liblog.so. But it cannot find. Did I miss or mess anything?
I was wondering if it's possible to package my native .so files into my .aar file? If so, where would the .so files go and are there any references that I can read in regards to this?
jni/<platform>/libexample.so
doesn't work.
It should be src/main/jniLibs/<platform>/libexample.so
http://www.codepool.biz/build-so-aar-android-studio.html
If you put it manually, then it should be placed underneath
jni/<platform>/libexample.so
where platform is a target CPU platform like "armeabi", "x86" etc. Typically you will have so-files for multiple platforms there. If you build from source code using Gradle you could simply put your native source code to
src/main/jni/
and build plugin will do the rest. As the resulting so-files will be built automatically and placed where they belong to.
Regarding the references, I've seen this been mentioned somewhere on the site dedicated to Android build plugin for Gradle. Since then I wasn't able to find this page again. But you can check out plugin's source code for more details.
I have a package integrated to Android 5.0 sources. It has a java service and a couple of native libraries. When I build it I get an apk with symbolic links to native libs (in /system/lib64/) and it's supposed that libs are already there. I have to make the package installable from app market, that is all libs must be included to the apk. I could get such an apk with SDK, but I cannot use it because I have dependencies on non-public libs and java classes.
How can I build apk in-tree so that my native libs are included in apk itself?
It really depends on the libs you want to use.
If you rely on libssl.so and libcrypto.so, you should compile your own version of OpenSSL, include and use it from your APK.
For other system libs that are officially part of the NDK (libc.so, libandroid.so...), there is no need to symbolic link anything, they will automatically be loaded from the system.
If you really need to use non-public libs and classes, you can do so, by loading directly the libs from the system, it doesn't make sense to embed a copy of these. However it may be a big source of crashes to use anything private, you shouldn't do that.
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.