JNI 全称为Java Native Interface 即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以让Java与C/C++相互调用。
一、如何使用JNI(注:本文中均只介绍CMakeList方式编译):
首先我们要在java中声明一个本地方法如:(此为kotlin 写法 java 写法为 public native void init();)
然后我们需要再c或C++文件中实现
1 .静态注册方式:
静态注册方式方面的命名必须严格按照命名规则命名 为 JAVA_包名(包名用_分隔)_类名_方法名(JNIEnv *env,jobject mjobject,其他参数..)。
JNIEnv是当前Java线程的执行环境,一个JVM对应一个JavaVM结构,而一个JVM中可能创建多个Java线程,每个线程对应一个JNIEnv结构,它们保存在线程本地存储TLS中。因此,不同的线程的JNIEnv是不同,也不能相互共享使用。JNIEnv结构也是一个函数表,在本地代码中通过JNIEnv的函数表来操作Java数据或者调用Java方法。也就是说,只有在本地代码中拿到了JNIEnv结构,才在本地代码中调用Java代码。jobject 是对应的是java的对象类型 在该方法中表示的是调用该本地方法的对象
2动态注册方式
当我们使用System.loadLibarary()方法加载so库的时候,Java虚拟机就会找到这个JNI_OnLoad
函数并调用该函数。所以我们可以在该函数中注册去动态的注册函数。先看代码
首先我们通过getEnv() 获取到 JNIEnv结构体指针再看jniRegisterNativeMethods()方法
先是调用了FindClass( className) 获取需要关联对象的jclass(对应java 的class)
然后调用RegisterNatives(clazz, gJni_Methods_table, numMethods) 方法 参数clazz为关联对象的 参数jclass gJni_Methods_table 为JNINativeMethod 的结构体数组 numMethods为 jclass gJni_Methods_table 的大小(方法的个数)
在这里我们要介绍下JNINativeMethod结构体, JNINativeMethod是一个在jni中定义的结构体用于描述native函数与java 函数的关系 数组中有三个参数 其中name为 java 层的方法名; signature 为函数表示(有参数和返回值组成的字符串,篇幅有限这就不在这展开说了) ;fnPtr为native方法的方法指针。
编写CMakeList文件
到此处我们便可以在java成中调用native方法了。
二、在通过JNI在native方法中调用java方法
1、 先要在native方法中调用java方法必须要先拿到该方法的id 获取方法id的方法为GetMethodID如
第一个参数: jClass为 方法所在的类的jclass对象 如例中就相当MainAcitivy.class ;
第二个参数: 为方法名
第三个参数:为有参数和返回值组成的函数签名
2 调用使用
CallVoidMethod
第一个参数为 : jobject (本例中相当于MainAcitivty的实例对象)
第二个参数为:jmethodID
第三个为参数 :对应参数(如有不止一个参数则在后面继续跟)
至此完成Java 与 native的互相调用