這兩天研究了下ndk開發,由於公司android播放器,後續開發須要調用底層so庫,網上查了不少資料全都是eclipse,可是我用的是netbeans只好自行研究,ndk很簡單,baidu一下資料不少,若是你是一個有經驗的程序員,分分鐘就能夠搞定,編譯出一個so來。 html
主要問題就在於如何將so與apk打包到一塊兒。 java
Eclipse是經過ADT插件自動完成的,也能夠本身編寫ant腳本,經過ant打包,這就不在本文範圍內了。 linux
讓習慣netbeans的程序員,排斥eclipse的程序員可以順利的完成他們的android開發,也讓像學習ndk開發的人可以快速入門 android
有VC基礎,想搞android開發的開發的技術人員 c++
使用netbeans的android開發人員(通常也都是VC轉過來的,由於VS IDE和NetbeansIDE風格比較類似) 程序員
Netbeans: 算法
本教程使用的是6.8,但不限於6.8版本(自行下載安裝) windows
用於開發android app api
Ndk開發環境: 安全
用於開發供app調用的so本地庫
Windows開發環境包含如下2個軟件包
n Ndk開發包android-ndk-r8d-windows.zip
下載連接http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip
若是打不開,能夠進入下載頁面
http://developer.android.com/tools/sdk/ndk/index.html#download下載
n Linux模擬環境cygwin
第2步. 下載Ndk開發包
第3步. 解壓到任意位置(本例:F:\ndk)目錄結構如圖
第4步. Ndk安裝就完成了,該安裝cygwin了
第5步. 下載cygwin.zip,這個是網絡安裝器,下載好有900多M就不打包在本教程中了
第6步. 安裝cygwin,選擇第一個,從網上下載安裝,如圖
第7步. 設置安裝目錄,如圖
第8步. 設置下載到安裝文件保存位置,如圖
安裝完成後,本地就有下載好的包,之後在別的機器從新安裝時就能夠選擇第3項,從本地安裝,選者這裏設置的目錄
第9步. 而後一直默認懸想,一直下一步,到如圖步驟,選擇一個下載站點,通常選擇163速度還能夠
第10步. 選擇要安裝的模塊,只要安裝Devel就夠了,如圖
第11步. 等待安裝完成吧,大小是900多M
第12步. 驗證cygwin安裝
n 運行安裝目錄下的「Cygwin.bat」,第一次運行時,它會自動建立用戶信息,用戶信息存放在「.\Cygwin\home」中。
n 在運行「Cygwin.bat」打開的命令行窗口輸入:「cygcheck -c cygwin」命令,會打印出當前Cygwin的版本和運行狀態,若是status是ok的話,則cygwin運行正常。
n 分別輸入:「make –v」和,「gcc –v」命令若是檢測成功,會有make和gcc相關版本信息打印出來。
如圖
第13步. Ndk開發環境搭建完成
第14步. 在系統環境變量中配置ndk目錄(可選的操做,主要是爲了方便),如圖
cygwin是linux模擬環境,訪問windows磁盤的方式是/cygdrive/盤符
直接使用附帶jni例子
進入目錄F:\ndk\\jni目錄
編譯hello-jni
編譯後就會生成so文件了,這個文件就能夠供android應用程序調用
第1步. 建立android項目calljni
第2步. 添加HelloJni類,代碼以下
package com.example.hellojni;
public class HelloJni
{
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI();
/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.hellojni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("hello-jni");
}
}
第3步. 在MainActivity類中添加調用代碼
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// ToDo add your GUI initialization code here
lib.stringFromJNI();
TextView tv = new TextView(this);
tv.setText( lib.stringFromJNI() );
setContentView(tv);
}
第4步. 將so文件添加到工程目錄\lib\armeabi下,添加後so位置如圖
第5步. Netbeans區別於eclipes的關鍵步驟
1) 編輯F:\ndk\calljni\nbproject\build-impl.xml文件
2) 找到name="-sign"的target, 也就是執行apkbuild的target
3) 在全部指令以前,加入如下指令,執行aapt將so打包進apk_
<exec executable="${aapt}" failonerror="true">
<arg value="a"/>
<arg value="${dist.apk}_"/>
<arg value="lib/armeabi/libhello-jni.so"/>
</exec>
若是有多個so須要打包進去,就多添加幾條以上指令
這一步就是幫助netbeans的用戶解決,如何把so文件打包進apk中這個難題。
你們都知道Apk就是一個zip格式的包,可是你不能直接將so文件打包進編譯出來的apk中,由於apk是要簽名纔有效的,裏面有簽名文件如圖中,打開查看,是經過hash算法計算出來的,因此必須在簽名以前,把so文件打包進去一塊兒簽名,因此必須本身修改項目的編譯腳本文件(其實就是ant編譯腳本)。
第6步. 編譯項目生成calljni.apk,在模擬器運行結果如圖
1. 什麼是NDK?
NDK 提供了一系列的工具,幫助開發者快速開發C/C++的動態庫(so文件),經過mk 文件隔離CPU、平臺、ABI 等差別,開發人員只須要簡單修改mk 文件(指出「哪些文件須要編譯」、「編譯特性要求」等),就能夠建立出so,使你能夠在你的Android程序當中用Java語言(JNI)調用這些c/c++代碼.
Google明確聲明該API是穩定的,在後續全部版本中都穩定支持當前發佈的API。從該版本的NDK中看出,這些API支持的功能很是有限,包含有:C標準庫(libc)、標準數學庫(libm)、壓縮庫(libz)、Log庫(liblog)
2. so文件必須使用ndk編譯?
不是,能夠直接在linux下編譯so,可是你得確保你所使用的api是操做系統所支持,就是上面google聲明中說的ndk支持的庫,若是是特定平臺支持的api,那可能就只有部分手機能夠正常運行
3. mk文件如何編寫
附件提供mk模板一分,可參考編寫
4. 網上說的使用javah生成c/c++ .h文件,是否必須
不是,徹底不須要,給出java生成.h文件的指令,和先決條件
javah -classpath ./build/classes -d jni org.me.calljni.MainActivity
首先必須編譯java類,無論你用任何方式,編譯出來就行,生成類.class文件,
而後使用以上指令生成頭文件-classpath後面的目錄就是生成的class的目錄
5. java代碼、c代碼、so方法之間的聯繫
n 你的應用的java源代碼中要聲明一個或多個方法,這些方法前面需有'native'關鍵字,這代表它們被本地代碼實現。如:
public native String stringFromJNI();
n 你必須提供本地的共享庫(.so),庫中包含這些方法的實現。將這個庫打包你的.apk中。這個庫的命名必須符合標準的Unix命名規則,也就是:lib<something>.so這種形式,例如:
libhello-jni.so。
n 而且還要包含一個標準的JNI入口,例如:
static {
System.loadLibrary("hello-jni");
}
n c函數生命應該按照以下規則命名,以說明函數是屬於哪一個java類的
java_目錄_目錄_方法名()例如:
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
以上函數,是一個java類的成員函數,這個類必須是在com\example\hellojni包下,類名必須是HelloJni
方法名必須是stringFromJNI(),沒有參數
這是由於java是面向對象的語言,因此so中實現的全部全局函數應該是java的某個成員方法
n JNIEnv* env, jobject thiz
這2個參數是全部jni函數必須的,只有這2個參數的函數,表示無參數的成員函數,帶有 3個參數就表示成員函數有1個參數,依次類推
n JNIEXPORT與JNICALL在提供android應用調用的so代碼中不是必須的
加上兼容性更好
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz );
6. ndk能不能直接開發java類
不知道,未研究,有興趣的能夠深刻研究,可以實現類成員函數,已經足夠
7. so中能不能調用其它 .so或.a
理論上能夠,但未驗證,能夠自行驗證,若是是so,須要將so文件一塊兒打包進apk,若是是.a文件,應該不須要打包進apk
8. ndk適合開發哪些模塊
如下爲我的理解
n 首先ndk未提供ui以及事件處理的api,因此作android開發不可能使用純c/c++,應用主體應該仍是android sdk使用java開發
n 其次so的反編譯難度比android應用的java代碼要難上不少,,因此ndk能夠用於開發一些須要保密代碼,防止反編譯泄露機密算法邏輯等
n 觀察ndk支持的庫,能夠看到,ndk適合作一些算法模塊,提升效率,支持libc也能夠實現通訊模塊,增強通訊的安全性