Android NDK使用分析

Android NDK使用分析:

在Android應用程序開發中,對於一些對性能安全要求較高的模塊開發中,我們一般會使用C/C++代碼來實現,或者引用一些已經實現好的C/C++庫時,都需要使用JNI機制。正如上面的介紹是比較常用的,同樣可以實現編寫基於JNI機制訪問C/C++庫文件。

Android NDK是谷歌公司提供的開發工具集,我們可以使用它快捷得開發基於JNI機制的程序。它的幾個重要的功能如下:

A、提供將C/C++源代碼編譯成本地庫文件(編譯器、連接器等)

B、提供將編譯好的本地庫文件插入到Android的包文件(.apk)

C、提供NDK開發相關的文檔、實例及規范等

註意:

谷歌是不建議開發者使用NDK開發Android本地應用程序的,當然,這樣做是可以實現的,因為Android系統的主要應用是運行在dalvik虛擬機上的Java程序,推薦多開發運行在dalvik上的程序。

NDK的功能:

如上圖所示,Android ndk先編譯瞭C/C++本地代碼,並生成本地庫文件,然後將其插入到Android應用程序的包當中,但調用JNI的編譯本地代碼的工作還需要我們來做的。vcD4KPHA+TkRLsLLXsKO6PC9wPgo8cD7U2rnIuOi52c34yc/PwtTY1+7QwrXETkRLsPyjrLKiveLRubW91ri2qLXExL/CvM/Co6zEx8O01eK49sS/wry+zdf3zqq7t76zseTBv7XEw/vX1qOsvLROREtfSE9NRaOsyLu689Tau7e+s7Hkwb+1xHBhdGjW0MztvNO4w05ES19IT01Fu7e+s7Hkwb+8tL/JoaM8L3A+CjxwPkN5Z3dpbrCy17CjujwvcD4KPHA+1NrJz8Pmo6zO0sPH0tG+rbCy17CyorCy17DBy0N5Z3dpbsHLo6zU2tXiwO+88rWlvenJ3M/Cy/u1xNf308Oho0N5Z3dpbtb30qrKx9PDwLS0psDtsrvNrMa9zKi85LXE16q7r7mk1/ejrMD9yOdBbmRyb2lkyse7+dPaTGludXi1xL/yvNy8r6OstvjO0sPHs6PKudPDtcTPtc2zyLTKx3dpbmRvd3PPtc2zo6zL+dLUyrnTw8v8wLS9q7/izsS8/rTTd2luZG93c9eqzqq7+dPaTGludXjPtc2ztcSho7WxyLujrMjnufvKudPDtcTPtc2zysdMaW51eLXEu7Ag1PLO3tDo1eK49rK91ujBy6GjPC9wPgo8cD68yMi71NrV4sDvvenJ3MHLy/yjrM7ev8nWw9LJu+HTw7W9y/y1xKGju9i1vcnPw+ZOREu7t76ztcTF5NbDo6zU9cO00fnR6daku7e+s7Hkwb/Kx7fxxeTWw7PJuabEx6O/tPCwuL7NysfKudPD1eK49kN5Z3dpbrmkvt+ho87Sw8e08r+qy/yjrNTawO/D5srkyOtuZGstYnVpbGSjrMjnufvDu9PQsai07bb4ysez9s/W1eK49r3hufu1xLuwo6zU8su1w/e7t76zseTBv8Xk1sOzybmmo7o8L3A+CjxwPiA8aW1nIHNyYz0=”/uploadfile/Collfiles/20140310/2014031009170267.jpg” alt=”\”>

哦,這裡的錯誤是因為沒設定項目的路徑,這裡不用理會即可。

NDK的使用步驟:

實際上,NDK的使用流程與之前介紹的《Android本地接口JNI使用分析》使用流程及內容很多都很相似,在這裡,我隻介紹與之前不同的一些東西,下面即為NDK的開發流程:

1、創建Java本地方法類

2、編譯Java本地方法生成C/C++頭文件

3、編寫實現上面的C/C++實現文件

4、編譯生成動態運行庫(.so)

5、運行應用程序

下面,根據上面的流程來介紹下NDK的使用及註意事項。我的項目目錄:

運行的效果如:

每點擊按鈕打印LOG日志。

創建Java本地方法:

創建Java本地方法與之前文章是相同的,隻不過這裡的LOG內容為”Hello Ndk!”而已,代碼如下:

public class VerifyNdkJniMethod {

static {

System.loadLibrary(“hello_ndk”);

}

public static native String helloNdk();

}

編譯Java本地方法:

和之前的文章內容相同,都是使用Javah命令來編譯生成的class文件,從而生成對應的C/C++頭文件,我的頭文件:

