使用 AndroidStudio 進(jìn)行 NDK 開發(fā)

AndroidStudio 中進(jìn)行NDK 開發(fā)比起以往的Eclipse 要方便的多绑谣,下面來介紹下如何使用AndroidStudio 這個(gè) IDE 工具實(shí)現(xiàn)NDK 相關(guān)開發(fā)工作。

1. 準(zhǔn)備工作


在實(shí)際寫代碼之前,首先我們還是需要做一些準(zhǔn)備工作:

  1. 下載NDK 開發(fā)包:Android 官方下載頁面
  2. 配置系統(tǒng)環(huán)境變量

下載好NDK 開發(fā)包之后夷野,直接解壓到任意目錄距芬,然后需要配置一下系統(tǒng)環(huán)境變量,之所以要配置環(huán)境變量赃磨,是為了方便使用命令ndk-build 腳本進(jìn)行NDK 編譯立由。配置參考如下:

# 在.bash_profile中配置如下代碼export ANDROID_NDK=/Users/you/android-ndkexport 
PATH=$ANDROID_NDK:$PATH
# 然后執(zhí)行如下代碼轧钓,更新配置文件
source .bash_profile

其實(shí)編譯C/C++代碼不一定在AndroidStudio 中,如果配置好環(huán)境變量锐膜,直接使用進(jìn)入項(xiàng)目中的jni 目錄執(zhí)行ndk-build 命令即可在當(dāng)前目錄下生成一個(gè)libs 的目錄毕箍,里面存放了不同 平臺(tái)的.so 包,當(dāng)然運(yùn)行這個(gè)命令的前提是道盏,這個(gè)目錄下至少得有一個(gè)Android.mk 文件而柑,如果需要指定具體的編譯平臺(tái),那么還需要添加一個(gè)Application.mk 文件荷逞,當(dāng)然媒咳,如果命令行讓你頭疼,那么你可以采用gradle 的方式來解決這些問題种远,接下來我們將分別介紹這些使用方式涩澡。

2. 項(xiàng)目配置

使用AndroidStudio 開發(fā)前我們也要做點(diǎn)額外工作,我們需要在項(xiàng)目根目錄下local.properties 中添加編譯NDK 的路徑:

ndk.dir=/Users/you/android-ndk

如果這個(gè)文件不存在坠敷,你可以手動(dòng)生成一個(gè)妙同,然后再添加上述內(nèi)容即可。完成這個(gè)步驟之后膝迎,我們就可以正式開始著手NDK 相關(guān)的開發(fā)工作了粥帚。之所以要配置這個(gè)目錄,目的是讓我們開發(fā)的項(xiàng)目在使用 gradle 編譯時(shí)能夠找到NDK 相關(guān)編譯路徑

那么限次,接下來的工作也分為兩種情況:

沒有(C/C++)源碼芒涡,別人已經(jīng)提供好相應(yīng)的.so 文件,不需要編譯代碼
擁有(C/C++)源碼卖漫,需要自己編譯.so 文件

2.1 已有.SO文件费尽,不需要編譯源碼

這類情況是最簡單的,.so 文件以及被其他人員編譯好懊亡,或者是第三方庫來提供的依啰,那么我們只需要把相應(yīng).so 文件放到AndroidStudio 目錄src/main/jniLibs/ 下即可,當(dāng)然店枣,肯定需要按 CPU 架構(gòu)分不同的子目錄速警。
jniLibsAndroidStudio 默認(rèn)提供的ndk 目錄,用來存放已經(jīng)編譯好的.so 文件鸯两,當(dāng)然你也可以放在任意自定義目錄下闷旧,例如src/main/libs,然后在build.gradle 中指定相應(yīng)的資源目錄位置即可:

android { 
    sourceSets.main { 
        // 你的.so庫的實(shí)際路徑 
        jniLibs.srcDir 'src/main/libs' 
    }
}

在導(dǎo)入.so 文件完成之后钧唐,那么你可以在相應(yīng)的java 類文件中忙灼,加載這個(gè)靜態(tài)庫,一般來說,.so 文件如果由第三方提供该园,他在提供.so 文件的同時(shí)也會(huì)提供相應(yīng)的java 調(diào)用類文件酸舍,或者按之前雙方定好的規(guī)則自己創(chuàng)建相應(yīng)類文件,并生成相應(yīng)的方法里初,之所以要約定好只因?yàn)椋?code>NDK 下的C/C++
函數(shù)和Java 橋接的函數(shù)命名是有約束的啃勉,規(guī)則如下:
Java_PackageName_ClassName_MethodName

雙方必須按這個(gè)規(guī)則來實(shí)現(xiàn)或者調(diào)用此函數(shù),否則不會(huì)成功双妨,例如淮阐,我們現(xiàn)在有一個(gè)函數(shù):String stringFromJNI()java函數(shù),它在com.example.hellojni.HelloJni 這個(gè)文件下刁品,這個(gè)函數(shù)用來返回一個(gè)字符串泣特,功能由底層C 來實(shí)現(xiàn),那么相應(yīng)的C 語言jni 開發(fā)文件中就必須按上述規(guī)則命名一個(gè)Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz) 的函數(shù)挑随,并返回一個(gè)字符串結(jié)果:

