Android開(kāi)發(fā)之NDK

NDK

NDK全稱(chēng):Native Development Kit。

關(guān)于NDK顷牌,360百科是這么說(shuō)的:
1.NDK是一系列工具的集合湘今。

  • NDK提供了一系列的工具己单,幫助開(kāi)發(fā)者快速開(kāi)發(fā)C(或C++)的動(dòng)態(tài)庫(kù)唉窃,并能自動(dòng)將so和java應(yīng)用一起打包成apk。這些工具對(duì)開(kāi)發(fā)者的幫助是巨大的纹笼。

  • NDK集成了交叉編譯器纹份,并提供了相應(yīng)的mk文件隔離平臺(tái)、CPU廷痘、API等差異蔓涧,開(kāi)發(fā)人員只需要簡(jiǎn)單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等)笋额,就可以創(chuàng)建出so元暴。

  • NDK可以自動(dòng)地將so和Java應(yīng)用一起打包,極大地減輕了開(kāi)發(fā)人員的打包工作兄猩。

2.NDK提供了一份穩(wěn)定茉盏、功能有限的API頭文件聲明。

Google明確聲明該API是穩(wěn)定的枢冤,在后續(xù)所有版本中都穩(wěn)定支持當(dāng)前發(fā)布的API鸠姨。從該版本的NDK中看出,這些API支持的功能非常有限淹真,包含有:C標(biāo)準(zhǔn)庫(kù)(libc)讶迁、標(biāo)準(zhǔn)數(shù)學(xué)庫(kù)(libm)、壓縮庫(kù)(libz)核蘸、Log庫(kù)(liblog)巍糯。

NDK產(chǎn)生的背景

Android平臺(tái)從誕生起,就已經(jīng)支持C值纱、C++開(kāi)發(fā)。眾所周知坯汤,Android的SDK基于Java實(shí)現(xiàn)虐唠,這意味著基于Android SDK進(jìn)行開(kāi)發(fā)的第三方應(yīng)用都必須使用Java語(yǔ)言。但這并不等同于“第三方應(yīng)用只能使用Java”惰聂。在Android SDK首次發(fā)布時(shí)疆偿,Google就宣稱(chēng)其虛擬機(jī)Dalvik支持JNI編程方式,也就是第三方應(yīng)用完全可以通過(guò)JNI調(diào)用自己的C動(dòng)態(tài)庫(kù)搓幌,即在Android平臺(tái)上杆故,“Java+C”的編程方式是一直都可以實(shí)現(xiàn)的。
  不過(guò)溉愁,Google也表示处铛,使用原生SDK編程相比Dalvik虛擬機(jī)也有一些劣勢(shì),Android SDK文檔里,找不到任何JNI方面的幫助撤蟆。即使第三方應(yīng)用開(kāi)發(fā)者使用JNI完成了自己的C動(dòng)態(tài)鏈接庫(kù)(so)開(kāi)發(fā)奕塑,但是so如何和應(yīng)用程序一起打包成apk并發(fā)布?這里面也存在技術(shù)障礙家肯。比如程序更加復(fù)雜龄砰,兼容性難以保障,無(wú)法訪問(wèn)Framework API讨衣,Debug難度更大等换棚。開(kāi)發(fā)者需要自行斟酌使用。
  于是NDK就應(yīng)運(yùn)而生了,2011發(fā)布NDK反镇。NDK全稱(chēng)是Native Development Kit固蚤。NDK的發(fā)布,使“Java+C”的開(kāi)發(fā)方式終于轉(zhuǎn)正愿险,成為官方支持的開(kāi)發(fā)方式颇蜡。NDK將是Android平臺(tái)支持C開(kāi)發(fā)的開(kāi)端。

NDK作用

  • 代碼的保護(hù)辆亏。由于apk的java層代碼很容易被反編譯风秤,而C/C++庫(kù)反匯難度較大。

  • 可以方便地使用現(xiàn)存的開(kāi)源庫(kù)扮叨。大部分現(xiàn)存的開(kāi)源庫(kù)都是用C/C++代碼編寫(xiě)的缤弦。

  • 提高程序的執(zhí)行效率。將要求高性能的應(yīng)用邏輯使用C開(kāi)發(fā)彻磁,從而提高應(yīng)用程序的執(zhí)行效率碍沐。(在前面性能優(yōu)化中有提及)

  • 便于移植。用C/C++寫(xiě)得庫(kù)可以方便在其他的嵌入式平臺(tái)上再次使用衷蜓。

具體可參考NDK 入門(mén)指南

JNI

