使用 AndroidStudio 進行 NDK 開發

AndroidStudio 中進行NDK 開發比起以往的Eclipse 要方便的多,下面來介紹下如何使用AndroidStudio 這個 IDE 工具實現NDK 相關開發工作。

1. 準備工作


在實際寫代碼之前,首先我們還是需要做一些準備工作:

  1. 下載NDK 開發包:Android 官方下載頁面
  2. 配置系統環境變量

下載好NDK 開發包之后,直接解壓到任意目錄,然后需要配置一下系統環境變量,之所以要配置環境變量,是為了方便使用命令ndk-build 腳本進行NDK 編譯。配置參考如下:

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

其實編譯C/C++代碼不一定在AndroidStudio 中,如果配置好環境變量,直接使用進入項目中的jni 目錄執行ndk-build 命令即可在當前目錄下生成一個libs 的目錄,里面存放了不同 平臺的.so 包,當然運行這個命令的前提是,這個目錄下至少得有一個Android.mk 文件,如果需要指定具體的編譯平臺,那么還需要添加一個Application.mk 文件,當然,如果命令行讓你頭疼,那么你可以采用gradle 的方式來解決這些問題,接下來我們將分別介紹這些使用方式。

2. 項目配置

使用AndroidStudio 開發前我們也要做點額外工作,我們需要在項目根目錄下local.properties 中添加編譯NDK 的路徑:

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

如果這個文件不存在,你可以手動生成一個,然后再添加上述內容即可。完成這個步驟之后,我們就可以正式開始著手NDK 相關的開發工作了。之所以要配置這個目錄,目的是讓我們開發的項目在使用 gradle 編譯時能夠找到NDK 相關編譯路徑

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

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

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

這類情況是最簡單的,.so 文件以及被其他人員編譯好,或者是第三方庫來提供的,那么我們只需要把相應.so 文件放到AndroidStudio 目錄src/main/jniLibs/ 下即可,當然,肯定需要按 CPU 架構分不同的子目錄。
jniLibsAndroidStudio 默認提供的ndk 目錄,用來存放已經編譯好的.so 文件,當然你也可以放在任意自定義目錄下,例如src/main/libs,然后在build.gradle 中指定相應的資源目錄位置即可:

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

在導入.so 文件完成之后,那么你可以在相應的java 類文件中,加載這個靜態庫,一般來說,.so 文件如果由第三方提供,他在提供.so 文件的同時也會提供相應的java 調用類文件,或者按之前雙方定好的規則自己創建相應類文件,并生成相應的方法,之所以要約定好只因為,NDK 下的C/C++
函數和Java 橋接的函數命名是有約束的,規則如下:
Java_PackageName_ClassName_MethodName

雙方必須按這個規則來實現或者調用此函數,否則不會成功,例如,我們現在有一個函數:String stringFromJNI()java函數,它在com.example.hellojni.HelloJni 這個文件下,這個函數用來返回一個字符串,功能由底層C 來實現,那么相應的C 語言jni 開發文件中就必須按上述規則命名一個Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz) 的函數,并返回一個字符串結果:

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

同樣對應的java 文件也必須:

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

