使用JNI 调用第三方c++动态库

来源:互联网 发布:异形知乎 编辑:程序博客网 时间:2024/05/08 09:48

昨天晚上到今天一直在折腾这个第三方库文件,唉,要哭了,一直就是各种问题。现在详细说说怎么做,踩过哪些坑。

现有个第三方的C++动态库(libModel.so),这个libModel.so是要能被android调用的arm库啊,需要在android中,使用java直接调用,那么一般是两种方式:

1:libModel.so 符合JNI规范,能够直接在java层调用
2:libModel.so不符合规范,只是普通的c++动态库,那么只能是在JNI,写个c/c++函数,调用这个libModel.so库里面的函数,然后重新编译为libhello.so库,android调用这个libModel.so;其实就像给libModel.so再封装一层。

由于libModel.so不符合JNI规范,我只能采用第二种方式。
首先,创建一个HelloTest的android程序,然后在HelloTest中新建一个jni文件,在jni文件中仔创建一个prebuilt文件夹,里面存放libmodel.so,并且新建一个Android.mk。
Android.mk的内容如下:

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := model LOCAL_SRC_FILES := libModel.so include $(PREBUILT_SHARED_LIBRARY)

然后在jni里面新建Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.cpp LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := model LOCAL_ALLOW_UNDEFINED_SYMBOLS := true //避免出现undefined的错误 include $(BUILD_SHARED_LIBRARY)include $(LOCAL_PATH)/prebuilt/Android.mk //包含prebuilt下的Android.mk

因为我jni里面的具体函数使用到了,所以需要添加一个Application.mk,Application.mk内容如下:

APP_STL := stlport_static

在这里也遇到了坑,一定要确保你是.cpp文件,不然Application.mk没有作用,依然会报:
error :can not find iostream的错误,因为这个stlport_static是供c++使用的。

在APK运行时,报了如下的错误,无法加载库,那是因为apk没有找到库文件:

01-02 03:50:05.655: E/AndroidRuntime(32314): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1285]:  2824 cannot locate '_ZN13CVQASSESSMENTC1Ev'...

我之前尝试使用如下方式进行打包,不创建prebuilt文件夹 ,直接在jni的Android.mk,加入libModel.so库,:

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libModel LOCAL_SRC_FILES := libModel.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE  := modeljni  LOCAL_SRC_FILES := modeTest LOCAL_SHARED_LIBRARY  := libModel    include $(BUILD_SHARED_LIBRARY) 

以上面的方式打包,在apk运行的时候,就找不到库,我也没有想明白为什么,还是我的打包有问题,用第一种方式执行成功

还有在java端调用库的时候,两个库都要包含进去,且顺序是先libModel.so,在调用新生成的。

static    {    System.loadLibrary("Model");    System.loadLibrary("hello");    }

其次就是c++库需要传递结构体参数,我是这样做的,在JAVA定义一个包含结构体所需参数的类,然后呢,java向jni中的C++ 传递 一个对象,c++解析java的对象,再重构第三方库需要的结构体参数, java 与c 传参 博客写的挺好的,具体的实现是:
首先在java申明native 方法:

public native int getInput(SideInfo sideInfo);

然后,使用javah 生成头文件,将头文件拷贝至jni中, jni中c++具体的实现如下:

//java 向c 传递对象jint  Java_com_example_hellotest_MainActivity_getInput(JNIEnv * env, jobject jthis, jobject sideInfo){CVQASSESSMENT VqAssessUnit;jmethodID methodId;//获得sideInfo对象的句柄jclass cls_objClass=env->GetObjectClass(sideInfo);//获得sideInput对象中特定方法getI_Audio_sample_rate的idmethodId=env->GetMethodID(cls_objClass,"getI_Audio_sample_rate","()I");//第三个是方法的签名,可以通过 javap -s XX.class的方式查看方法的签名。//调用sideInfo对象的特定方法getI_Audio_sample_ratejint  jrate=(jint)env->CallIntMethod(sideInfo,methodId,NULL); //获取不同的值,有不同的CallXXMethod方法。return jrate;}

通过这样的方法,就可以向c++ 传递java对象了。

1 0