天天看點

如何在Android下使用JNI 1.引言 2.環境配置 3.JNI實作 4.參考文章

我們知道,android系統的底層庫由c/c++編寫,上層android應用程式通過java虛拟機調用底層接口,銜接底層c/c++庫與java應用程式間的接口正是jni(javanative

interface)。本文描述了如何在ubuntu下配置androidjni的開發環境,以及如何編寫一個簡單的c函數庫和jni接口,并通過編寫java程式調用這些接口,最終運作在模拟器上的過程。

[html] view

plaincopy

$chmod a+x jdk-6u29-linux-i586.bin  

$jdk-6u29-linux-i586.bin  

(3)配置jdk環境變量

$sudo vim /etc/profile  

#javaevirenment  

exportjava_home=/usr/lib/java/jdk1.6.0_29  

exportjre_home=$java_home/jre  

exportclasspath=$java_home/lib:$jre_home/lib:$classpath  

exportpath=$java_home/bin:$jre_home/bin:$path  

儲存後退出編輯,并重新開機系統。

(4)驗證安裝

$java -version  

javaversion "1.6.0_29"  

java(tm)se runtime environment (build 1.6.0_29-b11)  

javahotspot(tm) server vm (build 20.4-b02, mixed mode)  

$javah  

用法:javah[選項]<類>  

其中[選項]包括:  

-help輸出此幫助消息并退出  

-classpath<路徑>用于裝入類的路徑  

-bootclasspath<路徑>用于裝入引導類的路徑  

-d<目錄>輸出目錄  

-o<檔案>輸出檔案(隻能使用-d或-o中的一個)  

-jni生成jni樣式的頭檔案(預設)  

-version輸出版本資訊  

-verbose啟用詳細輸出  

-force始終寫入輸出檔案  

使用全限定名稱指定<類>(例  

如,java.lang.object)。  

[plain] view

exportpath=~/software/android/android-sdk-linux/tools:$path  

 exportpath=~/software/android/android-sdk-linux/platform-tools:$path  

編輯完畢後退出,并重新開機生效。

$tar -xvf android-ndk-r6b-linux-x86.tar.bz2  

$sudo mv android-ndk-r6b /usr/local/ndk  

(3)設定ndk環境變量

exportpath=/usr/local/ndk:$path  

編輯完畢後儲存退出,并重新開機生效

$ cd/usr/local/ndk/samples/hello-jni/  

$ ndk-build  

gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver  

gdbsetup : libs/armeabi/gdb.setup  

install : libhello-jni.so => libs/armeabi/libhello-jni.so  

我們需要定義一個符合jni接口規範的c/c++接口,這個接口不用太複雜,例如輸出一個字元串。接下來,則需要把c/c++接口的代碼檔案編譯成共享庫(動态庫).so檔案,并放到模拟器的相關目錄下。最後,啟動java應用程式,就可以看到最終效果了。

(1)啟動eclipse,建立android工程

project:jnitest

package:org.tonny.jni

activity:jnitest

(2)編輯資源檔案

編輯res/values/strings.xml檔案如下:

<?xmlversionxmlversion="1.0"encoding="utf-8"?>  

<resources>  

<stringnamestringname="hello">helloworld, jnitestactivity!</string>  

<stringnamestringname="app_name">jnitest</string>  

<stringnamestringname="btn_show">show</string>  

</resources>  

編輯res/layout/main.xml檔案如下:

<linearlayoutxmlns:androidlinearlayoutxmlns:android="http://schemas.android.com/apk/res/android"  

android:layout_width="fill_parent"  

android:layout_height="fill_parent"  

android:orientation="vertical">  

<textview  

android:layout_height="wrap_content"  

android:text="@string/hello"/>  

<edittext  

android:id="@+id/ed_name"  

android:layout_width="match_parent"  

android:layout_gravity="center_horizontal"  

android:layout_marginleft="5dp"  

android:layout_marginright="5dp"/>  

<button  

android:id="@+id/btn_show"  

android:layout_width="109dp"  

android:text="@string/btn_show"/>  

</linearlayout>  

我們在主界面上添加了一個edittext控件和一個button控件。

(3)編輯jnitest.java檔案

[java] view

packageorg.tonny.jni;  

importandroid.app.activity;  

importandroid.os.bundle;  

importandroid.view.view;  

importandroid.widget.edittext;  

importandroid.widget.button;  

