源地址:http://www.voidcn.com/blog/chengkaizone/article/p-5761016.htmlhtml
好記性不如爛筆頭,開始堅持寫博客,學一點記一點,只爲了生活更好。java
學了一年多的硬件,如今來作android,不知道是對是錯,跟着感受走,開始老是想把android和硬件掛上勾,因此第一個android應用寫的是關於藍牙的。如今學習NDK開發,有時說得也是JNI開發。那爲何要學習JNI,JNI會學習到比較底層的東西,java能夠實現上層應用的開發,可是不能寫底層驅動,有些android項目必須和底層硬件打交道,好比要精確快速的獲取某種傳感器的值,那麼java是不能辦到的,那怎麼辦,就經過JNI開發,經過c/c++完成底層驅動或者值得獲取,而後將值傳回到java層。一樣java層也能夠將數據傳遞給c/c++層,這樣經過JNI完成數據的交互。linux
那爲何java不能訪問底層呢?先看一張java程序的執行流程圖:android
java源代碼經過java編譯器後變成字節碼,而後裝載到java平臺運行期環境(java虛擬機),在不一樣的平臺下游不一樣的java虛擬機,window下有window的,linux下有linux下的java虛擬機,java虛擬機屏蔽了與底層直接的細節,作到java運行與平臺無關,因此java是不能訪問底層的c++
那麼java層怎麼就能訪問到c/c++層並將數據傳輸過去:c/c++又怎麼能將數據傳回java層呢。出來在java層經過native標記某個方法是本地方法外,重要是須要NDK這個android 本地開發工具集 app
什麼是NDK(android native develop kits ):android 本地開發工具集 ,能夠把c/c++ ->編譯成一個 linux下能夠執行的二進制文件 java代碼裏面就能夠經過jni 調用執行二進制的文件.eclipse
什麼是JNI :java本地開發接口,JNI是一個協議這個協議用來溝通java代碼和外部的本地代碼(c/c++).經過這個協議,java代碼就能夠調用外部的c/c++,代碼外部的c/c++代碼也能夠調用java代碼。工具
JNI開發用途:驅動開發 (wifi-hotspot) 2.3無線熱點共享 ,Native code效率高,數學運算,實時渲染的遊戲上,音視頻處理(極品飛車,opengl,ffmpeg),複用代碼(文件壓縮,人臉識別…)等。學習
下面進入主題:JNI開發環境配置及簡單的程序實現。開發工具
一:須要的工具及資源:開發工具,android studio,NDK開發工具集,至於沒有的能夠到網上下載,我用的是android studio1.3和 android-ndk-r10,固然沒必要和我同樣的,好像聽網上說android studio1.3開始支持DNK開發,並且支持也不太好的,通過這幾天的學習,真的是感受支持不是很好的,最新的NDK開發工具集集成了cygwin(一個模擬Linux運行環境的軟件),因此就不像之前那樣還要安裝什麼cygwin。
環境配置步驟以下(簡單的說一下,網上有不少教程):
1 解壓NDK開發工具集,隨便哪裏都行,看你本身的習慣,可是仍是要本身知道,別何時不知不覺刪了,而後開發JNI始終不行,怎麼都找不到錯誤,那就杯具了。
2打開android studio,依次點擊:File ->ProjectStructure:如圖:
點擊右邊,選擇你解壓的NDK,點擊應用。這一步將工具包關聯到android studio。
在 local.properties 文件中設置ndk的路徑:
就是你解壓的NDK工具集的路徑 個人是 E:/Android/android-ndk-r10,注意要對應加斜槓
到這裏我說JNI(有時說的NDK開發,同樣的,叫法不一樣)環境初步建好了,不想eclipse那樣什麼cygwin啊,怎麼還要ndk-build的啊,我說什麼都不用,就用一個命令就好了,下面就開始咱們的第一個小demo。
程序過程講解:
一:頭文件生成:
第一步:像平時同樣將一個空的android工程。
第二部:前面說了,要用native來標識一個方法,告訴程序這是一個本地方法。程序以下
public class NDK extends Activity{ static { System.loadLibrary("MyJni");//導入生成的連接庫文件 } public native String getStringFromNative();//本地方法 public native String getString_From_c(); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.myjni); System.out.println(getStringFromNative()); } public void onClick(View view) { System.out.println(getString_From_c()); Toast.makeText(this, getStringFromNative(), Toast.LENGTH_LONG).show(); }}
這一步能夠先不加這行代碼:System.loadLibrary("MyJni");//導入生成的連接庫文件 ,由於這裏尚未創建C文件,不能生成庫文件。
而後make project一下,目的就是編譯成對應的class文件。而後根據生成的class文件,利用javah生成對應的 .h頭文件。若是沒有編譯就執行javah命令會提示找不到這個類文件的。下面是個人工程界面;![](http://static.javashuo.com/static/loading.gif)
這裏說一下:我工程裏面的本地方法顯示是紅色,我一開始覺得不能進行JNI開發,或者有錯誤,包括我後面的C文件和頭文件裏面也有不少地方是紅色的,我開始定義這些方法的時候是紅色的,可是有時又不是的,不知道是android studio對NDK支持不太好,仍是怎麼得,可是後面開發JNI程序沒有任何影響的。因此就沒有關了,若是那位大神知道還望告訴我一下,將很是感激。
第三部:打開命令窗口,點擊view ->ToolsWindows->Terminal,以下圖:
進來後默認是指向當前的工程目錄,接下來輸入命令:cd app/src/main 回車,切換到main目錄下:如圖:
至於怎麼理解命令,建議你去學一下linux系統,這事linux最基本的操做。
第四部:輸入javah -d jni -classpath E:/Android/sdk/platforms/android-22/android.jar;../../build/intermediates/classes/debug example.daosong.com.ndkdemo.NDK(注意先後有英文的;號隔開的哈) 生成頭文件(要先編譯程序的,否則會報錯)。可能有些人看到這裏就茫然了,這麼長怎麼寫出來的喲,這怎麼記獲得的,我告訴你們根本不用記,我給你說怎麼得來的,大家就能很快寫出來了,是否是真的喲,不信試一試的。
首先:javah是生成頭文件須要的工具,這個很好記得把,相信學java是都用過的。-d jni 在工程下生成jni目錄,到時會在這個目錄下建JNI開始的C/C++源文件的。
-classpath E:/Android/sdk/platforms/android-22/android.jar 這個就是你SDK文件下android.jar所在的文件位置,找到後複製便可。在學java的時候講了這個的,能夠將E:/Android/sdk/platforms/android-22/android.jar配置到環境變量就能夠不寫出來,由於在生成頭文件是須要這個jar包,由於我沒有配置到環境變量,因此這裏就顯示寫出來。這部分很好搞定把。前面好弄,那後面部分怎了弄得,相信學過linux的很快可以知道的。
../../build/intermediates/classes/debug example.daosong.com.ndkdemo.NDK
首先是 ../../build/intermediates/classes/debug,結合到下面的圖看:
..表示返回上級目錄,../..表示返回上兩級目錄,也就是返回到那層目錄,而後明白這個了啥../../build/intermediates/classes/debug,指向debug目錄,而後空格和後面隔離,
而後就是後面部分example.daosong.com.ndkdemo.NDK,看上圖明白啥,是該類的全路徑,這裏有.隔離開,平時寫類的全路徑都是用的.號,生成頭文件是將類對應的class文件生成二進制文件,因此要指向這裏的,而後回車就能完成了頭文件的生成。意思是將該文件目錄下的NDK.class文件生成相應的頭文件。打開jni目錄下會有本地方法相應的映射方法定義。
在jni目錄下創建C源文件
網上說須要在jni下多建一個空的C文件,不讓會出錯,到底出什麼錯我也不知道的,反正我多很少建都沒有什麼影響的,不過多建一個沒什麼影響,也就建了。
jni.c
代碼以下:
#include "example_daosong_com_ndkdemo_NDK.h"//#include <android/log.h>//#define LOG_TAG "System.out"//#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)//#define LOGINFO(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)JNIEXPORT jstring JNICALL Java_example_daosong_com_ndkdemo_NDK_getStringFromNative (JNIEnv * env, jobject obj){ // LOGINFO("LOGINFO"); return (*env)->NewStringUTF(env,"NDK 測試成功");}jstring Java_example_daosong_com_ndkdemo_NDK_getString_1From_1c (JNIEnv * env, jobject jobject){ return (*(*env)).NewStringUTF(env,"NDK 來自於C文件");}
講到這裏若是要運行還得配置一個地方:
如今運行控制檯就會打印相應的消息(至於爲何這麼寫,代碼表明什麼意思,我會在下一篇博客講解),不是eclipse還要配置android.mk這麼文件嗎?android studio不用,你還真猜對了,不過不是說不用就表明他沒有,只不過這個配置過程不過你來作,你要作的就是配置上圖的代碼。那android.mk
在哪裏的呢?看下圖:
是否是是曾相識啊,對就是它。不知不覺就是深夜1點多了,下面給出個人工程,裏面有log打印相關的知識,這個將在下一篇博客詳細講解,若是有什麼錯誤,歡迎你們指出。
http://download.csdn.net/detail/tuoguang/9068899
另外有一點很關鍵
若是出現以下錯誤: NDK integration is deprecated in the current plugin.
gradle.properties中添加以下配置
android.useDeprecatedNdk=true
來源地址: http://www.th7.cn/Program/Android/201509/550864.shtml