如何在Android Studio裡跑NDK
我的開發環境在Windows 7 64bit,首先你要安裝好Android Studio和NDK,NDK的部分是下載解開壓縮檔,它會產生一個帶有NDK版號的目錄,你要將目錄名稱改為NDK比較好。參考Google的NDK說明就有講,更多詳細說明請自行至NDK開發網站看。
安裝好Android Studio和NDK之後,開啟Android Studio新建一個專案,我這裡是寫一個簡單用C輸出字串給JAVA的範例,網路上好像也很多了。新建專案如下圖:
這裡面只有一個TextView元件,接著要定義使用的C/C++函式庫名稱和使用的C/C++副程式名稱和定義。我這裡函式庫名稱是JniDemo,副程式是String getStringFromNative(),這兩個要在MainActivity.java宣告。
宣告的程式碼如下:
static {
System.loadLibrary("JniDemo");
}
public native String getStringFromNative();
實際畫面如下圖紅框:
接下來要利用已經宣告的副程式名稱來產生相應的C/C++宣告檔,附檔名是.h,按下Android Studio左下角的Terminal按鍵(如下圖綠色框框)會進入你的專案目錄,這個模式下就可以下一般的consle指令,首先輸入cd src\main\java按下Enter後切換至你的專案的JAVA程式目錄去,接著利用javah工具讓它產生宣告檔,指令如下: javah -jni com.david.ndkdemo.MainActivity,com.david.ndkdemo是我的package名稱,MainActivity是我的class,因此完整的calss名字是com.david.ndkdemo.MainActivity,如果沒有問題會在你的專案目錄下的src/main/java裡產生一個.h的檔案,我這裡產生的是com_david_ndkdemo_MainActivity.h(如下圖的左上角紫色框框)。
接下來要建一個jni目錄來存放剛剛產生的.h檔,對準main目錄按下滑鼠右鍵,選擇NewàFolderàJNI Folder(如下圖),建好之後用滑鼠拖拉的方式把剛剛的.h檔拖進建好的jni目錄。
.h標頭檔準備好了,接下來就是C/C++的程式碼檔,一般都是.c或是cpp,我這裡是用.c,檔名隨便你取,對準jni目錄按右鍵新增一個檔案,我這裡是用HelloNDK.c,新增好之後去剛剛的.h裡把
函數宣告copy過來就可以,函數宣告內容如下:
JNIEXPORT jstring JNICALL Java_com_david_ndkdemo_MainActivity_getStringFromNative
(JNIEnv *, jobject);
這裡的宣告還缺點東西,(JNIEnv *, jobject)只有型態沒有實際命名,等一下會用到是無法操作的,所以改成(JNIEnv env*, jobject obj),另外慣例要把.h引入.c檔中,所以完整程式碼如下(如下圖):
#include <com_david_ndkdemo_MainActivity.h>
JNIEXPORT jstring JNICALL Java_com_david_ndkdemo_MainActivity_getStringFromNative
(JNIEnv * evn, jobject obj)
{
return (*evn)->NewStringUTF(evn,"Hello NKD demo");
}
return (*evn)->NewStringUTF(evn,"Hello NKD demo")這一行就是實際的程式碼。會傳回字串給JAVA。
接下來要設定NDK參數了,打開專案最上層路徑的local.properties檔案(如下圖紅框部分),新增ndk的安裝路徑,參數如下ndk.dir=C\:\\ndk,要配合你時機的NDK安裝路徑去設定,如下圖黃框部分。
另外還要設定ndk模組名稱,最開始有講名稱是JniDemo,打開專案下的app下的build.gradle檔(如下圖紅框部分),在defaultConfig的大括弧裡新增
ndk{
moduleName "JniDemo"
}
如下圖黃框部分。
最後去畫面把原本沒有id名稱的TextView給個名字,我這裡是給TextView1,然後去MainActivity.java裡把剛剛的C程式引進來用,程式碼很簡單如下:
TextView tmpView = (TextView) findViewById(R.id.TextView1);
tmpView.setText(getStringFromNative());
實際畫面如下圖紅框部分。
好了之後就可以按下執行,讓Android Studio開始編譯程式,不過應該會出現一個錯誤,我這裡的是make.exe: *** No rule to make target `E:\AndroidStudioProjects\NDKdemo\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/JniDemo/E_\AndroidStudioProjects\NDKdemo\app\src\main\jni', needed by `E:\AndroidStudioProjects\NDKdemo\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/JniDemo/E_\AndroidStudioProjects\NDKdemo\app\src\main\jni\HelloNDK.o'. Stop.
No rule to make target?? 這其實是個Android Studio編譯NDK的小bug,在剛剛jni目錄裡先增一個.c的檔案,但是裡面都不要有東西,我這裡是給aaa.c然後在編譯一次,大功告成,你應該可以看到畫面”Hello NKD demo”出現了,我實驗了一下發現編譯成功之後再把aaa.c砍掉也可以編譯成功,所以我想這是個小小的bug。下次再遇到No rule to make target就新增一個空檔騙一下Android Studio就好。

