一、前言
Android NDK將用於在Androud平臺上的C++開發;Android NDK是SDK的相關工具集,用來擴展Androud SDK的功能,從而使開發人員能夠使用機器代碼生成的編程語言(如C、C++和彙編語言)實現一些對代碼性能要求比較高的模塊並將這些模塊嵌入到Adroud應用程序中;
從今天起,讓我們開啓Androud NDK的學習之旅!
二、知識點概述
本片我們將從以下幾點初步認識、創建Android NDK:
1、Androud NDK的組件
2、Android NDK 的結構
3、Android NDK項目結構
4、Android Jni項目關聯頭文件
5、創建一個Android Jni項目
6、在Eclipse中配置javah、javap
7、javap使用演示
三、知識點詳解
通過以下4點知識點學習後,你就會快速地在Eclipse中搭建Android NDK開發環境了;
(1)android NDK的組件
Android NDK 不是一個單獨的工具,它是一個包含API、交叉編譯器、鏈接程序、調試器、構建工具、文檔和實例應用程序的綜合工具集。
Android NDK的主要組件:
1、ARM、x86和MIPS交叉編譯器: 我們可以使我們的項目支持一或多個交叉編譯器
2、構建系統: 是開發人員能夠用很短的構建文檔來描述原生的Androud應用程序;
3、Java原生接口頭文件:比如 jni.h
4、C庫
5、MATH庫
6、POSIX線程
7、最小的C++庫
8、ZLib壓縮庫
9、動態鏈接庫
10、Android日誌庫
11、Android像素緩衝區庫
12、Android原生應用APIs
13、OpenGL ES 3D圖形庫
14、OpenSL ES 原生音頻庫
15、OpenMAX AL 最小支持
(2)Android NDK 的結構
android NDK 結構如圖:
- ndk-build : 啓動Android的構建系統,該Shell腳本是Android NDK構建系統的起始點,一般在項目中僅僅執行這一個命令就可以編譯出對應的動態鏈接庫了。
- ndk-gdb:該shell腳本允許用GUN調試器調試Native代碼;
- ndk-stack:該shell腳本可以幫助分析原生組件崩潰時堆棧追蹤;
- build:包含Android構建系統的所有模塊;最重要的在build/core目錄中;後面我們會分析它們在構建系統中的作用;
- platforms:包含了支持不同Android目標版本的頭文件和庫文件;Android構建系統會根據具體的Android版本自動引用這些文檔;
- samples: Android NDK示例應用程序;
- sources:可供開發人員導入到現有的Android NDK項目的一些共享模塊;
- toochains:該目錄包含目前NDK所支持的不同平臺下的交叉編譯器——ARM、x86、MIPS,其中比較常見的是ARM和x86。構建系統會根據具體的配置選擇不同的交叉編譯器。
(3)Android NDK項目結構
以HelloNDK爲例介紹Android NDK項目結構:
我們會發現三個目錄:
- jni:該目錄包含原生組件的源代碼以及描述原生組件構建方法的Andoid.mk構建文件。Android NDK構建系統將該目錄作爲NDK項目目錄並希望在項目根目錄中找到它;
- libs :在Android NDK構建系統的構建過程中創建該目錄。它包含指定的目標機體系結構的獨立子目錄,例如ARM的armeabi。在打包過程中該目錄將被包含在APK文件中。
- obj:這是一箇中間目錄,編譯源代碼後所產生的目標文件都保存在該目錄下。開發人員最好不要訪問該目錄。
(4)Android Jni項目關聯頭文件
剛接觸到NDK時我們可能會碰到:
1、當我們創建一個Jni項目或者引入一個Jni項目後;當我們點擊jni目錄,查看C/C++代碼後會出現錯誤的提示!但我們發現代碼明明沒有錯誤,怎麼辦呢?
2、寫代碼方法時完全沒有提示!
效果如圖所示:
這是因爲我們沒有關聯頭文件;這就用到了我們上面講到的Androud NDK的結構platforms了;
步驟:
-
右擊項目–>propertise
-
C/C++ General -->Paths and Symbols
-
Add -->File system --> D:\android-ndk-r9d\platforms\android-18\arch-arm\usr\include(根據你的NDK路徑進行選擇,也可以選擇x86或mips路徑中usr\include,都可以)
-
點擊OK,這時我們再返回到jni目錄中的C/C++代碼中就正常了,而且類方法還有提示!
(5)創建一個Android Jni項目
創建一個Android Jni項目:HelloJni
步驟:
1、配置NDK路徑:
2、新建一個Android Application Project
3、右擊項目–> add Tools --> Add Native Support,給將要創建的.so文件起一個名字:
點擊Apply,OK;
4、然後在我們的HelloJni項目中多了3個目錄:jni、libs、obj;
5、修改文件
6、在Activity中 添加本地方法:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void getString(View view){
Toast.makeText(this, getStringFromNative(), Toast.LENGTH_LONG).show();
}
public native String getStringFromNative();
}
7、打開命令行界面,進入項目HelloJni/src目錄;輸入:javah com.example.hellojni.MainActivity
可以看到:
文件內容爲:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_hellojni_MainActivity */
#ifndef _Included_com_example_hellojni_MainActivity
#define _Included_com_example_hellojni_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_hellojni_MainActivity
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
8、這時候我們開始編寫C代碼了,編寫之前先按照**(4)Android Jni項目關聯頭文件**關聯下頭文件,然後編輯HelloJni.c源文件:
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_getStringFromNative
(JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env,"HelloJni");
}
9、最後一步在Acrivity中加入:
static {
System.loadLibrary("HelloJni");
}
此刻,把應用部署到手機上;點擊按鈕後會收到HelloJni吐司;成功了;
我們會發現在libs中多了一個libHelloJni.so文件,它就是我麼編譯後的C動態鏈接庫文件;我們以後程序的運行就靠它了,jni下的源代碼已經用不上了,我們可以刪除掉!項目依舊正常運行;
(6)在Eclipse中配置javah、javap
javah我們在上面已經知道是做什麼的了,至於javap我們在後面的文章中會介紹,它也是我們常用的命令;
我們可能會發現在使用Javah的時候很麻煩!又是通過命令行界面進入到 原項目src目錄。。。感覺自己開發的過程慢了一拍!現在我們就給大家介紹如何在Eclipse中如何配置Javah、javap;我們只需選中這個類,點擊javah,javap;就可以自動生成我們想要的文件;
javah配置:
1、如圖:
2、選中 Program 右鍵 --> 新建:
3、在refresh 中選擇 the project containing selected resource
4、Common 選擇如下:
點解Apply , Run就OK了; javah就配置好了;
javap配置:
1、它與javah的配置前兩部一樣,不同的是在界面中輸入的值不同:
2、點擊Apply 、Run; javap的配置就完成了!
###(7)javap使用演示
當我們的javap、javah配置好之後,會在工具欄中發現它們:
javah使用:
1、選中包含本地方法的類(在我們的HelloJni項目中是MainActivity):
2、點擊javah:
然後會生成如下文件:
頭文件的內容爲:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_hellojni_MainActivity */
#ifndef _Included_com_example_hellojni_MainActivity
#define _Included_com_example_hellojni_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_example_hellojni_MainActivity_MODE_PRIVATE
#define com_example_hellojni_MainActivity_MODE_PRIVATE 0L
#undef com_example_hellojni_MainActivity_MODE_WORLD_READABLE
#define com_example_hellojni_MainActivity_MODE_WORLD_READABLE 1L
#undef com_example_hellojni_MainActivity_MODE_WORLD_WRITEABLE
#define com_example_hellojni_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef com_example_hellojni_MainActivity_MODE_APPEND
#define com_example_hellojni_MainActivity_MODE_APPEND 32768L
#undef com_example_hellojni_MainActivity_MODE_MULTI_PROCESS
#define com_example_hellojni_MainActivity_MODE_MULTI_PROCESS 4L
#undef com_example_hellojni_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define com_example_hellojni_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef com_example_hellojni_MainActivity_BIND_AUTO_CREATE
#define com_example_hellojni_MainActivity_BIND_AUTO_CREATE 1L
#undef com_example_hellojni_MainActivity_BIND_DEBUG_UNBIND
#define com_example_hellojni_MainActivity_BIND_DEBUG_UNBIND 2L
#undef com_example_hellojni_MainActivity_BIND_NOT_FOREGROUND
#define com_example_hellojni_MainActivity_BIND_NOT_FOREGROUND 4L
#undef com_example_hellojni_MainActivity_BIND_ABOVE_CLIENT
#define com_example_hellojni_MainActivity_BIND_ABOVE_CLIENT 8L
#undef com_example_hellojni_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#define com_example_hellojni_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef com_example_hellojni_MainActivity_BIND_WAIVE_PRIORITY
#define com_example_hellojni_MainActivity_BIND_WAIVE_PRIORITY 32L
#undef com_example_hellojni_MainActivity_BIND_IMPORTANT
#define com_example_hellojni_MainActivity_BIND_IMPORTANT 64L
#undef com_example_hellojni_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define com_example_hellojni_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef com_example_hellojni_MainActivity_CONTEXT_INCLUDE_CODE
#define com_example_hellojni_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undef com_example_hellojni_MainActivity_CONTEXT_IGNORE_SECURITY
#define com_example_hellojni_MainActivity_CONTEXT_IGNORE_SECURITY 2L
#undef com_example_hellojni_MainActivity_CONTEXT_RESTRICTED
#define com_example_hellojni_MainActivity_CONTEXT_RESTRICTED 4L
#undef com_example_hellojni_MainActivity_RESULT_CANCELED
#define com_example_hellojni_MainActivity_RESULT_CANCELED 0L
#undef com_example_hellojni_MainActivity_RESULT_OK
#define com_example_hellojni_MainActivity_RESULT_OK -1L
#undef com_example_hellojni_MainActivity_RESULT_FIRST_USER
#define com_example_hellojni_MainActivity_RESULT_FIRST_USER 1L
#undef com_example_hellojni_MainActivity_DEFAULT_KEYS_DISABLE
#define com_example_hellojni_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undef com_example_hellojni_MainActivity_DEFAULT_KEYS_DIALER
#define com_example_hellojni_MainActivity_DEFAULT_KEYS_DIALER 1L
#undef com_example_hellojni_MainActivity_DEFAULT_KEYS_SHORTCUT
#define com_example_hellojni_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef com_example_hellojni_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define com_example_hellojni_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef com_example_hellojni_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define com_example_hellojni_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
* Class: com_example_hellojni_MainActivity
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Java_com_example_hellojni_MainActivity_getStringFromNative
(JNIEnv *, jobject);就是我們需要的內容;
四、總結
通過1、Androud NDK的組件 2、Android NDK 的結構 3、Android NDK項目結構 4、Android Jni項目關聯頭文件 5、創建一個Android Jni項目 6、在Eclipse中配置javah、javap 7、javap使用演示的學習,我們可以快速搭建一個NDK開發環境;下面就是怎樣寫C/C++代碼,Java代碼怎樣轉化C++代碼?這是我後面要分享的內容;