CMake的使用请见android中使用CMake,这里就不讲使用了,官方的说明里讲的很清楚,我这里就说一下常见问题的出现原因。
1、如果我们想要在自己的c/c++代码中使用一些第三方库的函数,比如ffmpeg。我们可以通过add_library来添加相关依赖(官网教程里面有详细说明)。但是我们打包好的ffmpeg的so库
应该放在哪里呢? 通常存放so库,我们是放在这两个位置的,那么到底应该放哪里呢?其实两个都是可以的,只不过你需要在gradle和CMakeLists.txt里面说明
不然有可能会出现以下问题
A、编译能通过,但是安装的时候会报 java.lang.UnSatisfiedLinkError : dlopen failed : library
这种情况,你需要在build.gradle里面添加如下代码
如果你是放在libs文件夹
- sourceSets.main {
- jniLibs.srcDirs = ['libs']
- jni.srcDirs = []
- }
- sourceSets.main {
- jniLibs.srcDirs = ['src/main/jniLibs']
- jni.srcDirs = []
- }
- add_library(avcodec SHARED IMPORTED)
- set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libavcodec-57.so)
- ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libavcodec-57.so
如果放在libs下面,就需要如下写
- set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libavcodec-57.so)
- set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)
上面说了avcodec其实只是你自定义的一个库的名字,但是你的add_library和set_target_properties以及进行link的target_link_libraries里面一定要保持一致如果我们在target_link_libraries的时候写错了,比如依赖库。
- add_library(avcodec SHARED IMPORTED)
- set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)
- target_link_libraries( # Specifies the target library.
- native-lib
- avcode
- }
2、还是依赖第三方库的问题,如果你出现了missing and no known rule to make it这个error,但是按照上面的方法并没有解决,如下错误
看起来,好像跟上面的错误很相似,也是在build
我们自己的libnative-lib.so这个库的时候,他需要依赖第三方库,但是没依赖成功,但是其实注意红色箭头指示的点,mips64??为什么会出现这个文件夹??其实使用jni编译的时候,在他讲我们的c文件打包成so库的时候,如果我们没有指定打包成哪种架构的so库,他默认是会进行所有的打包的(个人猜测),也就是在打mips64这个架构的so库的时候,他去对应地方找依赖的so库,发现没有找到,就会报上面的错误,这个时候,如果我们只支持armeabi架构,那么需要在build.gradle文件defaultConfig中添加如下代码
- externalNativeBuild {
- cmake {
- cppFlags ""
- abiFilters 'armeabi'//, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
- }
- }
3、同样是依赖第三方库,编译的时候,发现找不到使用的第三方库里面的某个函数,也就是undefined
reference to “某某函数”,但是又不是上面的那个原因。

我们的cpp代码如下
- #include <jni.h>
- #include <string>
- #include <libavformat/avformat.h>
- #include <libavcodec/avcodec.h>
- extern "C"
- {
- jstring
- Java_com_example_lenovo_ffmpegdemo_FFmpegUtils_stringFromFF(JNIEnv *env, jobject ) {
- char info[10000] = { 0 };
- av_register_all();
- sprintf(info, "%s\n", avcodec_configuration());
- return env -> NewStringUTF(info);
- }
- jstring
- Java_com_example_lenovo_ffmpegdemo_FFmpegUtils_stringFromJNI(
- JNIEnv *env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
- return env->NewStringUTF(hello.c_str());
- }
- }
- extern "C"
- #include <jni.h>
- #include <string>
- extern "C"
- {
- #include <libavformat/avformat.h>
- #include <libavcodec/avcodec.h>
- jstring
- Java_com_example_lenovo_ffmpegdemo_FFmpegUtils_stringFromFF(JNIEnv *env, jobject ) {
- char info[10000] = { 0 };
- av_register_all();
- sprintf(info, "%s\n", avcodec_configuration());
- return env -> NewStringUTF(info);
- }
- jstring
- Java_com_example_lenovo_ffmpegdemo_FFmpegUtils_stringFromJNI(
- JNIEnv *env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
- return env->NewStringUTF(hello.c_str());
- }