看了網上好多牛人寫的學習系列都是用HelloWorld作為開始,我們這里也用HelloWorld來開始我們的學習,首先我們來介紹下JNI吧。
JNI作為java代碼和C/C++的橋梁而存在的,為了讓java代碼更加接近原生代碼,大家都知道在linux中,C語言可以直接訪問硬件,但是java代碼想要直接操作硬件或者說是直接讀寫寄存器的話不行,所以需要jni來作為橋梁來訪問更底層的東西。
JIN使得JAVA代碼更加優越,但是用起來也不是那么容易的,特別是在規范方面,作為java虛擬機實現的一部分,jni是java應用程序調用原生代碼的途徑。下面這種圖顯示了JNI的角色扮演:

OK,知道了JNI的作用我們就開始我們的例子吧,我這里編譯jni是在ubunt下編譯的,eclipse是在windows下面的開發環境,在ubuntu下配置ndk開發環境請看我前面一篇文章,這里跳過環境配置,這里我們要實現的功能是:
功能:點擊一個按鈕,吐出來一個toast,toast中的字符串是在jni中傳進來的。
這樣就演示了如何在java中去調用jni,我這邊的jni是使用c語言編寫的,也可以使用C++,稍有一點區別,用C++編寫我比較喜歡在android BSP源碼中編譯。
下面首先是android.mk文件,其實就是linux中的makefile文件而已,這里就是說明了一些編譯方法以及生成模塊的名字。
~~~
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDE := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_MODULE := HelloWorld
LOCAL_SRC_FILES := \
HelloWorld.c
include $(BUILD_SHARED_LIBRARY)
~~~
Android.mk的編寫也是有規范的。
一個Android.mk file用來向編譯系統描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。編譯系統為你處理許多細節問題。
一個工程中的源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復雜的功能操作,因為 makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令。
makefile帶來的好處就是——“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。make是一個命令工具,是一個解釋makefile中指令的命令工具,一般來說,大多數的IDE都有這個命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成為了一種在工程方面的編譯方法。
Make工具最主要也是最基本的功能就是通過makefile文件來描述源程序之間的相互關系并自動維護編譯工作。而makefile 文件需要按照某種語法進行編寫,文件中需要說明如何編譯各個源文件并連接生成可執行文件,并要求定義源文件之間的依賴關系。makefile 文件是許多編譯器--包括 Windows NT 下的編譯器--維護編譯信息的常用方法,只是在集成開發環境中,用戶通過友好的界面修改 makefile 文件而已。
1、LOCAL_PATH := $(call my-dir)?
一個Android.mk file首先必須定義好LOCAL_PATH變量。它用于在開發樹中查找源文件。在這個例子中,宏函數’my-dir’, 由編譯系統提供,用于返回當前路徑(即包含Android.mk file文件的目錄)。
2、include $( CLEAR_VARS)
CLEAR_VARS 由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因為所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變量都是全局的。
3、LOCAL_MODULE := ?HcSyncml
LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包 含任何空格。注意編譯系統會自動產生合適的前綴和后綴,換句話說,一個被命名為'HcSyncml'的共享庫模塊,將會生成'libHcSyncml.so'文件。
4、LOCAL_C_INCLUDES :=$(LOCAL_PATH)/extra_inc$(LOCAL_PATH)/main_inc
LOCAL_C_INCLUDES 中加入所需要包含的頭文件路徑
5、LOCAL_SRC_FILES
LOCAL_SRC_FILES中加入源文件路徑(需要編譯的文件),多個文件用 ‘\’ 隔開
6、LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib –llog
表示允許打印Log
----------------------------------------------------------------------------------
下面是我們HelloWorld的jni代碼:
~~~
//
//Jay-----HelloWorld
//HelloWorld.c
#include <string.h>
#include <jni.h>
Jstring
Java_com_android_jni_HelloWorld_getString(JNIEnv *env,jobject jobj)
{
return (*env)->NewStringUTF(env,"HelloWorld! From C!");
}
~~~
很簡單吧,2個頭文件,大家一看就知道第二個頭文件,jni.h里面肯定定義了jni使用的一些庫函數,還有jni的一些模板。
JNI的函數名字也是要注意的一個地方,我們這邊是:Java_com_android_jni_HelloWorld_getString
Java+package name+class name+function name組成的
-----------------------------------------------------------------------------------
下面是java代碼:
~~~
// package name
package com.android.jni;
//use inport
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class HelloWorld extends Activity {
/**Called when the activity is first created. */
Context mContext = null;
Button bt = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setContentView(R.layout.main);
mContext = this;
bt = (Button)findViewById(R.id.button);
bt.setOnClickListener(new MyButtonListener());
}
class MyButtonListener implements OnClickListener{
public void onClick(View v) {
if(v.getId() == R.id.button ){
//調用原生函數得到字符串sre
String str=getString();
//吐出message
Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();
}
}
}
//聲明jni原生函數
public native String getString();
//載入原生庫
static {
System.loadLibrary("helloworld");
}
}
~~~
注釋在java代碼中都有,這邊都比較簡單,下面我們來運行模擬器。

點擊button,會出現HelloWorld! from C!
大功告成!
-------------------------------------------------------------------------------------
mail & msn: zhangjie201412@live.com
QQ: 417248058
-------------------------------------------------------------------------------------