本文地址:http://www.cnblogs.com/wavky/p/JNI.html
當你找到並鬼使神差地打開這個博文的時候,我敢肯定你已經知道什么是JNI,基本概念就不粘貼了。
百度出來的JNI調用方法,前三頁幾乎毫不例外的都是幾年前的資料,告訴你如何設置一大堆莫名其妙的參數、如何通過命令行加工出dll並調用出來的,遺憾的是筆主打開的那堆帖子,多少都有些操作上的出入,再一個筆主對嘿嘿的命令行窗口無愛,並且,例外的帖子筆主還木有幸看到...
所以筆主狠心放下公司工作,拋棄領導的績效獎金,花了大半天時間研究JNI的調用方法(尤其不用寫命令那種),終於趕在下班的前三分鍾,順利完全通過eclipse界面調用出自定義的dll方法!那個激動就像中美建交或日本沉沒或蒼老師來我家做客那一瞬間那么振奮人心!!
簡單准備工作:
以下具體操作方法可以直接百度,答案幾乎是唯一可信的。
- 安裝JDK,配置系統環境變量
- 准備好一個帶CDT插件的Eclipse,筆主使用的是google的ADT Bundle,自帶了CDT,對應Eclipse 3.8.0版
- 下載一個MinGW(免費的C/C++等語言編譯器套件),筆主限於公司垃圾網絡,測試時使用mingw-offline-install-20120426 v4.6.2版,安裝時僅需勾選(在線安裝版下載數據量約50Mb):
- C Compiler
- C++ Compiler
- MinGW Developer Toolkit (Indudes MSYS Basic System)
配置MinGW的環境變量:
- 打開環境變量(系統變量),添加 MINGW_HOME 變量,變量值是剛才MinGW的安裝地址,如 D:\Program Files\MinGW
- 設置path變量,編輯path變量添加 %MINGW_HOME%\bin;%MINGW_HOME%\msys\1.0\bin;
- 添加 LIBRARY_PATH 變量,變量值 %MINGW_HOME%\lib
- 添加 C_INCLUDE_PATH 變量,變量值 %JAVA_HOME%\include;%JAVA_HOME%\include\win32;%MINGW_HOME%\include
- 添加 CPLUS_INCLUDE_PATH 變量,內容 %JAVA_HOME%\include;%JAVA_HOME%\include\win32;%MINGW_HOME%\lib\gcc\mingw32\4.5.2\include\c++
- Win7點擊確定后立即生效,若未生效請重啟系統(參考安裝JDK時配置操作)
第4、5步額外添加的%JAVA_HOME%\include;%JAVA_HOME%\include\win32;是為了讓eclipse在c/c++項目中自動引入這個目錄下的各種頭文件,例如 jni.h,也可在具體項目的屬性中以下位置進行指定:
調用JNI全過程:
創建一個普通java工程 Test,添加一個專門負責引入調用本地庫的類 Native,代碼如下:
1 public class Native { 2 // 聲明自定義本地庫方法接口 3 native public static void run(); 4 5 // 自動加載本地庫文件,如文件名全稱為 myCLib.dll 6 static{ 7 System.loadLibrary("myCLib"); 8 } 9 }
打開CMD....好吧,筆主承認標題黨了,整個博文僅此一處需要一句簡單的命令! CMD導航至項目文件夾下的 src 目錄,輸入 javah test.Native(需要使用包名.類名的完整限定名稱),生成本地方法接口頭文件 test_Native.h:
刷新eclipse的 Package Explorer 應該會變成這樣的目錄狀態,其中剛才剛才生成的 test_Native.h 文件代碼如下圖示(筆主搶閘創建了Test類,稍候用於調用Native類的本地方法):
創建一個新的 C 工程 MyC,期待編譯成dll的時候,選擇 Shared Library 下的模板:
在 MyC 工程內創建一個文件夾 src ,並將剛才 Test 項目中生成的 test_Native.h 頭文件拷貝(或剪切)到 MyC 工程的 src 文件夾下,Test 工程下的 test_Native.h 文件在后面的項目運行過程中將不再起任何作用,可刪:
* 打開 MyC 工程下的 test_Native.h ,若 #include <jni.h> 提示 Unresolved inclusion: <jni.h> 的錯誤警告(如下圖所示),則表明目前這個C項目沒有指定 jni.h 的頭文件位置,參考上文 配置MinGW的環境變量 的第4、5步進行配置:
** MyC 工程文件中接口函數代碼上提示的 Syntax error 可以暫時忽略,據聞是eclipse語法檢測的一個bug:
在 MyC 工程 src 文件夾中,新建一個C的實現類 NativeC.c ,引入接口頭文件 jni.h、test_Native.h ,並編寫接口函數 JNICALL Java_test_Native_run 的實現(函數接口直接從 test_Native.h 中完整拷貝過來,注意加上形參):
1 #include <jni.h> 2 #include "test_Native.h" 3 #include <stdio.h> 4 5 JNIEXPORT void JNICALL Java_test_Native_run 6 (JNIEnv *env, jclass clazz){ 7 puts("Hello JAVA, I am C."); 8 }
此時工程看起來應該是這樣子的:
由於使用 minGW 默認生成的 dll 函數簽名帶有 @ 分隔符,將導致后面JNI調用時產生 java.lang.UnsatisfiedLinkError: xoxoclass.xoxomethod() 錯誤,因此需要執行以下步驟消除多余的 @ 符號。
配置 MyC 工程: MyC 工程上右鍵菜單 Properties ,左側選擇 C/C++ Build -> Settings ,右側 Configuration 中顯示的為當前正在顯示的編譯模板,[ Active ] 表示通過 Project->Build Project 菜單編譯時使用的默認編譯版本, minGW 將根據這些模板的屬性設置,編譯生成多套版本的 dll 或 exe ,有潔癖的同學可通過最右側的 Manage Configurations... 按鈕增刪編譯模板:
為了對比效果,筆主決定增加一套新模板 ReleaseNoAt ,繼承默認的 Release 模板屬性參數,並設置為Active,決不是因為潔癖或什么奇怪的原因:
OK返回剛才的編譯模板屬性配置界面,在 ReleaseNoAt 模板下,Tool Settins 頁中的 MinGW C Linker -> Miscellaneous ,Linker flags 框中輸入 -Wl,--kill-at,點擊最下方的 Apply:
點擊 MinGW C Linker ,顯示的參數結果應該是這樣的:
如果之前建立的C工程不是使用 Shared Library 模板,並且默認編譯出的不是 dll 文件,可以在此選擇 Build Artifact 頁進行修改配置,Artifact Type 中選擇 Shared Library ,Artifact extension 中選擇 dll 即可,Output prefix 可指定輸出 dll 文件的命名前綴:
OK確定返回代碼編輯界面,在 MyC 工程上右鍵菜單,Build Configurations->Build All,生成所有模板的dll文件版本:
各版本 dll 如下圖所示,控制台中可以見到每個 dll 生成所用的命令參數(現在顯示的是 ReleaseNoAt 版本,即唯一配置了去掉@符號的模板):
為了驗證默認 Release 與 ReleaseNoAt 版本的區別,可用 dllexp 這個工具打開這兩個 dll 文件進行查看(具體方法不告訴你):
Release版(下面這個 @8 就是一切麻煩的罪魁禍首)
ReleaseNoAt版(干凈了)
回到eclipse,在 Test 工程中新建文件夾 dll (命名隨意),並將上面生成的 ReleaseNoAt版 libMyC.dll 拷貝到這個dll文件夾中,重命名為 myCLib.dll(因為上文 Native類 中通過 System.loadLibrary("myCLib"); 加載了這個名字的dll文件,當然你也可以修改代碼變成 System.loadLibrary("libMyC"); 來取代重命名),此后 MyC 工程將不再起任何作用,可刪:
配置 Test工程 屬性,指定工程的本地庫目錄,直接看圖:
Test工程 test包中新建 Test類 (由於時間關系,筆主已經事先偷偷違建了),在main方法中引用 Native類 的本地方法run():
1 public class Test { 2 3 public static void main(String[] args) { 4 Native.run(); 5 } 6 }
最后一步,運行起來...好吧,上面已經偷跑了,最終結果如上圖所示,Hello, I am Wavky.