How to package prebuilt shared library inside an APK - android

This question seems to have been asked a lot but all were trying to use eclipse to package the library inside the APK.
However, my requirement is to package the library inside the APK (which will later be loaded using System.loadLibrary() through Java) using the Android build system, i.e. i want to write an Android.mk file that does this job.
Requirement:
1. Prebuilt shared library: libTest.so
2. Write an Android.mk file that will package this to libs/armeabi-7 inside the apk.
I don't know much about the build system I am using but the compilation is done using "mm" command after exporting the required environment variables.
When I provide libTest for LOCAL_JNI_SHARED_LIBRARIES, it tries to find it inside its exported paths and fails to find it there and hence build fails.
Can anyone please give any pointers on writing an Android.mk file that will package my prebuild shared library into the APK?

In order to prebuild your native library you have to
Create jni folder in your project folder
Create libs folder in your project folder
Add Adnroid.mk make file to the jni folder, it should looks like
this:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := Test
LOCAL_SRC_FILES := Test.cpp
include $(BUILD_SHARED_LIBRARY)
Note 1: Test.cpp is the main library source file containing implementation of native methods. You can add more sources as a space separated list.
Note 2: Do not include headers, they are included automatically.
Note 3: If you need to enable C++ STL, then create another make file - Application.mk, add it to the jni folder and set APP_STL := stlport_static flag in it.
Then you will have to set up a builder. Refer to this article for how to do that:
After these steps, the builder will create your library in the libs folder which will be automatically packed into the apk when building the whole application.
Note: Your library name should be lowercase, it is a Linux convention. The "lib" prefix will be automatically added, so the final library name will be libtest.so.

