編輯2016年7月26日——增加了下載網址,修改了一些錯誤。
摸索了一周,走了很多彎路,磕磕絆絆,總算是弄好了NDK的開發環境,在這里總結一下吧。
一、Android NDK開發環境
首先下載安裝JRE、JDK,不必多說。然后下載NDK包,建議下載r11版本后的,自帶C/C++的編譯器, 不需要使用外部編譯器的麻煩了,而且同時支持32位和64位的ARM處理器。下載完NDK包后,解壓縮即可,需要之后關聯到Eclipse。然后下載ADT Bundle,即安卓開發工具套裝,里面集成好的Eclipse的安卓開發環境,但是,里面的版本可能較低而且沒有集成NDK功能,下載新版的ADT包,進行更新。
開發環境推薦下載網站:http://tools.android-studio.org/index.php
關於SDK更新,由於長城防火牆的原因,導致無法更新SDK。可以進行如下設置,進行SDK更新。
HTTP Proxy Server 設置為 mirrors.neusoft.edu.cn
HTTP Proxy Port 設置為 80
其他設置如下圖
設置好了之后進行Reload,然后選擇需要的工具包進行安裝。
之后是ADT更新,下載最新的ADT包,然后在Eclipse的Help->Install New Software中進行離線更新,點擊add彈出窗口,Name可以任意填寫,location處單擊Aarchive選擇本地已經下載的adt插件。
完成更新后,在Preferences中的Android這一欄里出現了NDK,選擇后設置NDK的路徑即可,路徑設置到包含ndk-build.cmd文件的目錄下,一般是ndk的根目錄,或者根目錄的build文件夾下。
以上所有開發工具配置完成后,就可以進行期待的NDK開發了~~
二、運行NDK官方例子hello-jni
首先導入hello-jni到工作空間中,File->Import,選擇Existing Android Code Into Workspace,點擊next,然后在Root Directory中瀏覽找到NDK文件夾下的samples下的hello-jni選中,然后如下圖勾選,完成工程導入,整個工程就被復制到工作空間中了。
導入后,可以在工程瀏覽窗口中看到工程結構,如下圖
右鍵這個工程,Android Tools->Add Native Support,進入后直接點完成即可。
這樣,我們就可以編譯運行了。
三、編寫自己的第一個一個NDK的應用
我們將編寫一個NDK應用,其功能是調用本地方法getNum(),獲取一個整數,然后顯示出來。
首先新建工程,取名為MyFirstJni,我這里選擇的最低API 16,其他的是API 19,其余默認設置,建立工程。
之后在工程的MainActivity中,編寫代碼如下:
package com.pplxlee.myfirstjni; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = new TextView(this); tv.setText(String.valueOf(getNum())); // 通過getNum方法得到int型數字,轉換為Sting給tv setContentView(tv); // 顯示tv的內容 } private native int getNum(); // 聲明Native方法getNum static { System.loadLibrary("MyFirstJni"); // 載入動態鏈接庫libMyFirstJni.so } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
然后右鍵工程,Android Tools->Add Native Support,進入后注意框里面的名字要和MainActivity的程序中加載的動態鏈接庫的名字相同,這里輸入"MyFirstJni"直接點完成即可。
我們會看到產生了新的文件夾jni,並生成了文件MyFirstJni.cpp和Android.mk。MyFirstJni.cpp用於編寫C++代碼,去定義getNum()方法的具體實現過程,而Android.mk則描述了編譯C++成庫的方式。
對比官方jni的例子,我們可以發現,我們還少了一個Application.mk,我們可以在我們工程里也加入這樣的一個文件,文件內容為APP_ABI := all,這個文件使得編譯器生成其支持的全平台的so文件,如果針對某一平台開發,可以具體設置。
由於編寫jni的C++代碼有自己的規范,為了方便,可以通過jdk的javah工具,來自動生成頭文件,方法如下。
打開外部工具配置,新建工具javah4android,做如下設置(注意:Android JNI的生成配置和Java JNI的生成配置不同,無法混用):
Location:
瀏覽jdk\bin目錄,找到javah.exe
WorKing Directory:
${project_loc}
Arguments:
-v -classpath "${project_loc}/src"
-d "${project_loc}/jni"
-jni ${java_type_name}
設置完后選擇應用。然后,在光標在MainActivity.java內的情況下,運行此工具。會看到在jni文件夾內生成了com_pplxlee_myfirstjni_MainActivity.h的文件。
打開后可以看到代碼如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_pplxlee_myfirstjni_MainActivity */ #ifndef _Included_com_pplxlee_myfirstjni_MainActivity #define _Included_com_pplxlee_myfirstjni_MainActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_pplxlee_myfirstjni_MainActivity * Method: getNum * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_pplxlee_myfirstjni_MainActivity_getNum (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
實際上就是聲明了JNIEXPORT jint JNICALL Java_com_pplxlee_myfirstjni_MainActivity_getNum(JNIEnv *, jobject)函數,對應與java代碼中的getNum函數,剩下的事情就是編碼實現getNum的功能了。不過這里可能會出現Eclipse的bug,就是點擊C++代碼時,可能會產生類型不能解析的錯誤,導致無法編譯運行。解決方法就是在編譯運行之前刪掉這些錯誤就好了。
接下來編寫MyFirstJni.cpp文件如下:
#include "com_pplxlee_myfirstjni_MainActivity.h" jint Java_com_pplxlee_myfirstjni_MainActivity_getNum (JNIEnv *,jobject) { return 100; }
然后編譯運行,在手機上的運行結果如下:
自此,一個簡單的Android NDK程序完成了!
六、總結
作為一個初學者,一定要靜下心來一點一點的學習,切忌心浮氣躁,會走很多彎路的!
以后將學習如何在JNI中使用stl庫和Opencv庫等,學好后將會繼續分享到我的博客上面。