转载

Android JNI介绍(六)- 依赖其他库

在前面的文章中,我们已经了解了Java函数和native函数的绑定过程,了解了Java和native的绑定方法,本文将介绍如何让一个库依赖其他库。

一、动态库和静态库

首先介绍下动态库和静态库的概念。

  • 静态库

    在开发过程中,我们常常会用到一些常用的公共函数,我们可以将这些函数编到库中,在编写其他程序的时候一起整合到最终程序中,这种库就是静态库,在 编译时 链接,在 Linux 下一般是 .a 文件。

  • 动态库

    动态库在内部提供函数,让其他程序在运行时调用。在 Linux 下一般通过 dlopendlsym 等函数动态寻找,在 运行时 链接,在 Linux 下一般是 .so 文件。

对于外部引入的静态库,我们在编译时会将其一起打包到新生成的动态库中;

对于外部引入的动态库,我们需要将它们一起打包到 apk 中。

二、在Android Studio下引入外部库

这里以动态库为例,首先我们编一个动态库:

1. 编写代码

新写一个 CMakeLists.txt

add_library(abi
        SHARED
        abi.cpp)
复制代码

src/main/cpp/abi/abi.h 中定义如下函数

extern "C" const char *getAbi();
复制代码

src/main/cpp/abi/abi.cpp 内容如下,不同 ABI 的动态库会回传不同的结果

#include "abi.h"

const char *getAbi() {
#ifdef __arm__
    return "arm32";
#elif __aarch64__
    return "arm64";
#elif __i386__
    return "x86";
#elif __x86_64__
    return "x86_64";
#endif
}
复制代码

build.gradle 中重新指定 CMakeLists.txt 的路径

...
    externalNativeBuild {
        cmake {
//            path "CMakeLists.txt"
            path "src/main/cpp/abi/CMakeLists.txt"
        }
    }
    ...
复制代码

2. 编译动态库

然后点击 Android Studio 右侧的 Gradle 窗口中,指定 moduleexternalNativeBuildRelease 任务(也可以 gradlew 执行命令)。

Android JNI介绍(六)- 依赖其他库
执行成功后,我们就能在 build

目录下看到生成的动态库文件

Android JNI介绍(六)- 依赖其他库

3. 将动态库放到 src/main/jniLibs 目录下

Android JNI介绍(六)- 依赖其他库

为什么是这个目录,而不是其他目录?这是因为, src/main/jniLibsAndroid Studio 工程的默认动态库文件存放位置,如果将生成的库放在其他位置,打包apk的时候就不会把库拿过来一起打包,于是运行时就会缺少 libabi.so ,从而导致crash,如下:

Android JNI介绍(六)- 依赖其他库

4. 在CMakeLists.txt中配置依赖的动态库

build.gradle 中切换回原来的 CMakeLists.txt

...
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
//            path "src/main/cpp/abi/CMakeLists.txt"
        }
    }
    ...
复制代码

CMakeLists.txt 内容如下,添加依赖

cmake_minimum_required(VERSION 3.4.1)
add_library(
        native-lib
        SHARED
        src/main/cpp/native-lib.cpp)

find_library(
        log-lib
        log)
        
set(abi-lib ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libabi.so)

message("abi-lib is ${abi-lib}")

target_link_libraries(
        native-lib
        ${abi-lib}
        ${log-lib})
复制代码

其中,

message 函数用于输出信息到控制台;

set 函数用于创建变量,用法为 set(variable value) ;

CMAKE_SOURCE_DIR 表示当前 CMakeLists.txt 文件所在的目录;

CMAKE_ANDROID_ARCH_ABI 表示当前编译的 ABI ,如 armeabi-v7aarm64-v8a 等;

此时点击 externalNativeBuildReleaseRun 窗口输出如下,说明依赖 libabi.so 成功

release|armeabi-v7a :abi-lib is D:/android/android-projects/git/JNIDemo/app/src/main/jniLibs/armeabi-v7a/libabi.so
release|armeabi-v7a :-- Configuring done
release|armeabi-v7a :-- Generating done
release|armeabi-v7a :-- Build files have been written to: D:/android/android-projects/git/JNIDemo/app/.externalNativeBuild/cmake/release/armeabi-v7a
release|arm64-v8a :abi-lib is D:/android/android-projects/git/JNIDemo/app/src/main/jniLibs/arm64-v8a/libabi.so
release|arm64-v8a :-- Configuring done
release|arm64-v8a :-- Generating done
release|arm64-v8a :-- Build files have been written to: D:/android/android-projects/git/JNIDemo/app/.externalNativeBuild/cmake/release/arm64-v8a
release|x86 :abi-lib is D:/android/android-projects/git/JNIDemo/app/src/main/jniLibs/x86/libabi.so
release|x86 :-- Configuring done
release|x86 :-- Generating done
release|x86 :-- Build files have been written to: D:/android/android-projects/git/JNIDemo/app/.externalNativeBuild/cmake/release/x86
release|x86_64 :abi-lib is D:/android/android-projects/git/JNIDemo/app/src/main/jniLibs/x86_64/libabi.so
release|x86_64 :-- Configuring done
release|x86_64 :-- Generating done
release|x86_64 :-- Build files have been written to: D:/android/android-projects/git/JNIDemo/app/.externalNativeBuild/cmake/release/x86_64
复制代码

5. 在工程中调用 libabi.so 中的函数

在Java代码中定义native函数并调用

public native String getABI();

......
Log.i(TAG, "onCreate: getABI = " + getABI());
......
复制代码

native实现

...
#include "abi/abi.h"
...
extern "C" JNIEXPORT jstring
JNICALL
Java_com_wsy_jnidemo_MainActivity_getABI(
        JNIEnv *env,
        jobject /* this */) {
    return  env->NewStringUTF(getAbi());
}
复制代码

modulebuild.gradle 中进行配置,以指定 ABI 运行

android{
    ...
    defaultConfig{
        ...
        ndk{
            abiFilters "armeabi-v7a" // 指定以armeabi-v7a运行
            // abiFilters "arm64-v8a","armeabi-v7a"  // 以arm64-v8a、armeabi-v7a中,目标设备支持的最优ABI运行
            // abiFilters "arm64-v8a" // 指定以arm64-v8a运行
        }
        ...
    }
    ...
}
复制代码

前后以 armeabi-v7aarm64-v8a ABI运行,结果如下

Android JNI介绍(六)- 依赖其他库
原文  https://juejin.im/post/5e02147ae51d4557f17fc198
正文到此结束
Loading...