NKD中使用第三方SO

概述

Android开发中有时会遇到使用JNI调用C/C++函数库的场景。一般这个时候都是使用NDKC/C++源代码编译出so文件,然后进行调用。但是有时候会遇到另外的情况:

我们在NDK项目中还要再引入其他第三方的SO库

这个时候该怎么编译呢?

通过使用动态函数库的调用方法,直接包含其头文件,便可以直接调用库中的类和方法。

具体使用过程可以分为两步:

  • 编写JNI文件包含第三方库的头文件。

  • 编写MK文件引入预编译库(即第三方库)。

举个例子

拿现在项目中遇到的一个具体情景:

现在手头有一个USB设备,公司要求实现在windowsAndroidLinux嵌入式三平台通用的USB驱动库,然后各个平台只用做小量修改即可使用。经过评估决定使用git上的一个开源项目libusb来实现,当然可以直接使用源码来编译一个so出来,但是这样不够B格,而且实际使用过程中还要引入另外一个库文件,所以这里使用上面说的方式来调用,如下。

编写JNI文件

在要编写的源文件目录下新建include文件夹(其实这个随便),将要使用的函数所在的头文件放入其中,如:libusb.h。

在我们的源码中包含这个头文件

1
#include "include/libusb.h"

然后直接在需要使用的位置调用相应的函数即可:

1
2
3
4
5
6
7
JNIEXPORT void JNICALL Java_com_yannan_usbtest_UsbTest_libUsbInit
(JNIEnv *env, jclass jobj) {
if (libusb_init(NULL) < 0)
{
LOGD("VeinSensorBase::Open(): libusb_init() <0\n");
}
}

编译MK文件

首先将第三方库作为预编译引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := usb_pre
LOCAL_SRC_FILES := usb/libusb-1.0.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := usb_test.c
LOCAL_SHARED_LIBRARIES := usb_pre
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

其中:

  • LOCAL_MODULE := usb_pre 给这个第三方库取一个名字,不需要与原来的名字相同

  • LOCAL_SRC_FILES := usb/libusb-1.0.so 表示这个库的路径,是在MK文件的目录下的usb目录中

  • PREBUILT_SHARED_LIBRARY 表示这是一个共享库,即so库。

  • LOCAL_SHARED_LIBRARIES := usb_pre 这一步则表示此模块依赖于上面命名的预编译库。

然后执行ndk-build编译即可,此时在libs文件夹中会生成两个so文件,分别为libtest.solibusb-1.0.so,都拷贝到项目中就可以了。