JNI是Java Native Interface的縮寫(xiě)累提,它提供了若干的API實(shí)現(xiàn)了Java和其他語(yǔ)言的通信(主要是C&C++)。從Java1.1開(kāi)始磁浇,JNI標(biāo)準(zhǔn)成為java平臺(tái)的一部分斋陪,它允許Java代碼和其他語(yǔ)言寫(xiě)的代碼進(jìn)行交互。JNI一開(kāi)始是為了本地已編譯語(yǔ)言置吓,尤其是C和C++而設(shè)計(jì)的无虚,但是它并不妨礙你使用其他編程語(yǔ)言,只要調(diào)用約定受支持就可以了衍锚。使用java與本地已編譯的代碼交互友题,通常會(huì)喪失平臺(tái)可移植性。但是戴质,有些情況下這樣做是可以接受的度宦,甚至是必須的踢匣。例如,使用一些舊的庫(kù)斗埂,與硬件符糊、操作系統(tǒng)進(jìn)行交互,或者為了提高程序的性能呛凶。JNI標(biāo)準(zhǔn)至少要保證本地代碼能工作在任何Java 虛擬機(jī)環(huán)境男娄。

通俗點(diǎn)的意思就是用JAVA調(diào)用C或者C++。在實(shí)際開(kāi)發(fā)過(guò)程中很可能會(huì)使用到C或者C++開(kāi)發(fā)的DLL(windows平臺(tái))漾稀,或者so(Linux平臺(tái))模闲,這個(gè)時(shí)候就需要用JAVA來(lái)調(diào)用DLL或者so文件。

開(kāi)發(fā)NDK時(shí)崭捍,需要用到JNI尸折。

接口分析

JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);

  • JNIEXPORT :在Jni編程中所有本地語(yǔ)言實(shí)現(xiàn)Jni接口的方法前面都有一個(gè)"JNIEXPORT",這個(gè)可以看做是Jni的一個(gè)標(biāo)志,至今為止沒(méi)發(fā)現(xiàn)它有什么特殊的用處殷蛇。

  • void :這個(gè)學(xué)過(guò)編程的人都知道实夹,當(dāng)然是方法的返回值了。

  • JNICALL :這個(gè)可以理解為Jni 和Call兩個(gè)部分粒梦,和起來(lái)的意思就是 Jni調(diào)用XXX(后面的XXX就是JAVA的方法名)亮航。

  • Java_com_test01_Test_firstTest:這個(gè)就是被上一步中被調(diào)用的部分,也就是Java中的native 方法名匀们,這里起名字的方式比較特別缴淋,是:包名+類(lèi)名+方法名。

  • JNIEnv * env:這個(gè)env可以看做是Jni接口本身的一個(gè)對(duì)象泄朴,jni.h頭文件中存在著大量被封裝好的函數(shù)重抖,這些函數(shù)也是Jni編程中經(jīng)常被使用到的,要想調(diào)用這些函數(shù)就需要使用JNIEnv這個(gè)對(duì)象祖灰。例如:env->GetObjectClass()钟沛。

Jni中的數(shù)據(jù)類(lèi)型

每一個(gè)Java的數(shù)據(jù)類(lèi)型在Jni中都一個(gè)和它相對(duì)應(yīng)的數(shù)據(jù)類(lèi)型,這樣才能保證Java調(diào)用C或者C++的過(guò)程中數(shù)據(jù)的正確性局扶。jni.h頭文件中定義的類(lèi)型:

