JNI是什么
JNI是java平台的一个特性(与Android无关)
英文参考文档中的介绍如下:
The Java™ Native Interface (JNI) is a powerful feature of the Java platform.
Applications that use the JNI can incorporate native code written in programming
languages such as C and C++, as well as code written in the Java programming
language. The JNI allows programmers to take advantage of the power of the Java
platform, without having to abandon their investments in legacy code. Because the
JNI is a part of the Java platform, programmers can address interoperability issues
once, and expect their solution to work with all implementations of the Java plat-
form.
JDK环境搭建
想要使用jni,需要搭建好jdk环境。
jdk-8u211-linux-x64.tar.gz 的下载地址:
https://download.oracle.com/otn/java/jdk/8u211-b12/478a62b7d4e34b78b671c754eaaf38ab/jdk-8u211-linux-x64.tar.gz?AuthParam=1559785898_96645c696d32befddea78681f9c1926f
把jdk-8u211-linux-x64.tar.gz解压到/usr/local/jdk目录下,然后修改~/.bashrc文件,在该文件最后面,添加如下内容:
#JDK
export PATH=/usr/local/jdk/jdk1.8.0_211/bin/:$PATH
然后使用 source ~/.bashrc命令更新环境变量。
判断环境是否配置成功:
root@ubuntu:/usr/local/jdk# java -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
root@ubuntu:/usr/local/jdk#
如所示,jdk环境搭建完成。
使用流程:
JNI测试
下面介绍jni的测试过程。
HelloWorld.java 文件
新建 HelloWorld.java文件,并填充代码如下。
class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.loadLibrary("HelloWorld");
}
}
使用如下命令编译,生成 HelloWorld.class文件:
root@ubuntu:~/ken/jni# javac HelloWorld.java
root@ubuntu:~/ken/jni# ls
HelloWorld.class HelloWorld.java
root@ubuntu:~/ken/jni#
HelloWorld.h 文件
使用如下命令编译,生成HelloWorld.h文件。之后根据该.h文件,编写jni的.c文件。
root@ubuntu:~/ken/jni# ls
HelloWorld.class HelloWorld.java
root@ubuntu:~/ken/jni# javah -jni HelloWorld
root@ubuntu:~/ken/jni# ls
HelloWorld.class HelloWorld.h HelloWorld.java
root@ubuntu:~/ken/jni#
打开HelloWorld.h文件,内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method:print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
HelloWorld.c 文件
则我们编写HelloWorld.c文件如下:
#include
#include
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
libHelloWorld.so 动态库文件
接下来,把HelloWorld.c文件编译成动态库:libHelloWorld.so即可。
PS:
1、此处编译出的动态库的名称,是HelloWorld.java文件中定义了的。
System.loadLibrary(“HelloWorld”);
上面这条程序的作用就是加载libHelloWorld.so库文件。
2、在HelloWorld.h文件中函数声明是:
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
在HelloWorld.c文件中函数定义为:
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
如果函数参数中没有定义*env和obj,则会在编译库时报错:
HelloWorld.c: In function ‘Java_HelloWorld_print’:
HelloWorld.c:6:1: error: parameter name omitted
Java_HelloWorld_print(JNIEnv, jobject)
^
HelloWorld.c:6:1: error: parameter name omitted
3、笔者这边是在linux环境下测试的。如果是windwows的话,编译出.dll文件。
接下来,编译出动态库:
root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall HelloWorld.c -o libHelloWorld.so
HelloWorld.c:1:17: fatal error: jni.h: No such file or directory
#include
^
compilation terminated.
root@ubuntu:~/ken/jni#
如上,报错显示找不到动态库。
此时就和之前的jdk环境搭建有关系了。
root@ubuntu:~/ken/jni# ls /usr/local/jdk/jdk1.8.0_211/include/
classfile_constants.h jawt.h jdwpTransport.h jni.h jvmticmlr.h jvmti.h linux
root@ubuntu:~/ken/jni#无锡人流多少钱 http://www.bhnfkyy.com/
我们发现,在jdk中有我们需要的jni.h文件。
现在我们有两种方式可以解决这个报错。
第一种是把#include 改为#include "jni.h",然后把jdk中的jni.h文件拷贝到当前目录下。
第二种是在编译时通过“-I加头文件路径”,让编译器找到jni.h文件。
我们使用第二种。
继续编译动态库。
root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall -I/usr/local/jdk/jdk1.8.0_211/include HelloWorld.c -o libHelloWorld.so
In file included from HelloWorld.c:1:0:
/usr/local/jdk/jdk1.8.0_211/include/jni.h:45:20: fatal error: jni_md.h: No such file or directory
#include "jni_md.h"
^
compilation terminated.
root@ubuntu:~/ken/jni#
报错找不到jni_md.h文件。如果查看jni.h文件的话,会发现里面有包含jni_md.h文件。
jni_md.h文件在:(使用grep命令,在jdk目录下搜索)
root@ubuntu:~/ken/jni# ls /usr/local/jdk/jdk1.8.0_211/include/linux/
jawt_md.h jni_md.h
root@ubuntu:~/ken/jni#
把该路径添加到-I参数,继续编译动态库。
root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall -I/usr/local/jdk/jdk1.8.0_211/include -I/usr/local/jdk/jdk1.8.0_211/include/linux HelloWorld.c -o libHelloWorld.so
root@ubuntu:~/ken/jni# ls
HelloWorld.c HelloWorld.class HelloWorld.h HelloWorld.java jni.h libHelloWorld.so
root@ubuntu:~/ken/jni#
成功编译出libHelloWorld.so动态库。
测试JNI程序
root@ubuntu:~/ken/jni# ls
HelloWorld.c HelloWorld.class HelloWorld.h HelloWorld.java jni.h libHelloWorld.so
root@ubuntu:~/ken/jni# java HelloWorld
Hello World!
root@ubuntu:~/ken/jni#
成功运行C代码中函数。
————————————————————————————————
上面只是简单的jni调用,了解jni的大致调用流程。
关于JNI还有很多需要了解的,比如参数类型、函数传参等。
—————————————————————————————————
需要强调的是,虽然jni和ndk经常一起使用。但是jni是jni,ndk是ndk,是两码事。
什么时候需要ndk呢?用到Android时,就需要ndk了。
上面编译动态库的过程也不是通过gcc编译了,而是使用ndk提供的ndk-build工具,编译出动态库,给apk调用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。