赞
踩
安卓开发中,经常会用到第三方C++库,然后不知道是我对系统不熟悉的原因,还是安卓支持C++开发本来就比较弱,反正其中踩了很多坑。
android studio 版本 3.0.1, 在PC上安装android studio3.1.2,就是配置不成功,后面再笔记本上安装android studio3.0.1, 安装成功,本以为在PC上重新安装android studio3.0.1应该可以成功,但实际还是不行,因该是哪里配置问题,卸载时又卸载不干净。
操作步骤:
1、在android studio中建立一个工程,修改工程名,选择支持C++,其他使用系统默认参数
支持c++的工程中,多了一个CPP目录,里面一个native-lib.cpp,同时也多了一个CMakelists.txt
后续我们要修改下面几个文件:CMakelists.txt,app下面的build.gradle,native-lib.cpp,MainActivity.java
2、拷贝so和include文件到工程目录中
在app目录下建立一个 libs目录,然后在libs目录中,根据so的编译的cpu架构,建立该架构名的目录,我的是armeabi-v7a,将so文件拷贝到该目录。
同时在libs下面建立include目录,把头文件放这个目录下;
注:目前有七种安卓的cpu架构:1.armeabi ,2.armeabi-v7a,3.arm64-v8a,4.x86,5.x86_64,6.MIPS,7.MIPS64,目前主流的是armeabi-v7a,CPU架构具体介绍请百度;
3、修改CMakelists.txt文件
先设置一个环境变量:set(distribution_DIR ${CMAKE_SOURCE_DIR}/libs)
这个里面感觉是最坑的,下面逐个介绍
1)include目录配置,效果就是 -I 参数,有两个方法
INCLUDE_DIRECTORY(${distribution_DIR}/include) # 感觉无效,设置后并没有参数效果
target_include_directories(native-lib PRIVATE
${distribution_DIR}/include) # 这个测试是OK的
2)加载so
2.1)方法一
add_library( ebase_define
SHARED
IMPORTED)
set_target_properties( ebase_define
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi-v7a/libebase_define.so)
#set_target_properties:这里有个坑,后面再讲
target_link_libraries(
native-lib
ebase_define #在target_link_libraries中增加ebase_define 效果是增加 -l 参数
${log-lib})
2.2)方法二:使用-L参数
set(LD_LIBRARY_PATH ${distribution_DIR}/armeabi-v7a) # 测试无效,从命令行中来看,并没有增加-L参数
LINK_DIRECTORIES(${distribution_DIR}/armeabi-v7a) # 测试无效,从命令行中来看,并没有增加-L参数
target_link_libraries(
native-lib
ebase_define #在target_link_libraries中增加ebase_define 效果是增加 -l 参数
${log-lib})
测试了很多网上用的方法,结果都没有参数 -L 参数,感觉这是一个bug,此路不通过,有大神知道怎么增加 -L 参数请不吝赐教。
其实上面两个方法都有问题,我们暂且先用方法一继续。
4、修改build.gradle
1)android/defaultConfig 中增加:
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
}
2)android 中增加:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
jniLibs.srcDirs = ['libs'] 从测试效果来看,主要是打APK软件包时有用,没有加这个,apk中不会有libebase_define.so库
5、修改native-lib.cpp,这个可以参考native-lib.cpp现有代码以及C++语法,编写自己需要的接口
6、修改MainActivity.java
class MainActivity 中增加:
static {
System.loadLibrary("ebase_define"); // 增加的
System.loadLibrary("native-lib"); // 自动生成的
}
说明:其实System.loadLibrary("ebase_define");都可以不需要,加载native-lib库时,由于native-lib依赖ebase_define,会自动加载ebase_define库。
7、编译、测试
通过上面的方法,编译成功,但是运行时出错,打开app后闪退,日志显示:
java.lang.UnsatisfiedLinkError: dlopen failed: library "../../../../libs/armeabi-v7a/libebase_define.so" not found
这错误真是让人头疼,为啥运行时,会加载这个目录的so呢,这个目录在哪里设置的?
最后经过千山万水,终于发现这是前面挖的坑:
set_target_properties( ebase_define
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi-v7a/libebase_define.so)
这个目录就是跟${distribution_DIR}/armeabi-v7a/libebase_define.so目录一致,原来android studio将编译和运行的目录搞成一个了,这难道是个bug?
8、解决问题
没办法,只能继续回到编译时增加 -L 参数的方法,这样编译的时候,lib库就不需要路径了,
有人说使用find_library,测试还是无效
find_library(LIBHELLO_PATH ebase_define F:/paas_msp/android_prj/HelloC/app/libs/armeabi-v7a NO_DEFAULT_PATH)
link_libraries(${LIBHELLO_PATH})
找了各种方法,还是没有搞定,问题还要继续搞。
去掉add_library和set_target_properties两个函数后,编译时报错,找不到 -lebase_define ,这是预想到的,在错误的命令行中,找到了一个-L参数,这个参数是系统增加的,-LD:/Android/android-sdk-windows/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a
其中D:/Android/android-sdk-windows是android sdk的安装目录,于是我将库放到了D:/Android/android-sdk-windows/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a目录下
终于编译成功了,并且测试也是OK的,不再报java.lang.UnsatisfiedLinkError: dlopen failed: library "../../../../libs/armeabi-v7a/libebase_define.so" not found 这个错误。
上面仅仅是通过规避的方法搞定的,增加-L参数才是正道,不知道哪个大神能够指点一二。
后面使用开源项目时还遇到一个问题:开源项目一般编译出来的so带版本号,如openssl编译后的so有版本号, libssl.so.1,因为编译时需要用libopenssl.so,我把这个文件名改成了libopenssl.so,编译是通过了,但是运行时找的是openssl.so.1,linux下通常是用link文件搞定的,但是windows又不支持link文件。这让我想到前面的加载so的java代码,我是让系统自动加载的,没有显示调用加载 openssl库,在 System.loadLibrary("native-lib"); 的前面增加System.loadLibrary("openssl"); 嘿嘿,问题解决了。
好了,android studio中使用第三方so库就讲完了,希望对大家有所帮助。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。