#include 
// 函數(shù)名格式必須按規(guī)矩來
jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz)
{ 
    return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");
}

同樣對(duì)應(yīng)的java 文件也必須:

  1. 文件必須在com.example.hellojni 包名下
  2. 類文件名必須是HelloJni
  3. 方法名必須是stringFromJNI
package com.example.hellojni;

class HelloJni { 
    public static native String stringFromJNI(); 

    static { 
        // 加載 hellojni.so靜態(tài)塊 
        System.loadLibrary("hellojni"); 
    }
}

2.2 有源碼状您,需要編譯.so

文件
如果有 C/C++ 源碼,沒有.so 文件镀裤,那么我們就得手動(dòng)把源碼文件編譯成.so 文件竞阐,編譯的方式也分為兩種:
手工執(zhí)行命令經(jīng)行編譯
使用gradle 腳本自動(dòng)實(shí)現(xiàn)編譯

AndroidStudio 默認(rèn)的源碼存放目錄是:

src/main/jni

如果你沒發(fā)現(xiàn)此目錄,那么你可以手動(dòng)創(chuàng)建一個(gè)暑劝,把所有的 C/C++ 源碼放在此文件下骆莹,當(dāng)然并非必須要放在此目錄下,你可以自定義目錄担猛,然后在build.gradle 中做一個(gè)資源路徑指定即可:

// build.gradle
android { 
    sourceSets.main { 
        // 你的源碼目錄 
        jni.srcDir 'src/main/otherDir' 
    }
}

2.2.1 手工執(zhí)行命令經(jīng)行編譯

在使用手工編譯(C/C++)文件之前幕垦,我們要回到文章開頭部分,我們需要配置好系統(tǒng)環(huán)境變量傅联,這樣我們才能在系統(tǒng)環(huán)境下執(zhí)行ndk相關(guān)編譯命令先改,如果您的環(huán)境變量還沒有配置,那么可以參考下文章開頭部分蒸走,如果已經(jīng)做好這部分工作仇奶,那么咱們繼續(xù)。

接下來比驻,我們還要?jiǎng)?chuàng)建如下兩個(gè)文件:

  1. Android.mk
  2. Applicatoin.mk (非必要)

2.2.1.1 創(chuàng)建 Android.mk

Android.mk 文件用來指定源碼編譯的配置信息该溯,例如工作目錄,編譯模塊的名稱别惦,參與編譯的文件等狈茉,大致內(nèi)容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello_jni
LOCAL_SRC_FILES := hello_jni.c
include $(BUILD_SHARED_LIBRARY)

1. LOCAL_PATH:設(shè)置工作目錄,而 my-dir 則會(huì)返回 Android.mk 文件所在的目錄掸掸。
2. CLEAR——VARS:清除幾乎所有以 LOCAL——PATH 開頭的變量(不包括 LOCAL_PATH)氯庆。
3. LOCAL_MODULE:用來設(shè)置模塊的名稱蹭秋。
4. LOCAL_SRC_FILES:用來指定參與模塊編譯的 C/C++ 源文件名。
5. BUILD_SHARED_LIBRARY:作用是指定生成的靜態(tài)庫或者共享庫在運(yùn)行時(shí)依賴的共享庫模塊列表堤撵。

2.2.1.2 創(chuàng)建 Application.mk

這個(gè)文件用來配置編譯平臺(tái)相關(guān)內(nèi)容仁讨,我們最常用的估計(jì)只是APP_ABI
字段,它用來指定我們需要基于哪些 CPU 架構(gòu)的.so 文件粒督,當(dāng)然你可以配置多個(gè)平臺(tái):

APP_ABI := armeabi armeabi-v7a x86 mips

如果不創(chuàng)建Application.mk 文件陪竿,那么手動(dòng)編譯的.so 文件只有armeabi 平臺(tái)一個(gè)版本,其他平臺(tái)的不會(huì)被編譯屠橄。
假設(shè)我們配置好了Android.mk 文件,那么接下來我們就可以執(zhí)行如下命令來生成.so 文件了闰挡,我們假設(shè)開發(fā)NDK
的目錄為默認(rèn)目錄:

cd src/main/jni/
ndk-build

如果順利锐墙,那么你將會(huì)看到,在src/main/ 目錄下會(huì)多了一個(gè)libs 目錄长酗,這是NDK 使用命令編譯.so 文件的生成的默認(rèn)目錄溪北,而AndroidSutdio 默認(rèn)加載NDK 的目錄是jniLibs,那么你有兩種解決方式:

  1. 配置build.gradle 資源目錄夺脾,參見文章 2.1 小節(jié)
  2. 使用 ndk-build NDK_LIBS_OUT=../jniLibs指定具體的輸出目錄

