Android JNI開發(fā)工具篇(1)-開發(fā)環(huán)境搭建

原文出處:http://www.ccbu.cc/index.php/android/android-jni-dev-env.html

工欲善其事死相,必先利其器

1. 開發(fā)環(huán)境準(zhǔn)備

搭建開發(fā)環(huán)境是我們進(jìn)行開發(fā)前首先要完成的任務(wù)榆俺,進(jìn)行Android jni開發(fā),依賴的基本開發(fā)環(huán)境包括:

  1. Android sdk
  2. android ndk
  3. cmake
  4. android studio

Android studio的sdk manager已經(jīng)包括了上面所說的sdk,ndk,cmake等工具的安裝抵乓,所以一般只用下載android studio店归,然后再使用sdk manager工具下載這些工具就可以了。

默認(rèn)情況下醒叁,Android studio使用的編譯工具是cmake司浪,但很多沿用的項目都是使用NDK的ndk-build工具來編譯的,所以android studio也支持ndk-build把沼。

2. 使用android studio創(chuàng)建本地C++工程

1.新建工程啊易, 在向?qū)У?Choose your project 部分中,選擇Natvie C++ 項目類型 饮睬。

2.在設(shè)置工程名租谈,包名,保存路徑和語言续捂,此處我們選擇Java語言垦垂。

3.在向?qū)У?Customize C++ Support 部分中,可以選則C++ Toolchain牙瓢,一般情況下劫拗,選擇默認(rèn)就可以,如果開發(fā)中需要用到C++11,或者c++14等一些較高級的C++標(biāo)準(zhǔn)的特性時矾克,可以選擇對應(yīng)的Toolchain页慷。

4.點擊finish,開始構(gòu)建工程,工程構(gòu)建完成以后酒繁,整個項目及其gradle配置文件如下:

默認(rèn)情況下滓彰,Android studio使用cmake編譯鏈工具,通過gradle腳本進(jìn)行配置州袒,默認(rèn)cmake配置如下:

externalNativeBuild {
    cmake {
        path "src/main/cpp/CMakeLists.txt"
        version "3.10.2"
    }
}

cmake文件和c++源代碼都在src/main/cpp/目錄下揭绑。

Android studio也支持ndk-buid,根據(jù)實際需求郎哭,我們也可以配置為ndk-build他匪,當(dāng)然,這需要我們先寫好對應(yīng)的Android.mkAppplication.mk(可選)配置文件夸研,然后通過修改gradle配置中的externalNativeBuild配置項來進(jìn)行更改邦蜜。配置為nkd-build編譯工具,則其配置文件如下:

externalNativeBuild {
    ndkBuild {
        path file('src/main/cpp/Android.mk')
    }
}

3. 使用現(xiàn)有android studio工程鏈接C++工程

當(dāng)一個普通的不帶C++本地庫支持的項目需要引入一個現(xiàn)有的c++本地庫時亥至,可以使用android studio的Link C++ Psroject with Gradle功能來導(dǎo)入一個本地C++庫悼沈,導(dǎo)入的庫需要提供可用的cmake配置文件或Android.mk配置文件,導(dǎo)入工作是通過加載這些本地庫編譯配置文件來完成的姐扮。

4.在android studio配置javah工具

在Settings->Tools->External Tools下創(chuàng)建NDK group,在NDK group下創(chuàng)建javah工具絮供。

詳細(xì)的配置參數(shù)如下:

配置項 參數(shù)
Programe $JDKPath$\bin\javah.exe
Arguments -classpath $ModuleFileDir$\src\main\java -jni -d $ModuleFileDir$\src\main\cpp $FileClass$
Working directory $FileDir$

使用時,只需要在定義了native方法的java類上右鍵選擇NDK->javah即可生成對應(yīng)的c++本地函數(shù)定義的頭文件溶握。

截圖中例子中杯缺,TestJni.java定義了本地函數(shù)add

package com.android.jnitest;

public class TestJni {
    public native int add(int a, int b);
}

使用javah生成的對應(yīng)本地c++頭文件com_android_jnitest_TestJni.h內(nèi)容如下:

#include <jni.h>
/* Header for class com_android_jnitest_TestJni */

#ifndef _Included_com_android_jnitest_TestJni
#define _Included_com_android_jnitest_TestJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_jnitest_TestJni
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_android_jnitest_TestJni_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

5. 工程配置

5.1 可選參數(shù)配置

可以在模塊級 build.gradle 文件的 defaultConfig 塊中配置另一個 externalNativeBuild 塊,為 CMake 或 ndk-build 指定可選參數(shù)和標(biāo)記 睡榆。

android {
    ...
    defaultConfig {
        ...
        // This block is different from the one you use to link Gradle
        // to your CMake or ndk-build script.
        externalNativeBuild {
          // For ndk-build, instead use the ndkBuild block.
          cmake {
            // Passes optional arguments to CMake.
            arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
            // Sets a flag to enable format macro constants for the C compiler.
            cFlags "-D__STDC_FORMAT_MACROS"
            // Sets optional flags for the C++ compiler.
            cppFlags "-fexceptions", "-frtti"
          }
        }
    }
    ...
}