/* DO NOT EDIT THIS FILE – it is machine generated */

#include

/* Header for class com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod */

#ifndef _Included_com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

#define _Included_com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

#ifdef __cplusplus

extern “C” {

#endif

/*

* Class: com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

* Method: helloNdk

* Signature: ()Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_com_demo_verifyndk_1jni_ndk_VerifyNdkJniMethod_helloNdk

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

同樣的,與之前的頭文件編寫方式相同,我的實現文件如下:

#include

#include “VerifyNdkJniMethod.h”

JNIEXPORT jstring JNICALL Java_com_demo_verifyndk_1jni_ndk_VerifyNdkJniMethod_helloNdk

(JNIEnv *env, jclass obj)

{

return (*env)->NewStringUTF(env,”Hello Ndk!”);

}

編譯生成動態庫文件(.so):

在這裡,與我們之前介紹的略有不同,我們任然需要編寫Android.mk文件,我的mk文件如下(在文章的最下面會介紹下mk文件):

#指定源文件的位置

LOCAL_PATH := $(call my-dir)

#初始化與Make相關的環境變量

include $(CLEAR_VARS)

#庫編譯相關信息 包括庫名稱、源碼等

LOCAL_MODULE := hello_ndk

LOCAL_SRC_FILES := VerifyNdkJniMethod.c

#生成共享庫

include $(BUILD_SHARED_LIBRARY)

同樣需要將頭文件和實現文件及mk文件放在一起,隻不過這裡我們必須在項目的根目錄下新建一個jni目錄,cd到這個目錄下,使用ndk-build或是$NDK/ndk-build來編譯生成動態庫文件。這與之前有些不同,之前我們使用的是$NDK/ndk-build來編譯,是因為之前我們沒有通過NDK的方式來實現,而是借助工具Cygwin來實現生成共享庫文件的(這個是成立的);而現在,我們配置瞭NDK的環境變量可以使用$NDK/ndk-build或是ndk-build都可以進行編譯生成,不同的是使用NDK及進行編譯的話,我們必須cd到項目根目錄下的jni下,上面的編譯命令才會生效。原因是這樣的,使用NDK編譯的時候,NDK自身帶有編譯器系統,在編譯的時候,編譯系統會在當前的目錄下查找AndroidManifest.xml文件,若文件存在,則將當前的目錄看做為Android工程目錄。然後再轉到jni目錄下,根據Android.mk進行NDK編譯。

運行應用程序:

這個過程與之前的文章《Android本地接口JNI使用分析》基本相同,我的代碼如下:

public class VerifyNdkJniActivity extends Activity {

private static String TAG = “VerifyNdkJniActivity”;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_verify_ndk_jni);

}

public void helloNdk(View v) {

String result = VerifyNdkJniMethod.helloNdk();

log(result);

}

private void log(String log) {

Log.d(TAG, log);

}

}

Android.mk文件說明:

實際上,Android.mk文件的幫助文件在/docs/ANDROID_MK.html中(不過是英文的),下面就介紹下吧!

LOCAL_PATH := $(param…):

這個變量是用來在開發樹中查找源文件,必須在mk文件的最開始處定義,一般情況下,使用下面的這種的編寫格式:

LOCAL_PATH := $(call my-dir)

其中的my-dir為一個宏函數,$(call my-dir)就是用來返回一個宏函數的值,一般Android.mk文件與源文件在同一個目錄下。

Include $(CLEAR_VARS):

用來初始化mk文件中LOCAL_XXX的變量,但是上面的LOCAL_PATH除外,因為Android系統會將LOCAL_XXX的變量當作全局變量,所以會先對其進行初始化。

LOCAL_MODULE := XXX:

用來標記在mk文件中描述的每一個模塊,也就是要生成的庫的名稱。這個名稱必須唯一並且不能含有空格,編譯系統會自動產生適當的前綴和後綴,比如:libhello_jni.so文件。

LOCAL_SRC_FILES := XXX.c/.cpp:

用來將包含將要被編譯進打包模塊的各個資源文件。同時,這些源文件所在的位置為LOCAL_PATH所指定的目錄。

Include $(BUILD_SHARED_LIBRARY):

用來使用LOCAL_PATH、LOCAL_SRC_FILES等的變量值,創建名稱為lib$(LOCAL_MODULE).so的庫文件。

到這裡,關於NDK的一些基本的東西介紹完瞭,如果想要更靈活的使用NDK,那麼可以參看NDK中自帶的simples,仔細研究學習,其位置在: \samples\

/**

* 歡迎加入技術群:179914858

* 如果有任何問題請在評論中進行討論學習

*/

發佈留言