Android 学习笔记 ——本地调用,Java调C/C++,生成 .so,.so调用其他.so

准备工作

Android Studio下载的NDK是最新版,已不支持armabi和mips架构,所以想支持生成所有cpu平台,需要下载r15或之前版本ndk,可通过官网下载旧版NDK

如果有现成的so,可跳过第一步制作生成so。

一,制作生成 .so

这里我一次同时做两个,方便之后互相调用

新建两个java类,
NativeMethodCall 生成目标so
CallNativeMethod 生成用来调用目标so的中间so
在这里插入图片描述

public class CallNativeMethod {
    
    

    public static native String callNativeMethodFromSO();

    public static native int callNativeMethodFromSOSub(int a,int b);;
}
public class NativeMethodCall {
    
    
    public static native String helloFormC();

    public static native int sub(int a,int b);
}

注意所属的包名,之后生成的so方法名是基于 "包名_类名_方法名” 的。

创建好之后,打开Terminal
在这里插入图片描述
使用cd 命令到当前项目的java目录
在这里插入图片描述
再使用 javah + 包名类名 命令,生成 .h文件。

我这里将两个文件都生成了.h在这里插入图片描述
之后在main中新建jni目录,并将 .h 文件都拖到 jni目录
在这里插入图片描述
之后在jni目录创建几个文件,分别是:

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := NativeMethod     #对应生成libcreate.so库
LOCAL_SRC_FILES := NativeMethod.c  #create.c源文件的名字

include $(BUILD_SHARED_LIBRARY) #构建动态链接库

include $(CLEAR_VARS)
LOCAL_MODULE    :=CallNativeMethod
LOCAL_SRC_FILES :=CallNativeMethod.c
LOCAL_SHARED_LIBRARIES := NativeMethod
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)

Application.mk:

APP_ABI := all

NativeMethod.c:
注意这个里面的很长的方法名,可以拷贝上面自动生成的.h中对应的名称
(#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h> 这句也要改成自己的.h

#include <stdio.h>
#include <stdlib.h>
#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h>

JNIEXPORT jstring JNICALL Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_helloFormC
(JNIEnv * env, jclass jobject){
    
    
    return (*env) -> NewStringUTF(env,"hello form C");
};

JNIEXPORT jint JNICALL Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_sub
  (JNIEnv *env, jclass jobject, jint a, jint b){
    
    
    return a+b;
};

CallNativeMethod.c:
注意这个里面的很长的方法名,可以拷贝上面自动生成的.h中对应的名称
(#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h> 这句也要改成自己的.h

#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "jni.h"
#include  "dlfcn.h"
#include <fcntl.h>
#include <com_wwb_test_testcallnativelibrary_CallNativeMethod.h>

void * filehandle = NULL;
jstring (*getResult)(JNIEnv *, jobject) =NULL;

JNIEXPORT jstring JNICALL Java_com_wwb_test_testcallnativelibrary_CallNativeMethod_callNativeMethodFromSO
  (JNIEnv * env, jclass thiz){
    
    
    jstring result = "";
    filehandle = dlopen("libNativeMethod.so", RTLD_LAZY);
    if (filehandle) {
    
    
        getResult = (jstring (*)(JNIEnv *, jobject)) dlsym(filehandle,"Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_helloFormC");
        if (getResult)
            result = getResult(env, thiz);
        dlclose(filehandle);
        filehandle = NULL;
    }
    return result;
  };

  jint (*getSubResult)(JNIEnv *, jobject, jint, jint) =NULL;
  JNIEXPORT jint JNICALL Java_com_wwb_test_testcallnativelibrary_CallNativeMethod_callNativeMethodFromSOSub
    (JNIEnv * env, jclass thiz, jint a, jint b){
    
    
      jint result = 0;
      filehandle = dlopen("libNativeMethod.so", RTLD_LAZY);
      if (filehandle) {
    
    
          getSubResult = (jint (*)(JNIEnv *, jobject, jint, jint)) dlsym(filehandle,"Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_sub");
          if (getSubResult)
              result = getSubResult(env, thiz, a, b);
          dlclose(filehandle);
          filehandle = NULL;
      }
      return result;
    };

在这里插入图片描述
其中CallNativeMethod是在调用NativeMethod里面的对应方法。

随后,回到Terminal,cd命令到jni目录下
使用ndk目录的 ndk-build 命令,如下图,是我的ndk位置,之后回车
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
完成后,可以在生成的libs目录中看到,各种架构的.so。
在这里插入图片描述

二,调用.so

在app目录下的build.gradle中添加如下代码

sourceSets {
    
    
        main() {
    
    
            jniLibs.srcDirs = ['src/main/libs']
            jni.srcDirs = []  //This prevents the auto generation of Android.mk
        }
    }

在这里插入图片描述
修改MainActivity.java

public class MainActivity extends AppCompatActivity {
    
    
    //直接加载调用最终so
//    static {
    
    
//        //加载so库
//        System.loadLibrary("NativeMethod");
//    }
    
    //加载调用中间so
    static {
    
    
        //加载so库
        System.loadLibrary("CallNativeMethod");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //调用最终so方法,返回结果
//        Log.e("CallNative",""+NativeMethodCall.helloFormC());
//        Log.e("CallNative",""+NativeMethodCall.sub(1,2));

        //调用中间so方法, 中间so再去调用最终so,返回结果
        Log.e("CallNative",""+CallNativeMethod.callNativeMethodFromSO());
        Log.e("CallNative","1 + 2 = "+CallNativeMethod.callNativeMethodFromSOSub(1,2));
    }
}

其中注释了的是直接调用最终so的代码。
未注释的是调用中间so,中间so调用最终so的方法详见CallNativeMethod.c中的实现。

java
CallNativeMethod.so
NativeMethod.so

在手机或者模拟器里运行一下,可以看到打印结果
在这里插入图片描述
实现了,java调用so,so调用另一个so的方法。
如果.so是现成的,那就直接放到src/main/libs目录下就可以了
只需添加在这里插入图片描述
和java的调用即可。

更多类型的库调用jar,so,aar,可以借鉴 android.mk中引用第三方库的方法

猜你喜欢

转载自blog.csdn.net/wwb1990/article/details/104256783