2019-1-4日,记录一下这两天使用jni调用C++的过程
项目有一个需要控制ipc的功能,我之前取巧用了visca协议,走网口的,结果同组的C++的同事听闻我这样控,问了我控制方法,发现我这样控制很简单,而他使用onvif协议写了很多内容,遂验证该协议是否能对其他大厂的IPC进行控制,测了一个海康威视的摄像头就不行了,上网查了一下发现visca协议大多支持串口,网口实现的较少,相比之下Onvif协议比较通用,遂准备重新实现Onvif协议,刚开始写这个功能的时候也了解过,但是因为较麻烦又刚好从其他人那里知道了visca协议才没有实现,确实很麻烦,然后向C++同事请教控制流程,问过之后听他说可以用Java直接调C++的方法,我之前确实学完就忘了,然后重新学了一遍Jni,踩了不少坑记录一下
1.创建一个类,里面有 native 修饰的方法,可以是 static 修饰的
1 import java.util.Map; 2 3 public class Hello { 4 public native String hello(Map map); 5 6 }
2. 类路径下使用dos命令 {javac 类.java} ,编译出class 文件
1 C:\>javac Hello.java
3. 类路径下使用{javah 类名},生成 .h文件在同一路径下
1 C:\>javah Hello
这个地方有一个坑,刚开始测试的时候在类路径下这样执行是没问题的,但是正式放入项目中使用时报错了,
1 package com.x.hello;
放在项目中使用时要根据在package的最外层包下执行,也就是包含这个包com,项目路径下的src文件下执行,生成的文件在执行dos命令的路径下
1 C:\>javah -classpath . -jni 包名.类名
4. 打开VS2019(其他版本均可,我习惯性下最高版本),创建一个空项目
点击源文件,添加,类,头文件名改为生成文件名,然后点击添加,
5.打开头文件中生成的 头文件,把javah编译后生成的头文件内容复制到里面
这一步第一次的话也有一个坑,需要打开项目的属性页,点击c/C++,在附加目录中添加Java底层C++文件的路径,jdk安装目录下include文件夹和include文件夹下的win32文件夹,
如:
C:/jdk/include
C:/jdk/include/win32
6. 打开源文件在添加的类中放入以下内容
1 #include<iostream> 2 #include "hello.h" 3 4 using namespace std; 5 6 JNIEXPORT void JNICALL Java_Hello_hello(JNIEnv* env, jobject f) 7 { 8 printf("hello123"); 9 }
点击项目名生成即可。
需要注意的是这个设置内容需要和Java安装的环境一样,在这里32位不兼容64位,暂不清楚原因
7. 根据生成路径,在路径下找到 后缀位 .dll 和项目同名的文件,复制到C:/windows/system32 下即可
8. 打开Hello.java ,添加main方法调用native修饰方法,调用前使用
System.loadLibrary("C++项目名,不要后缀");
,试试效果,刚开始时也可直接写main方法,不过其中刚开始写可能会有语法问题,所以不建议生成头文件时就写main方法
1 package com.xh.server.utils; 2 3 public class OnvifUtil { 4 static { 5 System.loadLibrary("OnvifUtil"); 6 } 7 8 public native void hello(); 9 10 public static void main(String[] args){ 11 OnvifUtil onvifUtil = new OnvifUtil(); 12 13 onvifUtil.hello(); 14 15 } 16 17 }