publicclassjnitestextendsactivity {  

static{  

system.loadlibrary("jnitest");  

}  

privatenativestring getreply();  

privateedittextedtname;  

privatebuttonbtnshow;  

stringreply;  

/**called when the activity is first created. */  

@override  

publicvoidoncreate(bundle savedinstancestate) {  

super.oncreate(savedinstancestate);  

setcontentview(r.layout.main);  

reply= getreply();  

edtname= (edittext)this.findviewbyid(r.id.ed_name);  

btnshow= (button)this.findviewbyid(r.id.btn_show);  

btnshow.setonclicklistener(newbutton.onclicklistener() {  

publicvoidonclick(view arg0) {  

edtname.settext(reply);  

});  

我們看這一段代碼:

static表示在系統第一次加載類的時候,先執行這一段代碼,在這裡表示加載動态庫libjnitest.so檔案。

再看這一段:

native表示這個方法由本地代碼定義,需要通過jni接口調用本地c/c++代碼。

這段代碼表示點選按鈕後,把native方法的傳回的字元串顯示到edittext控件。

(4)編譯工程,生成.class檔案。

在終端中,進入android工程所在的bin目錄

$cd ~/project/android/jnitest/bin  

我們用ls指令檢視,可以看到bin目錄下有個classes目錄,其目錄結構為classes/org/tonny/jni,即classes的子目錄結構是android工程的包名org.tonny.jni。請注意,下面我們準備執行javah指令的時候,必須進入到org/tonny/jni的上級目錄,即classes目錄,否則javah會提示找不到相關的java類。

下面繼續:

$cd classes  

$javah org.tonny.jni.jnitest  

$ls  

org org_tonny_jni_jnitest.h  

執行javahorg.tonny.jni.jnitest指令,在classes目錄下會生成org_tonny_jni_jnitest.h頭檔案。如果不進入到classes目錄下的話,也可以這樣:

$javah -classpath ~/project/android/jnitest/bin/classesorg.tonny.jni.jnitest  

-classpath 參數表示裝載類的目錄。

生成org_tonny_jni_jnitest.h頭檔案後,我們就可以編寫相應的函數代碼了。下面在android工程目錄下建立jni目錄,即~/project/android/jnitest/jni,把org_tonny_jni_jnitest.h頭檔案拷貝到jni目錄下,并在jni目錄下建立org_tonny_jni_jnitest.c檔案,編輯代碼如下:

[cpp] view

#include<jni.h>  

#include<string.h>  

#include"org_tonny_jni_jnitest.h"  

jniexportjstring jnicalljava_org_tonny_jni_jnitest_getreply  

(jnienv *env, jobject obj){  

return(*env)->newstringutf(env,(char*)"hello,jnitest");  

我們可以看到,該函數的實作相當簡單,傳回一個字元串為:"hello,jnitest"

在~/project/android/jnitest/jni目錄下建立android.mk檔案,android可以根據這個檔案的編譯參數編譯子產品。編輯android.mk檔案如下:

local_path:= $(call my-dir)  

include$(clear_vars)  

local_module := libjnitest  

local_src_files:= org_tonny_jni_jnitest.c  

include$(build_shared_library)  

local_module表示編譯的動态庫名稱

local_src_files 表示源代碼檔案

進入到jnitest的工程目錄,執行ndk-build指令即可生成libjnitest.so檔案。

$cd ~/project/android/jnitest/  

$ndk-build  

invalidattribute name:  

package  

install : libjnitest.so => libs/armeabi/libjnitest.so  

可以看到,在工程目錄的libs/armeabi目錄下生成了libjnitest.so檔案。

(1)首先,我們把android模拟器啟動起來。進入到emulator所在目錄,執行emulator指令:

$cd ~/software/android/android-sdk-linux/tools  

$./emulator @avd-2.3.3-v10 -partition-size 512  

avd-2.3.3-v10表示你的模拟器名稱,與在eclipse->avdmanager下的avdname對應,-partition-size表示模拟器的儲存設備容量。

(2)接下來,我們需要把libjnitest.so檔案拷貝到模拟器的/system/lib目錄下,執行以下指令:

$cd ~/project/android/jnitest/libs/armeabi/  

$adb remount  

$adb push libjnitest.so /system/lib  

80 kb/s (10084 bytes in 0.121s)  

當在終端上看到有80 kb/s (10084 bytes in 0.121s)傳輸速度等資訊的時候,說明拷貝成功。

(3)在終端上執行jnitest程式,這個我們可以在eclipse下,右鍵點選jnitest工程,runas->android

application,即可在模拟器上啟動程式,執行效果如下:

如何在Android下使用JNI 1.引言 2.環境配置 3.JNI實作 4.參考文章
如何在Android下使用JNI 1.引言 2.環境配置 3.JNI實作 4.參考文章
如何在Android下使用JNI 1.引言 2.環境配置 3.JNI實作 4.參考文章

在模拟器上點選【show】按鈕,即可看到hello,jnitest,而這個字元串正是我們在org_tonny_jni_jnitest.c代碼檔案中所定義的。

ok,現在大功告成!

androidjni開發入門之一

androidjni代碼示例講解