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.
Related
Background info
When uploading an app to the play store that uses a native library its necessary to also upload the native debug symbols to get useful crash/ANR info.
If you upload without symbols you receive the following warning: "This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug."
In the past when uploading apps as .apk files it was necessary to manually upload such debug info. Now using .aab if the native library is built via android studio its possible to set android.defaultConfig.ndk.debugSymbolLevel = 'FULL' at which point when you build a the .aab it will include the debug info automatically, you upload this single file and everything is done/working.
pre-built libraries
However its not always possible/ideal/necessary to build a library inside android studio. Sometimes there are reasons for libraries to be externally pre-built and just used by android studio not built by it; Android studio supports this via a directory structure which is described here https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs
In short you just copy the libraries into the correct src/main/jniLibs/{ABI} path(s) and it is picked up and made part of the bundle.
Problem
Android studio can build a .aab that contains debug info that play store can understand so that you don't need to upload it manually.
Android studio can use pre built native libraries if you place them in the right path structure
I am unable to find any documentation or way to do both of these things together, use native pre-built libraries but include their debug info in the .aab. Even though logically it should be possible to do this.
I have searched everywhere I think but can't find anyone even talking about this really, how/where do you place the corresponding debug information so that that also can be included as part of the .aab? Is there a separate path for this, do they just need a specific file extension, does gradle need to be told what to do with them somehow?
Is it really just not possible?
Things I have tried:
Don't split the debug info just leave them in the .so files - play store does not strip them then so you deliver giant debug versions of your builds to your users
Split the debug info into files with .so.dbg extension and place them alongside the .so files - they aren't included in the .aab
Following the instructions (here https://support.google.com/googleplay/android-developer/answer/9848633 and elsewhere) to manually zip and upload the symbols after uploading the .aab - this appears to work but isn't the same convenience wise as having them in the .aab
I've tried building a sample app with android studio building a lib instead of using a pre-built lib just to verify that it does then include the debug info and what file extension it uses.
After some more digging I found the task responsible for this is "ExtractNativeDebugMetadataTask" with which some effort can likely be tailored/altered to do custom things here.
However this ended up being unnecessary as while digging into this I discovered that it actually already works.
At least as of now in latest gradle versions (not sure about the past).
It was only failing due to some NDK path confusion which doesn't fail the build/creation of the bundle building but just logs an easy to miss informational message.
Ultimately all you need to do to make this work is:
Build your external .so files with -g -g3 or similar
Do not strip them in any way
Place them in jniLibs directory structure un-stripped
Configure your build.gradle appropriately android{ ndk { debugSymbolLevel 'FULL' } ndkPath "$projectDir/path/to/NDK" }
Resulting .aab will contain the stripped .so files and the split-debug .so.dbg files all in the right location.
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.
I'm trying to build an app bundle but I'm getting the following error:
File 'root/lib/x86_64-MacOSX-gpp/jni/libjunixsocket-native-2.0.4.jnilib' uses reserved file or directory name 'lib'.
For what I've seen from similar questions, this issue is normally solved juggling dependencies or files in the project structure, but in this case it seems to point to a native library involved in app architecture if i'm not mistaken. Any ideas how to solve this?
It looks like you are adding a dependency as a jar instead of an aar.
The aar contains the information of what files should be considered as Android resources, native libraries, etc. in the app. A jar is just a plain list of files without Android concept. Because the jar you're depending on contains a directory lib, the files would normally end up being considered as native libraries, but because the files come from a jar instead of an aar, the build system warns that it's unlikely to be a native library and may have unintended consequences at runtime.
Try to package that library as an .aar instead of a .jar. See this documentation: https://developer.android.com/studio/projects/android-library
Edit:
Note that this file could not be loaded by the Android platform if it was included as is in the APK, so even though the previous build systems would allow you to put anything in an APK, the Android App Bundle is more restrictive to ensure that you don't accidentally put unnecessary files which would increase unnecessarily the size of your app.
Ok it is working now! Steps I used to found the problem (thanks for pointing me in the right direction #Pierre)
Run a gradle build --scan from your terminal or go to the Gradle tab in Android Studio, select :app, help , androidDependencies to see your dependency graph.
Search the dependency graph for the library name related to the problem ( in my case I searched for socket, there was no match for libjunixsocket for example).
Going upwards on the dependency tree I realized it was caused by the 'io.voucherify.android.client:voucherify-android-sdk:2.1.0' dependency.
I just added #aar at the end of the dependency implementation, and I managed to build the app bundle.
implementation 'io.voucherify.android.client:voucherify-android-sdk:2.1.0#aar'
I am new in Gradle.
I've been made android library and I will upload this into maven repository.
But is it possible to add "Readme.txt" into my library?
for example,
When someone add my library into dependencies section in build.gradle and sync.
then Gradle creates(or copy) "Readme.txt" into target project(probably $projectDir or $projectDir/app) and user can read it(Like NuGet)
(Important things of this library, how to use example or something like that.)
I think it is really annoying visit project web-site and read "How to use" every using single library.
I want my library contains how to use text file.
Thank you.
I don't think this is possible, you don't know how the calling use is referencing your project. They are likely only referencing the compiled source code and never running your gradle file.
This is not a good idea, you don't know their exact folder structure, and even if you did you can not be sure that your readme.txt would have a unique name that did not conflict with their project file.s
When using a .jar file you cannot include this as resources cannot be compiled into it. But you can export your library as an *.aar file which can contain resource files. You get this by using "com.android.library" as your plugin type and can then find the aar-file in your build folder after you have built it.
This can then be included in your other project e.g. as a file reference.
Hi I am working on a Android native application.
There is 'abc.so' files which depend on some 'xyz.so.1' file. All of the required files are available in the project structure before building, but the '.so.1' are not a part of the generated .apk file (I checked the apk file by unpacking).
This is causing in a "'java.lang.UnsatisfiedLinkError' Couldnt load 'abc.so.1' from loader dalvik" when trying to run the application.
I dont want to push the .so.1 file as the phone is not rooted and runs on a production build. How do I include the .so.1 files as a part of the APK?
Thank you.
I think you havent got the concept of loading native libraries to Java through JNI.
First you define the native methods in java and do the corresponding implementation in the native and compile it (you have to register the native methods by either 1) following a naming convention 2) registering the native methods in jni_onload...i think you must have done this, if not check http://www.ntu.edu.sg/home/ehchua/programming/android/android_ndk.html)
Next, you have to load the library before any call can be made to native. This has to be done once. You can do it in an activity by defining:
static{
System.loadLibrary("mylib.so");
}
Note while compiling the library you will have got the library name as libXYZ.so, but when loading the library in java the "lib" should be omitted ,just system.loadlibrary(XYZ.so)
If you are using NDK the library would have been already copied to Java project > libs > armeabi folder , if not you have to copy your lib.so there
Now if you have multiple shared libraries , you should load the least dependent lib.so first , followed by second etc i.e.
Static {
System.loadLibrary(independent_lib.so); // should depend on only android libs
System.loadLibrary(next_dependent_lib1.so); //can depend on android libs and independent_lib.so
System.loadLibrary(next_dependent_lib2.so); //can depend on android libs,independent_lib.so,next_dependent_lib1.so
.....
....
..
}
If you jumble up, the VM will not be able to link the libraries and throw a unsatisfied link error.
Lastly, all this .so s will be part of your apk and it will be pushed to the system libs only runtime. Unless its a rooted phone you cannot extract the .so. If you follow the above method you will not need to push any .so to the system. Only build on eclipse/cygwin and run
Hope this helps,
Regards,
Shrish