JNI 调用外部 so 里面的函数 so插件化 [附源码]

什么是 so插件化

简单的来说就是:把数据处理或者算法在外部 so 库实现,当算法或者数据处理的逻辑需要改变的时候 在项目代码完全不变动的情况下 只要修改 so 库然后更新 so就实现修改。

需要会下面的东西:

生成 so 库

AS 里新建个 C 文件。代码里写个简单的加法运算。啥头文件都不用导入这个文件就这点代码

int add(int a ,int b){
    return  a+b ;
}

用 Linux 命令将上面的 c 文件生成 so 文件(也可以利用 JNI 环境自动生成 so 文件)。

生成 so 的命令:
    gcc -fPIC -shared so.c -o sotest.so
so.c 就是写加法运算的 c 文件
sotest.so 就是生成的文件。

将生成的 so 复制到安卓项目的 libs/armeabi(你适配了几个架构都要拷贝) 因为这里的 so 库是会被系统拷贝到内部存储的特定目录的 比如 /data/data/package/lib

在安卓项目里调用这个 so ;

在 activity 写个 native 方法(这个方法是在 JNI 里面实现的)

public native int getSoPlugIntValue(int a,int b);

JNI 里面的代码

  • 导入两个头文件

    jni.h、dlfcn.h

  • 实现 native 方法。

typedef int (* Add)(int a,int b);
JNIEXPORT jint JNICALL Java_com_test_custom_mydemos_NDK_L16_L16_getSoPlugIntValue
        (JNIEnv * env, jobject jobj, jint a, jint b){

    void * handle = dlopen("/data/data/com.test.custom.mydemos/lib/libsotest.so",RTLD_LAZY);
    if (handle == NULL){
        return -1 ;
    }

    Add add = NULL ;
    *(void **)(&add) = dlsym(handle,"add");

    return add(a,b);
}

几个东西解释一下

  • dlopen
    指定模式打开指定的动态连接库文件。就是打开 so 库拿到这个库的操作句柄。

  • “/data/data/package/lib/xxx.so”
    关于这个路径 我把 so 放在 “/data/user/0/package/lib/xxx.so” 下也可以读取 但是放在外置 sd 卡路径读取失败。拷贝到内部存储的 jni_libs 目录下也读取失败。也就是说这个路径是特殊路径才有效。而这些路径都是不能进行读写操作的。里面的文件都是由系统拷贝进去的。

    扫描二维码关注公众号,回复: 5326916 查看本文章
  • RTLD_LAZY
    RTLD_LAZY 暂缓决定,等有需要时再解出符号
    RTLD_NOW 立即决定,返回前解除所有未决定的符号。

  • dlsym
    根据动态链接库操作句柄与符号,返回符号对应的地址。就是调用方法
    (项目里这方法可能编译不过 但是不用管 可以运行的。)

最后安卓项目里调用 so 库

TextView viewById = (TextView) findViewById(R.id.test);
        viewById.setText("从 so 获取的 5+9 的值 : "+getSoPlugIntValue(5,9));

这里写图片描述

**

源码

**

猜你喜欢

转载自blog.csdn.net/u013171212/article/details/78315672