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中引用第三方库的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值