一. 前言
最近接到一个项目,由于我们公司做水控设备项目,买的挺好的,有一个客户需要做对需要我们设备接入他们的系统,于是需要我们提供二次开发接口,而且是Java 平台的,通过由于这个项目我编写的客户端是使用C# 编写的,并且都是所有接口都是集成到客户端中,因此没有预留给其他平台调用的接口。由于Java Web 不能直接操作硬件。因此,需要我提供Java 能调用的接口,Java能调用的接口并且可以直接操作硬件,只能是C/C++ 。于是,通过JNI Java可以间接操作我们公司的USB设备,于是写下这篇文件,记录JNI 编写的过程,防止下次忘记了,又需要重新学习。
二. 简介
2.1 什么是JNI
JNI(Java Native Interface)意为JAVA本地调用,它允许Java代码和其他语言写的代码进行交互相(一般为C/C++),简单的说,一种在Java虚拟机控制下执行代码的标准机制。
2.2 JNIEnv与JavaVM
JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;
JNIEnv 与 JavaVM : 注意区分这两个概念;
-- JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;
-- JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;
JNIEnv 作用 :
-- 调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;
-- 操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;
摘自《JNI 实战全面解析》
2.3
详细关于JNI 相关可以查看大神文章,讲的非常好《JNI 实战全面解析》
三. 开发环境

(1) JDK v1.8 (2) Eclipse 2018-12 (4.10.0) (3) Visual Studio 2015
四. JNI 相关代码编写
4.1 编写由Java native 类接口,通过javah 命令生成.h文件
java 类
package com.chen.jni;
public class JNIInterface
{
//由java 调用c/c++ 接口打印信息
public native void hellojni();
//java 传递 byte 数据到C/C++ 中,并且修改
public native void testByteArray(byte[] stream);
static {
System.loadLibrary("testjni");
}
}
使用找到JNIInterface.java 文件,使用在Windows 控制台中javah -classpath . -jni com.chen.JNIInterface 生成对应.h 文件
如下图:
4.2 使用VS 创建DLL 工程,编写JNI 到x64动态库
4.2.1 新建Win32 控制台工程
4.2.2 选择DLL
4.2.3 将使用javah 生成的.h 文件拷贝到Win32 DLL 工程目录下
4.2.4 将.h 文件添加到工程上和jni.h 相关的文件也拷贝到工程目录下,并且添加到工程中将jni.h 和相关文件拷贝出来,是方便当工程移动到别的电脑照样可以直接编译。
4.2.5 编写同名.cpp 文件,并且实现接口
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_chen_jni_JNIInterface.h"
/*
* Class: com_chen_jni_JNIInterface
* Method: hellojni
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_chen_jni_JNIInterface_hellojni
(JNIEnv *env, jobject jobj)
{
printf("helllo jni");
}
/*
* Class: com_chen_jni_JNIInterface
* Method: testByteArray
* Signature: ([B)V
*/
JNIEXPORT void JNICALL Java_com_chen_jni_JNIInterface_testByteArray
(JNIEnv * env, jobject jobj, jbyteArray jByteArray)
{
int ik = 0;
unsigned char data[4] = { 0 };
env->GetByteArrayRegion(jByteArray, 0, 4, (jbyte *)data);
printf("java to c++ data\n");
for (ik = 0; ik < 4; ik++)
{
printf("data[%d] = %.2X ", ik, data[ik]);
data[ik] = data[ik] + 1;
}
env->SetByteArrayRegion(jByteArray, 0, 4, (jbyte *)data);
}
4.2.6 在C/C++ 工程配置中,添加JNI 目录依赖
4.2.7 根据使用场景,配置工程编译为64位DLL 或者32 位DLL.
4.3 在Eclipse 中Java 通过JNI 调用C++
4.3.1 将生成的DLL 拷贝到java 工程目录下
4.3.2 配置工程,增加JNI 库支持
然后,就可以调用了。