Android NDK初體驗(上)

以前學了一點NDK相關的知識,這篇文章主要總結回顧一下。NDK是一種幫助我們開發C/C++代碼的工具,NDK的開發包里包含很多交叉編譯的工具。一般情況下我們開發Android應用,只需要用到Java代碼,調用Android API即可,因此NDK在我們應用開發中很少接觸,下面從幾個方面詳細介紹一下NDK。

一、NDK使用場景

NDK到底在什么情況下使用呢?一般用于以下三種情形:

  1. 提高效率:C/C++編寫的代碼較Java編寫的代碼效率高,例如需要對大量數據進行排序時
  2. 使用現有第三方C/C++庫:大部分開源庫都是用C/C++編寫的,例如:人臉識別、音視頻處理開源庫、圖形圖像處理開源庫,如OpenCV等。
  3. 底層程序設計,便于移植:用C/C++代碼編寫的庫可以方便地在其他嵌入式平臺上再次使用。例如想開發一個在Android和IOS平臺都能使用的庫,就需要用到C/C++來編寫。

二、什么是交叉編譯

一般我們編寫的程序很容易就在電腦上編譯執行,這是因為我們的電腦的內存及CPU都能提供充足的空間和處理能力,但是在一般的嵌入式設備中開發就沒那么簡單了。由于嵌入式設備只有有限的空間和處理資源,因此很多情況下我們無法在嵌入式設備上編譯程序,由此就有了交叉編譯的概念。
  交叉編譯就是在一個平臺上生成另一個平臺上可執行的代碼,例如我們的電腦是X86平臺,手機是arm平臺,那么我們可以在電腦的x86平臺上編譯出來我們的應用程序,安裝到我們手機的arm平臺來運行,ndk開發包中就提供了這樣的交叉編譯工具。

三、什么是JNI

JNI(Java Native Interface,本地調用)提供了若干的API實現了Java和其他語言的通信(主要是C&C++),JNI標準已經成為了Java平臺的一部分。
JNI的實現流程如下:

四、什么是鏈接庫

“庫”是成熟的、可復用的代碼,我們可以將“庫”理解為一個文件,這個文件可以在編譯時由編譯器直接鏈接到可執行程序中,也可以在運行時由操作系統的runtime enviroment根據需要動態加載到內存中。
  很多時候我們程序員寫代碼都會依賴很多底層的,的存在不僅節約了很多時間,也保證了我們開發的穩定性,很多時候我們沒有那么多的精力和能力來將所有的代碼從頭開始寫,因此庫的存在是很有意義的。
  本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。
  庫有兩種:靜態庫(.a、*.lib)和動態庫(.so、.dll)。windows上對應的是.lib和.dll。linux上對應的是.a和.so。
  我們知道,將一個程序編譯成可執行程序有如下幾個步驟:


  所謂靜態、動態是指鏈接。靜態庫與動態庫的區別在于鏈接階段如何處理庫:

  • 靜態鏈接庫:將匯編生成的目標文件.o與引用到的庫一起鏈接打包到可執行文件中。它的特點是體積大、可移植性好,對庫的鏈接是編譯時完成的。
  • 動態鏈接庫:在編譯時只編譯自己的資源,運行時動態查找所需資源。它的特點是體積小、可共享,但可能出現所需文件找不到的情況。

五、動手試試吧

首先下載ndk開發包,可以去官網上下載相應的版本:下載地址,下載好以后配置環境,這里就不贅述了。

1.eclipse下ndk的使用##

以前用NDK都是在eclipse下,主要有以下個步驟:
(1)新建Android項目,在MainActivity中添加native方法,例如:

public static native String getStringFromC();

(2)在項目工程下創建jni目錄,并借助javah命令生成C頭文件到jni目錄下,在cmd中敲如下指令即可生成對應頭文件:


生成的頭文件可以看見其中與native函數有關的函數定義:

/*
 * Class:     com_example_hellondk_MainActivity
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_hellondk_MainActivity_getStringFromC
  (JNIEnv *, jclass);

(3)在jni目錄下寫.c文件來寫具體的實現代碼,并在該C文件中引入(2)中生成的頭文件

#include<stdio.h>
#include<stdlib.h>
#include "com_example_hellondk_MainActivity.h"http://引入(2)中生成的頭文件
JNIEXPORT jstring JNICALL Java_com_example_hellondk_MainActivity_getStringFromC
  (JNIEnv * env, jclass jclass){ // 函數的具體實現
    return(*env)->NewStringUTF(env,"Get Hello string from C!");
}

(4)在jni下創建Android.mk文件,指定編譯哪個C文件

LOCAL_MODULE  : = hello
LOCAL_SRC_FILES  : = hello.c

(5)執行ndk-build命令,生成obj目錄并生成libhello.so(在obj目錄下)
(6)在MainActivity中寫靜態代碼塊:

static{
       System.loadLibrary("hello");//導入生成的庫libhello.so
}

最終我們的MainActivity.java如下,調用名為“hello”的動態庫里的函數getStringFromC(),獲得其返回字符串顯示在頁面的TextView中:



最后我們運行一下我們的應用程序可以看到,我們的java層成功地調用了我們的動態庫中的獲取字符串函數并將我們設置的字符串顯示了出來。


:我們可以編譯不同平臺的.so文件,通過在jni目錄下建立Application.mk文件來控制。
當Application.mk文件中加入:APP_ABI := all時,生成所有四個版本的so文件,如下圖所示。

若只想生成arm平臺下的so文件,可將Application.mk文件中APP_ABI := all注釋,如下圖:


2.Android Studio下ndk的使用##

用AndroidStudio也來試試吧!我使用的Android Studio版本是1.5,gradle版本是2.8
(1)首先新建一個工程,配置好NDK路徑:File->Project Structure


這樣設置ndk路徑的效果跟在工程的local.properties中添加如下配置語句是一樣的,這樣設置成功后會自動在該文件下生成這句配置語句。

ndk.dir=E\:\\androidStudio\\android-ndk-r13

(2)在app模塊的build.gradle文件中配置ndk相關信息,如下圖,此處配置了生成的庫的名字,也可以在這里進行更多的配置,比如編譯平臺的選擇、log功能的配置等等。



(3)在工程目錄下的 gradl.properties 文件里加上android.useDeprecatedNdk=true


(4)與在eclipse下的MainActivity代碼一樣,調用native的getHelloStringFromC()方法,這時候這個方法會報錯,因為還沒有與這個方法對應的本地方法


解決辦法很簡單,在app>src>main目錄下新建jni目錄


在報錯的本地方法調用函數上按Alt+Enter,便會在jni目錄下自動生成對應的.c文件



修改hello.c中的代碼即可,所有的都是自動生成的,是不是很方便?
若想生成對應的頭文件,也很簡單,借助javah命令,在Terminal中輸入如下語句即可:

javah -d [生成頭文件的存放路徑] -jni [調用對應native方法的源文件路徑]

3.ndk的使用小結##

從上面eclipse和Android Studio的使用可以看出,二者原理上并無差別,只是Android Studio的自動化程度更高,用起來更加方便,但是目前對NDK的支持仍處于試驗階段,可能不同版本的使用過程中會出現這樣或者那樣的錯誤。工具只是一種輔助,自己可以根據自己的使用習慣選擇合適的工具。有關NDK使用的進階學習可以查看我的另一篇博客:Anroid NDK初體驗(下)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容