class HelloJni { 
    public static native String stringFromJNI(); 

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

2.2 有源碼,需要編譯.so

文件
如果有 C/C++ 源碼,沒有.so 文件,那么我們就得手動把源碼文件編譯成.so 文件,編譯的方式也分為兩種:
手工執行命令經行編譯
使用gradle 腳本自動實現編譯

AndroidStudio 默認的源碼存放目錄是:

src/main/jni

如果你沒發現此目錄,那么你可以手動創建一個,把所有的 C/C++ 源碼放在此文件下,當然并非必須要放在此目錄下,你可以自定義目錄,然后在build.gradle 中做一個資源路徑指定即可:

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

2.2.1 手工執行命令經行編譯

在使用手工編譯(C/C++)文件之前,我們要回到文章開頭部分,我們需要配置好系統環境變量,這樣我們才能在系統環境下執行ndk相關編譯命令,如果您的環境變量還沒有配置,那么可以參考下文章開頭部分,如果已經做好這部分工作,那么咱們繼續。

接下來,我們還要創建如下兩個文件:

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

2.2.1.1 創建 Android.mk

Android.mk 文件用來指定源碼編譯的配置信息,例如工作目錄,編譯模塊的名稱,參與編譯的文件等,大致內容如下:

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:設置工作目錄,而 my-dir 則會返回 Android.mk 文件所在的目錄。
2. CLEAR——VARS:清除幾乎所有以 LOCAL——PATH 開頭的變量(不包括 LOCAL_PATH)。
3. LOCAL_MODULE:用來設置模塊的名稱。
4. LOCAL_SRC_FILES:用來指定參與模塊編譯的 C/C++ 源文件名。
5. BUILD_SHARED_LIBRARY:作用是指定生成的靜態庫或者共享庫在運行時依賴的共享庫模塊列表。

2.2.1.2 創建 Application.mk

這個文件用來配置編譯平臺相關內容,我們最常用的估計只是APP_ABI
字段,它用來指定我們需要基于哪些 CPU 架構的.so 文件,當然你可以配置多個平臺:

APP_ABI := armeabi armeabi-v7a x86 mips

如果不創建Application.mk 文件,那么手動編譯的.so 文件只有armeabi 平臺一個版本,其他平臺的不會被編譯。
假設我們配置好了Android.mk 文件,那么接下來我們就可以執行如下命令來生成.so 文件了,我們假設開發NDK
的目錄為默認目錄:

cd src/main/jni/
ndk-build

如果順利,那么你將會看到,在src/main/ 目錄下會多了一個libs 目錄,這是NDK 使用命令編譯.so 文件的生成的默認目錄,而AndroidSutdio 默認加載NDK 的目錄是jniLibs,那么你有兩種解決方式:

  1. 配置build.gradle 資源目錄,參見文章 2.1 小節
  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 = []
    }

當你得到了.so 文件,那么接下來就是在java 文件中調用執行即可,如果想了解更多ndk-build 命令內容,可參見:Android ndk-build 使用文檔

2.2.2 使用 gradle 腳本

當然該機器做的事我們還是盡量讓機器來做,因此,接下來我打算使用build.gradle 來添加一些配置,讓Gradle 自動幫我完成編譯工作,這簡直就是爽歪歪啦!
使用gradle, 你再也不用手動添加Android.mkApplication.mk 文件,一切在build.gradle 文件中就都能搞定,在這里我們直接貼出build.gradle 中ndk 相關的配置:

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

    // 指定編譯平臺,更多平臺信息 參見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 的好處是,自動編譯生成apk 文件,并且把相關的.so 文件打包到apk 安裝包中,一勞永逸。

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

推薦閱讀更多精彩內容

  • Android游戲開發實踐(1)之NDK與JNI開發02 承接上篇Android游戲開發實踐(1)之NDK與JNI...
    AlphaGL閱讀 3,771評論 0 24
  • 前段時間由于做比賽的事,一直都沒時間寫博客,現在終于可以補上一篇了,一直想學習一點NDK開發的知識,但是遲遲沒有動...
    冰鑒IT閱讀 1,788評論 7 18
  • 一、NDK產生的背景 Android平臺從誕生起,就已經支持C、C++開發。眾所周知,Android的SDK基于J...
    Ten_Minutes閱讀 3,530評論 1 27
  • 動態注冊JNI函數 其實NDK開發具體操作在NDK官網Guides中已經有了很詳細的介紹。。這里主要記錄一下我自己...
    Gabo閱讀 1,173評論 1 48
  • 2017年11月7日 今天是換食第一天早餐過后沒有什么異常的感覺,午餐后午休時蓋著熱護毯做擺動的時候就迷迷糊糊地睡...
    CiCi愛美麗閱讀 304評論 0 0