通過上面的配置萍肆,可用對cmake的編譯選項及C和C++編譯選項做一些配置。

5.2 指定 ABI

默認(rèn)情況下胀屿,Gradle 會針對 NDK 支持的應(yīng)用二進(jìn)制接口 (ABI) 將您的原生庫編譯到單獨的 .so 文件中塘揣,并將這些文件全部打包到您的 APK 中。如果您希望 Gradle 僅編譯和打包原生庫的部分 ABI 配置宿崭,您可以在模塊級文件 build.gradle 中使用 ndk.abiFilters 標(biāo)記指定這些配置亲铡,如下所示:

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
        cmake {...}
        // or ndkBuild {...}
        }

        // Similar to other properties in the defaultConfig block,
        // you can configure the ndk block for each product flavor
        // in your build configuration.
        ndk {
        // Specifies the ABI configurations of your native
        // libraries Gradle should build and package with your APK.
        abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
        'arm64-v8a'
        }
    }
    buildTypes {...}
    externalNativeBuild {...}
}

6. 原生庫支持

Android NDK 會提供一組隨著新的 Android API 級別的后續(xù)發(fā)布而逐漸添加的原生標(biāo)頭和共享庫文件。 請執(zhí)行以下兩個基本步驟的操作葡兑,以便讓您的應(yīng)用使用 NDK 提供的庫:

  1. 在您的代碼中添加與您想使用的庫關(guān)聯(lián)的標(biāo)頭奖蔓。

  2. 通知編譯系統(tǒng)您的原生模塊需要在加載時鏈接庫。

    • 如果您使用的是 ndk-build:將原生庫添加到您 Android.mk 文件中的 LOCAL_LDLIBS 變量中讹堤。例如吆鹤,要鏈接 /system/lib/libfoo.so,請?zhí)砑右韵逻@行代碼:
    LOCAL_LDLIBS := -lfoo  
    

    要列出多個庫洲守,請使用空格作為分隔符疑务。

    • 如果您使用的是 CMake沾凄,向 CMake 編譯腳本添加 find_library() 命令以找到 NDK 庫并將其路徑存儲為一個變量。

      find_library( # Defines the name of the path variable that stores the
                        # location of the NDK library.
                        log-lib
                        # Specifies the name of the NDK library that
                        # CMake needs to locate.
                        log )
      

      然后再 CMake 腳本中的 target_link_libraries() 命令來關(guān)聯(lián)庫:

      target_link_libraries( # Specifies the target library.
                                 native-lib
                                 # Links the log library to the target library.
                                 ${log-lib} )
      

常用的android原生庫包括以下一些:

API級別 庫名 鏈接代碼 說明
3 C 庫 系統(tǒng)自動添加知允,無需配置
3 動態(tài)鏈接器庫 LOCAL_LDLIBS := -ldl 動態(tài)鏈接器的 dlopen(3) 和 dlsym(3) 功能
3 Android日志庫 LOCAL_LDLIBS := -llog 原生代碼向 logcat 發(fā)送日志消息
3 ZLib 壓縮庫 LOCAL_LDLIBS := -lz
4 OpenGL ES 1.x LOCAL_LDLIBS := -lGLESv1_CM
5 OpenGL ES 2.0 LOCAL_LDLIBS := -lGLESv2
8 jnigraphics LOCAL_LDLIBS += -ljnigraphics
9 EGL LOCAL_LDLIBS += -lEGL 分配和管理 OpenGLES 表面的原生平臺接口
9 OpenSL ES LOCAL_LDLIBS += -lOpenSLES 原生音頻處理庫
9 Android 原生應(yīng)用api LOCAL_LDLIBS += -landroid 使用原生代碼編寫整個 Android 應(yīng)用
14 OpenMAX AL LOCAL_LDLIBS += -lOpenMAXAL 原生多媒體處理庫
14 OpenSL ES LOCAL_LDLIBS += -lOpenSLES 增加了 PCM 支持
18 OpenGL ES 3.0 LOCAL_LDLIBS := -lGLESv3
21 OpenGL ES 3.1 LOCAL_LDLIBS := -lGLESv3
24 OpenGL ES 3.2 LOCAL_LDLIBS := -lGLESv3

7. C++ 庫支持

7.1 C++ 運行時庫

NDK 支持多種 C++ 運行時庫撒蟀。

名稱 庫文件 功能
libc++ 共享庫為 libc++_shared.so
靜態(tài)庫為 libc++_static.a
C++17 支持。
system /system/lib/libstdc++.so newdelete温鸽。(在 r18 中已棄用保屯。)
none 無頭文件,有限 C++嗤朴。

libc++

libc++ 同時提供靜態(tài)庫和共享庫 配椭。LLVM 的 libc++ 是 C++ 標(biāo)準(zhǔn)庫虫溜,自 Lollipop 以來 Android 操作系統(tǒng)便一直使用該庫雹姊,并且從 NDK r18 開始成為 NDK 中唯一可用的 STL。libc++ 的共享庫為 libc++_shared.so衡楞,靜態(tài)庫為 libc++_static.a吱雏。