![2.png](http://upload-images.jianshu.io/upload_images/4623465-45b6afc193305be2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

NDK環(huán)境搭建

下載NDK恨统,下載具體文件解壓即可,也可使用studio的sdk manager下載安裝

Android-Studio配置

配置NDK路徑

  • 右擊Module->Open Module Setting->SDK Location->Android NDK Location
  • 或者直接修改local.properties文件
QQ圖片20170410212255.png

創(chuàng)建Library項(xiàng)目详民,定義模板類(lèi)延欠,此類(lèi)主要為了生成so文件用陌兑,so文件生成后可刪除

// 包名和類(lèi)名要和.cpp或者.c文件中一致
package com.ndkdemo;

public class MathKit
{
   // 定義native本地方法沈跨,和普通方法相同,加上native關(guān)鍵字
    public static native int square(int num);
}

創(chuàng)建jni目錄兔综,默認(rèn)為src/main/jni

javah命令生成.h文件

在Android Studio找到View->Tool Windows->Terminal 打開(kāi)命令行:
執(zhí)行如下命令:

javah -d NDKDemo/src/main/jni/ -classpath D:/AndroidStudioProjects/MyWork/NDKDemo/build/intermediates/classes/debug  -jni com.ndkdemo.MathKit

或者

cd D:/AndroidStudioProjects/MyWork/NDKDemo/build/intermediates/classes/debug
javah com.ndkdemo.MathKit

-d . 表示將在當(dāng)前目錄下生成一個(gè)當(dāng)前命令行文件夾饿凛,產(chǎn)生的頭文件就在這里面了狞玛;
-classpath < PATH> 指明class文件所在的位置(目錄)
-jni com.ndkdemo.MathKit 指定類(lèi)名

javah命令主要用于在JNI開(kāi)發(fā)的時(shí),把java代碼聲明的JNI方法轉(zhuǎn)化成C\C++ 頭文件涧窒,以便進(jìn)行JNI的C\C++ 端程序的開(kāi)發(fā)心肪。
但是需要注意的是javah命令對(duì)Android編譯生成的類(lèi)文件并不能正常工作。如果對(duì)于Android的JNI要想生成C\C++ 頭文件的話纠吴,可能只有先寫(xiě)個(gè)純的java代碼來(lái)進(jìn)行JNI定義硬鞍,接著用JDK編譯,然后再用javah命令生成JNI的C\C++ 頭文件戴已。當(dāng)然你也可以不用javah命令固该,直接手寫(xiě)JNI的C\C++ 頭文件。

創(chuàng)建cpp文件糖儡,文件名最好和.h文件同名伐坏,便于管理編輯.cpp文件

#include <com_ndkdemo_MathKit.h>

JNIEXPORT jintJNICALL Java_com_ndkdemo_MathKit_square
        (JNIEnv *env, jclass cls, jint num){
    return num * num;
}

在app module目錄下的build.gradle配置ndk選項(xiàng)

defaultConfig {
    ......
    ndk{
           moduleName "ndklib"         //生成的so名字,實(shí)際為 libndklib.so
           abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86"  //輸出指定三種abi體系結(jié)構(gòu)下的so庫(kù)
        }
}
buildTypes {
        release {
            minifyEnabled false
            proguardFiles 'proguard-rules.pro'
            ndk {
                moduleName "jnimain"
                abiFilters "armeabi", "armeabi-v7a"
            }
        }
    }

Make上述Library項(xiàng)目,生成so文件

先在gradle.properties中添加:android.useDeprecatedNdk=true

生成的so文件在如下目錄握联,生成的so文件為 =lib+ 配置生成名 .so
<Module主目錄>/build/intermediates/ndk/debug/lib/arm64-v8a/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/armeabi/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/armeabi-v7a/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/x86/libndklib.so

在其他Application項(xiàng)目中引用

1.直接引用Library Module
定義和模板類(lèi)相同類(lèi)桦沉,包名+類(lèi)名和此前jni中一致

// 包名和類(lèi)名要和.cpp或者.c文件中一致
package com.ndkdemo;

public class MathKit{
    static{
        // 對(duì)應(yīng)庫(kù)文件名稱(chēng),要一致金闽。生成的.so文件名為libndklib.so纯露,
        // 那么loadLibrary為ndklib,去掉前面的lib及后面的.so
        System.loadLibrary("NDKDemo");
    }
   // 定義native本地方法呐矾,和普通方法相同苔埋,加上native關(guān)鍵字
    public static native int square(int num);
}

在應(yīng)用中使用靜態(tài)方式調(diào)用native方法
例如: MathKit.square(10)

2.創(chuàng)建src/main/jniLibs目錄,把生成的so文件拷貝進(jìn)去調(diào)用natvie方法方式同上

自定義jni路徑和so文件路徑

1.jni編輯路徑自定義

android {

  sourceSets.main {
      jni.srcDirs 'src/main/source'
  }
}

2.so文件路徑自定義

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

由于Android Studio以強(qiáng)大的方式集成了NDK, 所以上面很多配置都不需要寫(xiě). 方便了很多..mk文件不用自己寫(xiě)蜒犯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末组橄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子罚随,更是在濱河造成了極大的恐慌玉工,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淘菩,死亡現(xiàn)場(chǎng)離奇詭異遵班,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)潮改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)狭郑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人汇在,你說(shuō)我怎么就攤上這事翰萨。” “怎么了糕殉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵亩鬼,是天一觀的道長(zhǎng)殖告。 經(jīng)常有香客問(wèn)我,道長(zhǎng)雳锋,這世上最難降的妖魔是什么黄绩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮玷过,結(jié)果婚禮上爽丹,老公的妹妹穿的比我還像新娘。我一直安慰自己辛蚊,他們只是感情好习劫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著嚼隘,像睡著了一般诽里。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上飞蛹,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天谤狡,我揣著相機(jī)與錄音,去河邊找鬼卧檐。 笑死墓懂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霉囚。 我是一名探鬼主播捕仔,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼盈罐!你這毒婦竟也來(lái)了榜跌?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盅粪,失蹤者是張志新(化名)和其女友劉穎钓葫,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體票顾,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡础浮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奠骄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豆同。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖含鳞,靈堂內(nèi)的尸體忽然破棺而出影锈,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布精居,位于F島的核電站,受9級(jí)特大地震影響潜必,放射性物質(zhì)發(fā)生泄漏靴姿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一磁滚、第九天 我趴在偏房一處隱蔽的房頂上張望佛吓。 院中可真熱鬧,春花似錦垂攘、人聲如沸维雇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吱型。三九已至,卻和暖如春陨仅,著一層夾襖步出監(jiān)牢的瞬間津滞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工灼伤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留触徐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓狐赡,卻偏偏與公主長(zhǎng)得像撞鹉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颖侄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容