爬過也試過很多文章都失敗 按照你的步驟一次就成功 寫得太好了.. 我有個問題要問一下 NDK的範例 jni 資料夾裡有用 android.mk application.mk 為什麼你寫的步驟不需要??
很高興對你有幫助,android.mk這部分android studio他會自己產生,路徑就在NDKdemo\app\build\intermediates\ndk\debug下,NDKdemo是你專案名稱,我這裡是NDKdemo, application.mk這裡就不用了,指定CPU的方式android studio也會根據build.gradle來編譯,有時間多研究一下Gradle,因為android studio已經都用gradle來管理專案的東西了。一些編譯相關的資料都是在gradle裡面改。
HI~ 我又來了 那Gradle的文件有推薦的地方可以研究嗎?(官方文件好少) 今天我試NDK的範例 "bitmap-plasma" 編譯時遇到 1.Error:(383) undefined reference to `__android_log_print' 2.Error:(377) undefined reference to `AndroidBitmap_getInfo' 這兩個問題 1.可以在 android.mk 裡 加入 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog 或 Gradle 裡 ndk 加入 ldLibs "log" (以解決) 2.可以在 android.mk 裡 加入LOCAL_LDLIBS := -ljnigraphics 那在 Gradle 裡要怎麼加入? 要如何查這類的資訊? 謝謝你^^
你好, 這兩天有東西要趕工沒辦法幫你查那個東西,你可以先查看看gradle在build專案時候的參數,也許有類似的作法,可以查看看http://tools.android.com/tech-docs/new-build-system/user-guide,等過兩天我比較有空檔我在幫忙查看看你要的。 你好, 我利用晚上時間寫的一個有關自訂Android.mk和Application.mk來編譯的說明請見http://david740204.pixnet.net/blog/post/412169557 你好, 我根據你給的資料把bitmap-plasma範本拿來寫一個新的app已經可以正常運作沒有出現編譯錯誤,執行畫面上顯示一個不斷變換色彩的極光。
您好: 我想請教您說的函示庫名稱為JNIDemo 這邊指的函示庫是什麼呢? 小弟最近才在做這個 有點不懂 謝謝
函示庫指的是英文的Library,在這裡你可以看成是一個模組,用來置放c副程式的地方。
gradle是有點像JAVA裡的makeflie 這樣說可以嗎? 所以我要將所有可能會用到的lib都先在build.gradle裡的ndk寫下來對吧! 像是如果會用到LOG就要寫ldLibs "log" 有用到bitmap就要寫ldLibs "z", "jnigraphics" 那有沒有甚麼地方可以找得到這些lib的列表呢?
是像makefile沒錯,lib要事先定義好寫在gradle裡,至於要那些lib列表我倒是沒有資料,我建議到google的android開發網找找應該會有。
您好, 不知道我照著您的只是往下做,做到要在 terminal 輸入 javah ....時 它只跟我說 'javah' 不是內部或外部命令、可執行的程式或批次檔。 並沒有主動產生出來 .h檔 謝謝您 :)
抱歉太晚看到訊息了,應該是跟jdk有關,看是沒安裝好還是路徑沒設定,我印象當時裝好jdk是有設定一下windows路徑到我的系統環境變數裡去。
這篇文章真的太棒了,讓我了解 如何用 android studio 讓 android app 經由JNI 呼叫 c/c++ function.
您有受用我就開心了。