一、背景
有时,应用需要访问的系统特性和设备通过java平台是无法实现的,这时我们使用jni技术。
二、步骤
2.1 在本地声明一个本地方法
public class HelloNative {
//native本地方法关键字
public static native void greeting();
}
项目结构如图:
2.2 运行javah(jdk 8),javac -h(jdk 10+)获得包含该方法的C声明的头文件
注意,从jdk10开始,javah命令就被删除了,使用javac -h A.java直接生成A.class和A.h文件。cd到.java文件的目录,执行以下命令:
其中./代表生成的class和h文件的存储目录,一定要写,不然会报错
此命令在当前目录生成了.class和.h文件
2.3 用C实现该本地方法
新建一个C项目,将HelloNative.h拷贝进去
生成的.h文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */
#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloNative
* Method: greeting
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloNative_greeting
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
发现include<jni.h>位置报错:“jni.h" not found。
跑到jdk/include目录下找到jni.h,放到helloNative.h同目录下
将include<jni.h>改成include "jni.h"解决该报错 该报错解决吼,发现JNIEXPORT飘红,JNIEXPORT变量找不到,跑到jdk/include/win32下找到jni_md.h,放到helloNative.h同目录下,报错解决
新建HelloNative.c,放到helloNative.h同目录下,实现该头文件的函数Java_HelloNative_greeting;
//
// Created by wangwenxuan on 2019/12/7.
//
#include "HelloNative.h"
JNIEXPORT void JNICALL Java_HelloNative_greeting
(JNIEnv *env, jclass object){
printf("Hello World");
}
此时C项目结构如下:
2.4 将代码置于共享库中
unix和类unix平台打包成.so文件,windows平台打包成.dll文件。
windows平台方法
(1)使用cmakeList 和cmake. make 打包(要下载cmake)
(2) 使用gcc命令,MingW等带有该命令的执行文件,为该执行文件设置环境变量即可
(3)一些编译器自带生成.dll文件的方法,比如Vs
使用gcc方法如下:
接下来就是使用GCC对HelloJNI.c编译,在Terminal窗口输入如下:
C:\Users\wangwenxuan\CLionProjects\HelloNative>gcc -c HelloNative.c
完成编译。此时在项目中会生成HelloJNI.o文件。接下来是将HelloJNI.o转为HelloJNI.dll,即转为windows平台下的动态链接库。在Terminal中输入如下:
C:\Users\wangwenxuan\CLionProjects\HelloNative>gcc -Wl,--add-stdcall-alias -shared -o hello.dll HelloNative.o
会在HelloNative.c同目录生成.dll文件,目录结构如下:
2.5 在Java程序中加载此类库
public class HelloNativeTest {
static{
System.loadLibrary("hello");
}
public static void main(String[] args){
HelloNative.greeting();
}
}
java程序结构:
运行结果:
可能出现的错误
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) at java.lang.Runtime.loadLibrary0(Runtime.java:870) at java.lang.System.loadLibrary(System.java:1122) at com.huachao.java.HelloJNI.<clinit>(HelloJNI.java:8) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:123) Process finished with exit code 1
即找不到我们生成的dll文件。可以在library的path中加入我们的dll文件
File——Project Structure——Libraries——新建Java library,选中我们生成的dll文件即可。
- 32bit和64bit的冲突。是gcc版本和jdk版本的冲突,有一个是32位一个64位,重新下载改成一致的