首先我們要知道Java是如何呼叫c/c++的
什麼是JNI
java native interface(java本地介面)
ABI: application binary interface (應用程式二進位制介面)
簡介
JNI是Java語言提供的Java和C/C++相互溝通的機制,Java可以通過JNI呼叫本地的C/C++程式碼,本地的C/C++的程式碼也可以呼叫java程式碼。JNI 是本地程式設計介面,Java和C/C++互相通過的介面。Java通過C/C++使用本地的程式碼的一個關鍵性原因在於C/C++程式碼的高效性。
NDK是一系列工具的集合。它提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,並能自動將so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。它整合了交叉編譯器,並提供了相應的mk檔案隔離CPU、平臺、ABI等差異,開發人員只需要簡單修改mk檔案(指出“哪些檔案需要編譯”、“編譯特性要求”等),就可以建立出so。它可以自動地將so和Java應用一起打包,極大地減輕了開發人員的打包工作。
#為什麼要使用JNI
- 複用很多優秀的c/c++程式碼
- ffmpeg 多媒體播放器
- opencv 圖形識別引擎
- 7-zip 壓縮
- opencore 視訊播放
- 效率問題
- java程式碼跨平臺,不直接操作硬體,虛擬機器解釋執行。垃圾回收機制。
- art 在安裝apk應用程式的時候,把apk裡面的dex翻譯成機器碼(apk的體積會變大)
- c程式碼直接操作硬體,程式設計師可以手工的釋放記憶體
- 應用場景問題
- c程式碼可以直接操作硬體。
- java程式碼只能操作虛擬機器(一次編譯到處執行)
- 智慧家居操作硬體
- 車載電腦(obd: onboard debug system)
- 特殊業務邏輯
- c程式碼反編譯困難,除錯困難。
- java程式碼反編譯容易,很容易看懂。
#怎麼使用JNI
- 看懂c程式碼( 有c語言基礎)
- 懂流程 (熟悉jni的規範)
- 熟練(NDK 工具 native develop kits)
開發工具
dev-cpp.exe
- 輕量級開發工具
- 編譯器gcc c99標準
Java通過JNI機制和C/C++溝通的具體步驟
- 1、編寫包含native本地方法的java類
- 2、通過javah工具生成C/C++語言的標頭檔案
- 3、使用C/C++語言實現標頭檔案
- 4、使用交叉編譯工具對C/C++原生程式碼進行編譯
- 5、最後通過連結生成*.so可執行的C/C++庫
實際執行Java程式碼去和本地的C/C++程式碼互相溝通
JNI中的JavaVM與JNIEnv物件
在標準的Java平臺下,每個Process裡可以產生很多JavaVM物件,每個JavaVM物件都有一個與之對應的JavaVM物件,但是在Android平臺上,每個Process只能產生一個DalvikVM物件,也就是說在一個Android的程式中是通過有且只有一個虛擬器物件來服務所有Java和C++程式碼的。
- 1、JNIEnv 內部包含一個Pointer,Pointer指向Dalvik的JavaVM物件的Fanction Table,JNIEnv 關於程式執行環境的眾多函式正是來源於Dalvik虛擬機器
- 2、Android中每當一個Java執行緒第一次要呼叫本地C/C++程式碼時,Dalvik虛擬機器例項會為該Java執行緒產生一個JNIEnv *指標
- 3、Java每條執行緒在和C/C++互相呼叫時,JNIEnv是相互獨立的,互不干擾
4、每本地的C/C++程式碼想獲得當前執行緒所要使用的JNIEnv時,可以使用Dalvik VM物件的Java VM jvm->getEnv()方法,該方法即會返回當前執行緒所在的JNIEnv*
Java、Dalvik VM、C/C++的執行機制與流程 在Android的NDK中,Java、C/C++、Dalvik VM關係如下:
- 1、java的dex位元組碼和C/C++的*.so同時執行DalvikVM之內,共同使用一個程式空間。每次使用jni呼叫c/c++開闢一個執行緒去處理
- 2、java和C/C++可以相互呼叫,呼叫的關鍵是DalvikVM
- 3、一般而言,比較經典的模式是Java通過JNI的C組建和C++相互溝通,一般業務處理放在C/C++中
- 4、C++程式碼處於核心控制地位更具價值
當java需要C/C++程式碼時,在DalvikVM虛擬機器中載入動態連結庫時,會先呼叫JNI_Onload()函式,此時就會把javaVM物件的指標儲存於C層JNI組建的全域性環境中,在JAVA層呼叫C層的本地庫函式時,呼叫C本地函式執行緒必然通過Dalvik VM來呼叫C本地函式,測試Dalvik虛擬機器會為本地的C組建例項化一個JNIEnv指標,該指標指向Dalvik虛擬機器的具體函式列表,當JNI的C元件呼叫java層方法和屬性時,需要通過JNIEnv指標來進行呼叫。
當C++元件主動呼叫Java層方法時,需要通過JNI的C元件把JNIEnv指標傳遞給C++元件,此後,c++元件即可通過JNIEnv指標來掌控Java層程式碼。
NDK和jni的區別
對於JNI和NDK很多Android開發初學者沒有搞明白這個問題:
- JNI是Java呼叫Native機制,是Java語言自己的特性全稱為Java Native Interface
- 類似的還有微軟.Net Framework上的p/invoke,可以讓C#或Visual Basic.NET可以呼叫C/C++的API,所以說JNI和Android沒有關係
- 在PC上開發Java的應用,如果執行在Windows平臺使用JNI是是經常的,比如說讀寫Windows的登錄檔。- 而NDK是Google公司推出的幫助Android開發者通過C/C++本地語言編寫應用的開發包,包含了C/C++的標頭檔案、庫檔案、說明文件和示例程式碼
- 我們可以理解為Windows Platform SDK一樣,是純C/C++編寫的,但是Android並不支援純C/C++編寫的應用
同時NDK提供的庫和函式功能很有限,僅僅處理些演算法效率敏感的問題
相信自己,沒有做不到的,只有想不到的
如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809
微信公眾號:終端研發部