生成.so后之拨,為了避免C/C++文件被Java編譯,可能需要使用如下gradle 配置:

    sourceSets.main {
        // default .so path
        jniLibs.srcDir 'src/main/libs'
        // disable automatic ndk-build
        jni.srcDirs = []
    }

當(dāng)你得到了.so 文件咧叭,那么接下來就是在java 文件中調(diào)用執(zhí)行即可蚀乔,如果想了解更多ndk-build 命令內(nèi)容,可參見:Android ndk-build 使用文檔

2.2.2 使用 gradle 腳本

當(dāng)然該機(jī)器做的事我們還是盡量讓機(jī)器來做菲茬,因此吉挣,接下來我打算使用build.gradle 來添加一些配置,讓Gradle 自動(dòng)幫我完成編譯工作婉弹,這簡直就是爽歪歪啦睬魂!
使用gradle, 你再也不用手動(dòng)添加Android.mkApplication.mk 文件,一切在build.gradle 文件中就都能搞定镀赌,在這里我們直接貼出build.gradle 中ndk 相關(guān)的配置:

android.ndk { 
    // 模塊名稱 
    moduleName = "hello-jni" 

    // 指定編譯平臺(tái)氯哮,更多平臺(tái)信息 參見https://developer.android.com/ndk/guides/abis.html#sa 
    abiFilters "armeabi", "armeabi-v7a" 
    /* * Other ndk flags configurable here are 
    * cppFlags.add("-fno-rtti") 
    * cppFlags.add("-fno-exceptions") 
    * ldLibs.addAll(["android", "log"]) 
    * stl = "system" 
    */ 
}

使用gradle 的好處是,自動(dòng)編譯生成apk 文件商佛,并且把相關(guān)的.so 文件打包到apk 安裝包中喉钢,一勞永逸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末威彰,一起剝皮案震驚了整個(gè)濱河市出牧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歇盼,老刑警劉巖舔痕,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡伯复,警方通過查閱死者的電腦和手機(jī)慨代,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啸如,“玉大人侍匙,你說我怎么就攤上這事《vǎ” “怎么了想暗?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帘不。 經(jīng)常有香客問我说莫,道長,這世上最難降的妖魔是什么寞焙? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任储狭,我火速辦了婚禮,結(jié)果婚禮上捣郊,老公的妹妹穿的比我還像新娘辽狈。我一直安慰自己,他們只是感情好呛牲,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布刮萌。 她就那樣靜靜地躺著,像睡著了一般侈净。 火紅的嫁衣襯著肌膚如雪尊勿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天畜侦,我揣著相機(jī)與錄音元扔,去河邊找鬼。 笑死旋膳,一個(gè)胖子當(dāng)著我的面吹牛澎语,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播验懊,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼擅羞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了义图?” 一聲冷哼從身側(cè)響起减俏,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碱工,沒想到半個(gè)月后娃承,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奏夫,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年历筝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酗昼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梳猪,死狀恐怖麻削,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情春弥,我是刑警寧澤呛哟,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站惕稻,受9級(jí)特大地震影響竖共,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俺祠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望借帘。 院中可真熱鬧蜘渣,春花似錦、人聲如沸肺然。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽际起。三九已至拾碌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間街望,已是汗流浹背校翔。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灾前,地道東北人防症。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像哎甲,于是被迫代替她去往敵國和親蔫敲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • Android游戲開發(fā)實(shí)踐(1)之NDK與JNI開發(fā)02 承接上篇Android游戲開發(fā)實(shí)踐(1)之NDK與JNI...
    AlphaGL閱讀 3,740評(píng)論 0 24
  • 前段時(shí)間由于做比賽的事炭玫,一直都沒時(shí)間寫博客奈嘿,現(xiàn)在終于可以補(bǔ)上一篇了,一直想學(xué)習(xí)一點(diǎn)NDK開發(fā)的知識(shí)吞加,但是遲遲沒有動(dòng)...
    冰鑒IT閱讀 1,743評(píng)論 7 18
  • 一裙犹、NDK產(chǎn)生的背景 Android平臺(tái)從誕生起尽狠,就已經(jīng)支持C、C++開發(fā)伯诬。眾所周知晚唇,Android的SDK基于J...
    Ten_Minutes閱讀 3,479評(píng)論 1 27
  • 動(dòng)態(tài)注冊(cè)JNI函數(shù) 其實(shí)NDK開發(fā)具體操作在NDK官網(wǎng)Guides中已經(jīng)有了很詳細(xì)的介紹。盗似。這里主要記錄一下我自己...
    Gabo閱讀 1,160評(píng)論 1 48
  • 2017年11月7日 今天是換食第一天早餐過后沒有什么異常的感覺哩陕,午餐后午休時(shí)蓋著熱護(hù)毯做擺動(dòng)的時(shí)候就迷迷糊糊地睡...
    CiCi愛美麗閱讀 292評(píng)論 0 0