JNI编程一:详细阐述一个简单的JNI开发流程
在我们平时java开发的时候会调用到底层一些 .so/.dll动态库,这个时候就需要在java层和c/c++层进行交互,为了满足java和c/c++进行通信,就产生了一套java与native层交互的接口,也就是JNI (java native interface)。
JNI开发流程步骤
一、在java文件中编写native方法
我们使用eclipse来编写java代码,通过如下步骤来建立一个java工程:
打开eclipse ——> File菜单 ——> new ——> project... ——> java project ——> next ——> 输入项目名称 jni_demo1 ——>剩下的步骤大家都会了~
这样我们的java项目就建立好了,接下来就创建java类文件了,我们在jin_demo1项目下的src目录里面创建一个java类,取名就叫JniMain.java。

接下来我们就在JniMain.java文件里面写一个native方法:
public class JniMain {
public native static String getStringFromC();
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
这样我们就完成了第一步编写包含native方法的java类文件。
二、 使用javah命令生成 .h文件
首先进入cmd命令行工具,
进入的JniMain.java所在目录下,
再输入javah JniMain,
一定要在配置好的java环境下进行。

这个时候就生成了JniMain.h头文件。

三、复制.h头文件到cpp工程
接下来的步骤我们要创建一个cpp工程来编写native层代码:
1.使用Visual Studio创建一个工程
假设给这个工程取一个名字JNI_Demo1

2.将JniMain.h添加到头文件目录下
在vs右侧的解决方案里面如下图操作添加头文件

把JniMain.h复制到这个目录下


四、引入jni.h和jni_md.h
接下来我们打开JniMain.h文件会发现需要引入一个jni.h的文件,如下图

这个jni.h头文件在我们安装的jdk目录下有,我们来找到这个头文件

将这两个文件按照上面第二步的方法添加到头文件目录里面去

此时jni.h和jni_md.h就被添加到头文件里面了。
最后我们再将JniMain.h文件里面的 #include <jni.h> 改成 #include“jni.h”,因为手动引入非系统库的头文件一般都是用 “ ”

五、实现.h头文件里面声明的native函数
我们有了头文件里面声明的函数之后,这个时候我们就要去实现它,我就得要创建一个.c文件来编写这个函数的具体内容,假设我们这个.c文件叫做jni_impl.c


接下来咋们在jni_impl.c里面实现那个声明的函数,代码如下
#include "stdafx.h"
#include "JniMain.h"
JNIEXPORT jstring JNICALL Java_JniMain_getStringFromC
(JNIEnv * env, jclass jclz){
return (*env)->NewStringUTF(env, "hello JNI");
}
就是如此简单的代码,我们就实现了native层的编写。
六、生成一个动态库
动态库分为两种,在window平台下一般使用.dll动态库,在linux平台下一般使用.so动态库,本次我们生成一个.dll动态库。
在生成动态库之前,我们需要在vs做一些配置。
首先我们打开配置管理器,设置活动解决方案配置是debug,活动解决方案平台是x64,操作如下


然后我们还要设置一下配置类型为的动态库(.dll),如下图


然后再生成解决方案

此时我们会发现一个预编译头报错

我们只需要再按照如下图配置一下即可


接下来继续生成解决方案,就成功执行了

我们到工程目录下寻找JNI_Demo1.dll动态库,因为我们之前设置的活动解决方案平台是x64,之前我们设置活动解决方案配置是debug,我们可以在工程目录下的x64/Debug文件夹下找到动态库JNI_Demo1.dll。

七、在java工程中加载动态库
在找到动态库之后,我们就需要把动态库拷贝到java工程里面供使用,我们直接将JNI_Demo1.dll动态库拷贝到jni_demo1工程根目录下。

接下来,我们再在JniMain.java里面加载动态库,也就是我们最熟悉的那一句话
static{
System.loadLibrary("JNI_Demo1");
}
就这么简单动态库就加载起来了~~
八、触发java工程中native函数
最后就是直接调用native方法,我们就能将动态库里面的函数执行了。
public class JniMain {
public native static String getStringFromC();
static{
System.loadLibrary("JNI_Demo1");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(getStringFromC());
}
}
最后的结果就是 hello JNI

哈哈! 以上就是jni的整个实现流程。
最后附上两个工程的代码:
java工程:https://github.com/iwanttoseethecode/iava_jni_demo.git
c工程:https://github.com/iwanttoseethecode/c_jni_demo.git