Let's say there is one libxxx.so shared library under libs/armeabi/ of project which you want to pack into apk. There are 2 things you need to do in the Android.mk as below:
# 1. Copy .so to out/target/product/***/obj/lib
$(shell cp $(wildcard $(LOCAL_PATH)/libs/armeabi/*.so $(TARGET_OUT_INTERMEDIATE_LIBRARIES))
# 2. Make libxxx to be packed into apk
LOCAL_JNI_SHARED_LIBRARIES := libs/libxxxx
Then you can use apktool to unpack the built apk, you will find the libxxx.so will be located in libs/armeabi*/. It is indeed packed into the apk.

I had two LOCAL_JNI_SHARED_LIBRARIES that I wanted to build into my APK. I manage to do it by setting the following in my Android.mk:
LOCAL_MODULE_TAGS := samples
After re-compiling the module I was able to find both libraries inside the .apk under /lib/.

Related

How to use prebuilt c++ library for android ndk project

I am a android NDK newbie, I am trying to follow the documentation at https://developer.android.com/ndk/guides/prebuilts and I found it is unclear on how to setup the code.
So to declare a prebuilt library, it shows the first step:
Give the module a name. This name does not need to be the same as that
of the prebuilt library, itself.
Question 1: What does this mean by giving the module a name? rename the module folder? is this the folder usually called jni/? does it matter where this folder should be?
Question 2: If I don't find this jni/ folder, should I just add one by creating a new folder or right clicked on my project in android studio to add new module? I did the right click thing and there is no such module for native c++ libs.
the second step:
In the module's Android.mk file, assign to LOCAL_SRC_FILES ...
Question 3: Should I create the 1Android.mk` file by myself? if it is a must, why not have it generated automatically?
I then tried to follow the documentation at https://developer.android.com/studio/projects/add-native-code#new-project but there is no such Android.mk file created...
Anyway, in the Android.mk file it has something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-user
LOCAL_SRC_FILES := foo-user.c
LOCAL_SHARED_LIBRARIES := foo-prebuilt
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)
Question 4: On the documentation page, where variables like PREBUILT_SHARED_LIBRARY BUILD_SHARED_LIBRARY is defined? can these path can be any place in the system as long I define it with full path?
Question 5: for LOCAL_PATH, I understand it is the local path where the Android.mk file locates, does that mean 1) the system will find this file automatically, 2) I can only have one folder with Android.mk if I want to use native libs?

Why ndk-build will modify prebuild so libraries?

I use some prebuilded so in the prebuild directory of an Android JNI project. The Android mk file for the prebuild libs are like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuild
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
But each time when I run ndk-build -B, the so files generated in libs/armeabi changed. So I realized that ndk-build modified the so files rather than simplely copied them. This is annoying when I have to manage these so files with version control software like git, since it is hard to kown if the comitted version is consistent with the so in the prebuild directory. Can I keep them the same?
To check what exactly NDK does on your binary - run it with verbose output: ndk-build V=1. This will print all commands, that NDK does under the hood. Probably it strips debug info, non-exported entries in symbol table with strip.

android ndk communicate different c++ project

I want to create a c++ project for android ndk.And I want to use it every project like dynamic library.I dont want to change /transport source code every time.I import *.so file and include it and use its class or whatever.
This is possible.If it possible how could import and use it.
Or i create java project and i use it to communicate c++ project with using jni and i compile it.After that i have a *.jar file and i use it instead of android ndk.
Which one of them possible or effective.
I'm not entirely sure if I understood the question correctly, but I assume you prefer to write your Android applications using solely/mostly C++ and have a core library/module that you want to re-use for every consecutive project WITHOUT including that libraries SOURCE files in each consecutive project.
You can omit including the source files and include the final built .so file in your new project by adding the required libraries into your makefile. Like so:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for libraryname)
LOCAL_MODULE := libraryname
LOCAL_SRC_FILES := libraryname.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
--- instructions for custom application code here ---
LOCAL_SHARED_LIBRARIES := libraryname
Where "libraryname" is the name of the library module and "libraryname.so" is the name of the library file. Note the path should be relative to the make file. Below the second "include $(CLEAR_VARS)" and above the final "LOCAL_SHARED_LIBRARIES" you add the instructions for building the source code of the application which is to use the shared library.
Don't forget to load all libraries in order on the Java side, i.e.:
System.loadLibrary( "libraryname" );
System.loadLibrary( "customlib" );

Accessing headers for NDK from Android Library Project

I'm currently implementing a custom Logging mechanism that I need to be accessible from both native and Java code. The fundamentals of the logging are implemented in C/C++ with a Java wrapper, and the two together are being built as an android Library Project.
The issue at hand is that while my Java code can access the Library project output, there doesn't seem to be a way for my native code to access the native .so or headers from the Library project. Is there an additional step I'm missing or is this just a limitation of the current ADT? More specifically, is there a makefile/eclipse configuration that will address the things I'm used to getting out of Library projects in general? (Build .so as needed, import rebuilt .so, import relevant headers for c/c++ compilation, etc.)
I don't think it's a limitation. We are supposed to declare native code dependencies in Android.mk and Application.mk
Worked out a way to get what I wanted - most of the information is (of course) in the NDK documentation, but what I was trying to do isn't 100% supported within the ADT. It should also be noted that I'm currently stuck developing in a windows environment, so much of this might be easier or unnecessary in Linux. The first key is the $(call import-module ...) macro. Within your library project, move the source files and the Android.mk folder into a named directory you can locate later. My Library project directory looked like this:
MyProject
> src
> res
v jni
- Application.mk
v MyLib
- source.cpp
- source.h
- Android.mk
I also had to edit my Application.mk to point to the project:
APP_PROJECT_PATH := <path-to-my-project>
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/MyProject/Android.mk
Annoyingly, this broke my Android.mk in ways unforseen until I added a ./ to my source files. Also you need to export your includes for linking:
LOCAL_SRC_FILES := ./source.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
Ensure that the system path variable NDK_MODULE_PATH is set to include your library's JNI directory, e.g. <path-to-my-project>/jni (Note: I had to restart eclipse after I did this).
In the receiving application's Android.mk file (the one you'd like to link natively to your app), import the module:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyNativeProject
LOCAL_SRC_FILES := source.cpp
LOCAL_CFLAGS := -DANDROID_NDK -g -std=c99
LOCAL_SHARED_LIBRARIES := MyLib
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-module, IntelLog)
At this point everything built perfectly, but the APK packager didn't like the generated .so binary being included twice (once from the Library project's natural import process, and again from the import-module call). To solve this, clean the library and don't build it again! the import-module call will build the .so and import it into your project. (Obviously, if your project only requires the Java API, you would need that .so file to be built). Congratulations! you have a functional (if not straightforward) build process with a hybrid native/Java Library

Copy files to libs folder as a part of build script

I have an android application which uses jni and I'm trying to automate build process in Eclipse (using cdt plugin). I need to build my own static library, and I also need to use some precompiled libraries.
That means that I need to
a) build my own shared library (no problems here)
b) after build is complete, copy existing libraries into libs/armeabi folder (because this folder will be cleared during build process I must copy those files after every build)
I have some problems with b). What I'm trying to do is I'm inserting custom shell script (which works when executed as-is) after include $(BUILD_SHARED_LIBRARY) in Android.mk file. Unfortunately, this doesn't work, because apparently /libs/armeabi folder gets cleared only after Android.mk file is complete.
Is that true? Is there a way to insert post-build script into Android.mk? Is there any way I can execute bash script after jni code finished building but before whole build is complete (e.g. before java part is build and application starts executing?)? I though there must be some kind of "post-build" script in eclipse c/c++ project build settings, but there is no such thing.
Here's the complete Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_MODULE := player
LOCAL_SRC_FILES := player.c
include $(BUILD_SHARED_LIBRARY)
$(shell ./copy-libs.sh) #this script will get called, but the files will be erased right after
Well, it looks like there is an easier way to copy .so and .a libs without resorting to custom build scripts.
NDK supports prebuilt modules starting from ndk-r5, and they allow to copy .a or .so libraries into obj/lib folder during build process as needed.
Example and complete description are available in PREBUILTS.html file inside $NDK_INSTALLATION_FOLDER/docs/.

Categories

Resources