Android JNI helloworld程序編寫與編譯-圖文解說

 

這是一個經典的helloworld程序,此程序本身並沒有什麼功能,但是其意義在於拋磚引玉。瞭解了JNI的機理,對於那些習慣於C程序的人很重要,在處理底層的讀寫等操作就可以在UI層用java輕而易舉地實現,就
如同
C程序中調用一個系統調用那麼簡單,下面分步敘述。


一、創建最上層的java程序

  首先打開eclipse,創建一個java工程,並在工程中添加一個類,類名爲helloworld.java,如圖所示:

1.bmp

2011-5-22 19:35:19 上傳
下載附件 (221.97 KB)

打開java源碼helloworld.java,編寫代碼,實現c語言中的printf功能,代碼如下:

2.bmp

2011-5-22 19:38:04 上傳
下載附件 (642.01 KB)

Print()函數的聲明中,關鍵字native標明此方法是一個“本地”方法或者“原生”方法,即從c/c++庫中調用的方法。

Main()函數必須爲static,否則運行時會報錯,找不到main,原因不詳。

Static段中的loadLibrary提供了此程序運行時需要加載的c動態鏈接庫***.soprint()的實現就在此庫中。


二、
編譯helloworld.java

編譯helloworld.java的方法有兩種,一種是在shell中利用javac編譯,另一種在eclipse中,直接保存。

對於第一種方法,直接告訴javac編譯器需要編譯的文件即可,命令如下:


Javac helloworld.java

生成的helloworld.class就在$(shell pwd)下。

第二種方法,eclipse會在工程目錄下的bin目錄下生成helloworld.class



三、
生成JNI頭文件helloworld.h

利用javah命令生成。Javah的命令格式如下:

       javah –jni –classpath <classpath> <classfile>

例如我的helloworld.class文件是由eclipse生成的,因此其絕對路徑是:


/root/Project/jni/helloworld/bin/helloworld.class

我當前所在目錄爲/root/Project/jni/helloworld/

上面的命令就可以寫成:javah –jni –classpath bin helloworld

命令執行後再$(shell pwd)下生成一個文件:helloworld.h,其內容如下: 3.bmp

2011-5-22 19:42:38 上傳
下載附件 (1.1 MB)

在這個文件中提供了javac的接口


JNIEXPORT void JNICALL Java_helloworld_print(JNIEnv *, jobject);

另外,jni.h中定義了各種從javac的類型轉換,宏定義等。

接着我在工程根目錄下創建了一個目錄include,將生成的頭文件mvinclude目錄下。


四、
創建helloworld.c並編譯生成動態鏈接庫helloworld.so

首先編寫代碼如下(推薦在vim或者其他可視化編輯軟件中):

4.bmp

2011-5-22 19:45:42 上傳
下載附件 (435.81 KB)

    由圖中可見,此處就是最上層的helloworld.java代碼中的方法的實現,在此實現中沒有用到系統提供的兩個參數,但是此2個參數非常重要。第一個參數代表此共享庫運行的環境,即java虛擬機,在虛擬機中獎上層的java類型轉換爲C類型。第二個參數類似於C++中的this對象,C代碼要通過此函數來改變對象中某些變量的值。

接下來要做的就是將此C代碼編譯成共享鏈接庫文件,可以直接在shell裏完成,或者爲了便於管理,通過GNU make

    編譯時需要定位jni.h所在路徑,locate,結果如下:

5.bmp

2011-5-22 19:47:39 上傳
下載附件 (829.83 KB)

    由於我當前使用的ndk~/Project/android-ndk-r4b,並且我想讓程序運行在宿主機上,於是選擇第4條或者第6條,我選第6條,因此在gccflags裏應該添加此路徑。

    爲了方便起見,我在helloworld根目錄下創建一個makefile,採用遞歸調用Makefile,深入到各目錄中進行操作,對各子目錄下的Makefile統一管理:

6.bmp

2011-5-22 19:49:22 上傳
下載附件 (796.71 KB)

源文件所在目錄的Makefile如下:

7.bmp

2011-5-22 19:52:03 上傳
下載附件 (1.3 MB)

使用make命令在工程根目錄下編譯之後,在工程根目錄下的lib目錄中生產了helloworld.so的共享庫文件:

8.bmp

2011-5-22 19:54:47 上傳
下載附件 (107.05 KB)

五、
檢驗程序正確性

運行程序有兩個方法:shell中運行和eclipse中運行。

1.
shell
中運行

運行jni程序需要告訴java兩個參數,即classpath和共享庫的位置。

classpath可以通過設置環境變量:

export CLASSPATH=$CLASSPATH:/root/Project/workspace/jni/helloworld/bin/

而共享庫的位置在命令行中給出即可:


Java –Djava.library.path=’lib/’ helloworld

運行結果如下:

9.bmp

2011-5-22 19:55:51 上傳
下載附件 (124.69 KB)

2.
eclipse
中運行

需要爲java虛擬機設置共享庫路徑,打開run configurations,切換到第二個選項卡arguments,在虛擬機參數輸入框中輸入

-Djava.library.path=/root/Project/workspace/jni/helloworld/lib/

如圖所示:

10.bmp

2011-5-22 19:58:12 上傳
下載附件 (1.47 MB)

之後運行,運行結果如下:

11.bmp

2011-5-22 19:59:22 上傳
下載附件 (1.47 MB)


六、 補充說明

    我的工程根目錄:/root/Project/workspace/jni/helloworld/

    如果用eclipse編寫代碼並運行的話,需要爲eclipse安裝CDT插件,這樣纔可以支持c/c++。對於這個程序,如果不使用eclipse,可能反而更簡單一些。

    另外,環境變量的設置也很重要,要根據自己系統中jdk的路徑設置環境變量,設置方法可以上網搜索。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章