android studio中使用第三方so库(终结版)

    安卓开发中,经常会用到第三方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库就讲完了,希望对大家有所帮助。

 

你可能感兴趣的:(android studio中使用第三方so库(终结版))