I have an Android NDK project which builds and runs fine with Android.mk files, it consists of my native code (one C file) built as a shared library, this code has a dependency to a third party static library (.a file).
Right now I am trying to migrate it to Gradle. My current configuration is as follows:
Static library Android.mk that is under the /static_libs folder
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := opus
LOCAL_SRC_FILES := lib/libopus.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)
Main module Android.mk file: (under the usual jni/ folder)
LOCAL_PATH := $(call my-dir)
$(call import-add-path,$(LOCAL_PATH)/../static_libs)
include $(CLEAR_VARS)
LOCAL_MODULE:=opus_jni
LOCAL_SRC_FILES:= opus_jni.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -ldl
LOCAL_WHOLE_STATIC_LIBRARIES := opus
include $(BUILD_SHARED_LIBRARY)
$(call import-module,opus)
When I run ndk-build
on the main module the only output is one file libopus_jni.so
that is the only one used to build the final APK.
Now on Gradle, the only thing I want to do for now is create an APK with this same prebuilt shared library and the same code, so I copied my generated library into jniLibs/
folder (I know as of 0.9 Gradle already supports JNI libraries if the files are put here). The project builds and the final APK does contain the .so
file inside the libs/
folder. (I verified by unzipping the generated APK)
The problem is that when I try to use any of the native methods I get the following error:
05-28 14:57:53.393 3370-3370/com.opusgradle.app D/OB-OpusCodec﹕ testPcmToOpus()
05-28 14:57:53.393 3370-3370/com.opusgradle.app D/dalvikvm﹕ Trying to load lib /data/app-lib/com.opusgradle.app-2/libopus_jni.so 0x42630b18
05-28 14:57:53.393 3370-3370/com.opusgradle.app D/dalvikvm﹕ Added shared lib /data/app-lib/com.opusgradle.app-2/libopus_jni.so 0x42630b18
05-28 14:57:53.393 3370-3370/com.opusgradle.app D/OB-OpusCodec﹕ Trying to initialize...
05-28 14:57:53.393 3370-3370/com.opusgradle.app W/dalvikvm﹕ No implementation found for native Lcom/opusgradle/app/OpusCodec;.initOpusEncoder:(II)V
05-28 14:57:53.393 3370-3370/com.opusgradle.app D/AndroidRuntime﹕ Shutting down VM
05-28 14:57:53.393 3370-3370/com.opusgradle.app W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x415e0ba8)
05-28 14:57:53.393 3370-3370/com.opusgradle.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.opusgradle.app, PID: 3370
java.lang.UnsatisfiedLinkError: Native method not found: com.opusgradle.app.OpusCodec.initOpusEncoder:(II)V
at com.opusgradle.app.OpusCodec.initOpusEncoder(Native Method)
at com.opusgradle.app.OpusCodec.(OpusCodec.java:23)
at com.opusgradle.app.MainActivity.testPcmToOpus(MainActivity.java:78)
at com.opusgradle.app.MainActivity.access$000(MainActivity.java:22)
at com.opusgradle.app.MainActivity$1.onClick(MainActivity.java:64)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
As you can see the .so
file is found and loaded but the call to the native function fails. The Java code is the same as in the original project that works fine, basically the invocation to the library looks like this:
static
{
System.loadLibrary("opus_jni");
}
It seems that when a static library is required, Gradle needs something else copied into the jniLibs folder, I tried copying the .a file to the jniLibs/
folder too without any success.
Is there any other requirement for pre-built shared librares with a static library dependency to build correctly on Gradle?
Most likely, you changed the package name for the Java class that uses your native library. Usually, the native method names are hardcoded to satisfy JNI automatic binding. That's why you cannot use the prebuilt libopus_jni.so
.
The easiest resolution would be to rename the class com.opusgradle.app
back (was it com.opus.app
?). You can change this class without renaming the app package in AndroidManifest.xml
.
Alternatively, you can rename the Jni native method names in opus_jni.c
, rebuild the library, and copy it to the jniLibs/
folder for gradle.