您好,登錄后才能下訂單哦!
JNI是什么
JNI是java平臺的一個特性(與Android無關(guān))
英文參考文檔中的介紹如下:
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環(huán)境搭建
想要使用jni,需要搭建好jdk環(huán)境。
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文件,在該文件最后面,添加如下內(nèi)容:
#JDK
export PATH=/usr/local/jdk/jdk1.8.0_211/bin/:$PATH
然后使用 source ~/.bashrc命令更新環(huán)境變量。
判斷環(huán)境是否配置成功:
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環(huán)境搭建完成。
使用流程:
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文件。之后根據(jù)該.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文件,內(nèi)容如下:
/* 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 動態(tài)庫文件
接下來,把HelloWorld.c文件編譯成動態(tài)庫:libHelloWorld.so即可。
PS:
1、此處編譯出的動態(tài)庫的名稱,是HelloWorld.java文件中定義了的。
System.loadLibrary(“HelloWorld”);
上面這條程序的作用就是加載libHelloWorld.so庫文件。
2、在HelloWorld.h文件中函數(shù)聲明是:
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
在HelloWorld.c文件中函數(shù)定義為:
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
如果函數(shù)參數(shù)中沒有定義*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環(huán)境下測試的。如果是windwows的話,編譯出.dll文件。
接下來,編譯出動態(tài)庫:
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#
如上,報錯顯示找不到動態(tài)庫。
此時就和之前的jdk環(huán)境搭建有關(guān)系了。
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/
我們發(fā)現(xiàn),在jdk中有我們需要的jni.h文件。
現(xiàn)在我們有兩種方式可以解決這個報錯。
第一種是把#include 改為#include "jni.h",然后把jdk中的jni.h文件拷貝到當前目錄下。
第二種是在編譯時通過“-I加頭文件路徑”,讓編譯器找到jni.h文件。
我們使用第二種。
繼續(xù)編譯動態(tài)庫。
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文件的話,會發(fā)現(xiàn)里面有包含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參數(shù),繼續(xù)編譯動態(tà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動態(tài)庫。
測試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代碼中函數(shù)。
————————————————————————————————
上面只是簡單的jni調(diào)用,了解jni的大致調(diào)用流程。
關(guān)于JNI還有很多需要了解的,比如參數(shù)類型、函數(shù)傳參等。
—————————————————————————————————
需要強調(diào)的是,雖然jni和ndk經(jīng)常一起使用。但是jni是jni,ndk是ndk,是兩碼事。
什么時候需要ndk呢?用到Android時,就需要ndk了。
上面編譯動態(tài)庫的過程也不是通過gcc編譯了,而是使用ndk提供的ndk-build工具,編譯出動態(tài)庫,給apk調(diào)用。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。