system

系統(tǒng)運行時指的是 /system/lib/libstdc++.so。請勿將該庫與 GNU 的全功能 libstdc++ 混淆瘾境。在 Android 系統(tǒng)中歧杏,libstdc++ 只是 newdelete。對于全功能 C++ 標(biāo)準(zhǔn)庫迷守,請使用 libc++犬绒。

none

不包括STL。在這種情況下兑凿,沒有關(guān)聯(lián)或授權(quán)要求凯力。不提供 C++ 標(biāo)準(zhǔn)頭文件。

7.2 配置C++ 運行時

如果您要使用 CMake礼华,則可使用模塊級 build.gradle 文件中的 ANDROID_STL 變量咐鹤,指定表表格中的一個運行時 。如果您要使用 ndk-build圣絮,則可使用 Application.mk 文件中的 APP_STL 變量指定表 1 中的一個運行時祈惶。

APP_STL := c++_shared

只能為應(yīng)用選擇一個運行時,并且只能在 Application.mk 中進(jìn)行選擇扮匠。

7.3 共享運行時

如果應(yīng)用包括多個共享庫捧请,則應(yīng)使用 libc++_shared.so

在 Android 系統(tǒng)中棒搜,NDK 使用的 libc++ 不是操作系統(tǒng)的一部分疹蛉。這使得 NDK 用戶能夠獲得最新的 libc++ 功能和問題修復(fù)程序,即使應(yīng)用以舊版 Android 為目標(biāo)帮非。需要權(quán)衡的是氧吐,如果使用 libc++_shared.so讹蘑,則必須將其納入 APK 中。如果使用 Gradle 編譯應(yīng)用筑舅,則此步驟會自動完成座慰。

7.4 C++ 異常

C++ 異常受 libc++ 支持,但其在 ndk-build 中默認(rèn)為停用狀態(tài)翠拣。這是因為之前 NDK 并不支持 C++ 異常版仔。CMake 和獨立工具鏈默認(rèn)啟用 C++ 異常。

要在 ndk-build 中針對整個應(yīng)用啟用異常误墓,請將下面這一行代碼添加至 Application.mk 文件:

APP_CPPFLAGS := -fexceptions

要針對單一 ndk-build 模塊啟用異常蛮粮,請將下面這一行代碼添加至相應(yīng)模塊的Android.mk中:

LOCAL_CPP_FEATURES := exceptions

或者,您可以使用:

LOCAL_CPPFLAGS := -fexceptions

7.4 RTTI

與異常一樣谜慌,RTTI 也受 libc++ 支持然想,但在 ndk-build 中默認(rèn)為停用狀態(tài)。CMake 和獨立工具鏈默認(rèn)啟用 RTTI欣范。

要在 ndk-build 中針對整個應(yīng)用啟用 RTTI变泄,請將下面這一行代碼添加至 Application.mk文件:

APP_CPPFLAGS := -frtti    

要針對單一 ndk-build 模塊啟用 RTTI,請將下面這行代碼添加至相應(yīng)模塊的 Android.mk中:

LOCAL_CPP_FEATURES := rtti    

或者恼琼,您可以使用:

LOCAL_CPPFLAGS := -frtti

參考:

將 Gradle 關(guān)聯(lián)到您的原生庫

向您的項目添加 C 和 C++ 代碼

Android NDK 原生 API

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妨蛹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晴竞,更是在濱河造成了極大的恐慌蛙卤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噩死,死亡現(xiàn)場離奇詭異颤难,居然都是意外死亡,警方通過查閱死者的電腦和手機甜滨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門乐严,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衣摩,你說我怎么就攤上這事昂验。” “怎么了艾扮?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵既琴,是天一觀的道長。 經(jīng)常有香客問我泡嘴,道長甫恩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任酌予,我火速辦了婚禮磺箕,結(jié)果婚禮上奖慌,老公的妹妹穿的比我還像新娘。我一直安慰自己松靡,他們只是感情好简僧,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雕欺,像睡著了一般岛马。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屠列,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天啦逆,我揣著相機與錄音,去河邊找鬼笛洛。 笑死夏志,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撞蜂。 我是一名探鬼主播盲镶,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蝌诡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起枫吧,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤浦旱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后九杂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颁湖,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年例隆,在試婚紗的時候發(fā)現(xiàn)自己被綠了甥捺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡镀层,死狀恐怖镰禾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唱逢,我是刑警寧澤吴侦,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站坞古,受9級特大地震影響备韧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痪枫,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一织堂、第九天 我趴在偏房一處隱蔽的房頂上張望叠艳。 院中可真熱鬧,春花似錦易阳、人聲如沸虑绵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翅睛。三九已至,卻和暖如春黑竞,著一層夾襖步出監(jiān)牢的瞬間捕发,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工很魂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扎酷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓遏匆,卻偏偏與公主長得像法挨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子幅聘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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