要爲您的應用編譯和調試原生代碼,您須要如下組件:html
您能夠使用 SDK 管理器安裝這些組件:java
1.在打開的項目中,從菜單欄選擇 Tools > Android > SDK Manager。android
2.點擊 SDK Tools 標籤。git
3.選中 LLDB、CMake 和 NDK 旁的複選框,如圖 1 所示github
圖 1. 從 SDK 管理器中安裝 LLDB、CMake 和 NDK。api
4.點擊 Apply,而後在彈出式對話框中點擊 OK。架構
5.安裝完成後,點擊 Finish,而後點擊 OK。oracle
建立支持原生代碼的項目與建立任何其餘 Android Studio 項目相似,不過前者還須要額外幾個步驟:app
-fexceptions
標誌添加到模塊級 build.gradle
文件的 cppFlags
中,Gradle 會將其傳遞到 CMake。-frtti
標誌添加到模塊級 build.gradle
文件的 cppFlags
中,Gradle 會將其傳遞到 CMake。在 Android Studio 完成新項目的建立後,請從 IDE 左側打開 Project 窗格並選擇 Android 視圖。如圖 2 中所示,Android Studio 將添加 cpp 和 External Build Files 組:框架
注:此視圖沒法反映磁盤上的實際文件層次結構,而是將類似文件分到一組中,簡化項目導航。
native-lib.cpp
,並將其置於應用模塊的 src/main/cpp/
目錄中。本示例代碼提供了一個簡單的 C++ 函數 stringFromJNI()
,此函數能夠返回字符串「Hello from C++」。要了解如何向項目添加其餘源文件,請參閱介紹如何建立新的原生源文件的部分。build.gradle
文件指示 Gradle 如何構建應用同樣,CMake 和 ndk-build 須要一個構建腳原本瞭解如何構建您的原生庫。對於新項目,Android Studio 會建立一個 CMake 構建腳本 CMakeLists.txt
,並將其置於模塊的根目錄中。要詳細瞭解此構建腳本的內容,請參閱介紹如何建立 Cmake 構建腳本的部分。點擊 Run 後,Android Studio 將在您的 Android 設備或者模擬器上構建並啓動一個顯示文字「Hello from C++」的應用。下面的概覽介紹了構建和運行示例應用時會發生的事件:
CMakeLists.txt
。native-lib.cpp
編譯到共享的對象庫中,並命名爲 libnative-lib.so
,Gradle 隨後會將其打包到 APK 中。MainActivity
會使用 System.loadLibrary()
加載原生庫。如今,應用可使用庫的原生函數 stringFromJNI()
。MainActivity.onCreate()
調用 stringFromJNI()
,這將返回「Hello from C++」並使用這些文字更新 TextView
。注:Instant Run 與使用原生代碼的項目不兼容。Android Studio 會自動停用此功能。
若是您想要驗證 Gradle 是否已將原生庫打包到 APK 中,可使用 APK 分析器:
1.選擇 Build > Analyze APK。
2.從 app/build/outputs/apk/
目錄中選擇 APK 並點擊 OK。
3.如圖 3 中所示,您會在 APK 分析器窗口的 lib/<ABI>/
下看到 libnative-lib.so
圖 3. 使用 APK 分析器定位原生庫。
提示:若是您想要試驗使用原生代碼的其餘 Android 應用,請點擊 File > New > Import Sample 並從 Ndk 列表中選擇示例項目。
若是您但願向現有項目添加原生代碼,請執行如下步驟:
CMakeLists.txt
構建腳本或者使用 ndk-build 幷包含 Android.mk
構建腳本,則能夠跳過此步驟。配置完項目後,您可使用 JNI 框架從 Java 代碼中訪問您的原生函數。要構建和運行應用,只需點擊 Run 。Gradle 會以依賴項的形式添加您的外部原生構建流程,用於編譯、構建原生庫並將其隨 APK 一塊兒打包。
要在應用模塊的主源代碼集中建立一個包含新建原生源文件的 cpp/
目錄,請按如下步驟操做:
cpp
)並點擊 OK。native-lib
。.cpp
。
.cxx
或 .hxx
。在彈出的 C/C++ 對話框中,從 Source Extension 和 Header Extension 下拉菜單中選擇另外一個文件擴展名,而後點擊 OK。若是您的原生源文件尚未 CMake 構建腳本,則您須要自行建立一個幷包含適當的 CMake 命令。CMake 構建腳本是一個純文本文件,您必須將其命名爲 CMakeLists.txt
。本部分介紹了您應包含到構建腳本中的一些基本命令,用於在建立原生庫時指示 CMake 應使用哪些源文件。
注:若是您的項目使用 ndk-build,則不須要建立 CMake 構建腳本。提供一個指向您的 Android.mk
文件的路徑,將 Gradle 關聯到您的原生庫。
要建立一個能夠用做 CMake 構建腳本的純文本文件,請按如下步驟操做:
注:您能夠在所需的任意位置建立構建腳本。不過,在配置構建腳本時,原生源文件和庫的路徑將與構建腳本的位置相關。
如今,您能夠添加 CMake 命令,對您的構建腳本進行配置。要指示 CMake 從原生源代碼建立一個原生庫,請將 cmake_minimum_required()
和 add_library()
命令添加到您的構建腳本中:
# Sets the minimum version of CMake required to build your native library. # This ensures that a certain set of CMake features is available to # your build. cmake_minimum_required(VERSION 3.4.1) # Specifies a library name, specifies whether the library is STATIC or # SHARED, and provides relative paths to the source code. You can # define multiple libraries by adding multiple add.library() commands, # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. add_library( # Specifies the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp )
使用 add_library()
向您的 CMake 構建腳本添加源文件或庫時,Android Studio 還會在您同步項目後在 Project 視圖下顯示關聯的標頭文件。不過,爲了確保 CMake 能夠在編譯時定位您的標頭文件,您須要將 include_directories()
命令添加到 CMake 構建腳本中並指定標頭的路徑:
add_library(...)
# Specifies a path to native header files.
include_directories(src/main/cpp/include/)
CMake 使用如下規範來爲庫文件命名:
lib庫名稱.so
例如,若是您在構建腳本中指定「native-lib」做爲共享庫的名稱,CMake 將建立一個名稱爲 libnative-lib.so
的文件。不過,在 Java 代碼中加載此庫時,請使用您在 CMake 構建腳本中指定的名稱:
static { System.loadLibrary(「native-lib」); }
注:若是您在 CMake 構建腳本中重命名或移除某個庫,您須要先清理項目,Gradle 隨後纔會應用更改或者從 APK 中移除舊版本的庫。要清理項目,請從菜單欄中選擇 Build > Clean Project。
Android Studio 會自動將源文件和標頭添加到 Project 窗格的 cpp 組中。使用多個 add_library()
命令,您能夠爲 CMake 定義要從其餘源文件構建的更多庫。
Android NDK 提供了一套實用的原生 API 和庫。經過將 NDK 庫包含到項目的 CMakeLists.txt
腳本文件中,您可使用這些 API 中的任意一種。
預構建的 NDK 庫已經存在於 Android 平臺上,所以,您無需再構建或將其打包到 APK 中。因爲 NDK 庫已是 CMake 搜索路徑的一部分,您甚至不須要在您的本地 NDK 安裝中指定庫的位置 - 只須要向 CMake 提供您但願使用的庫的名稱,並將其關聯到您本身的原生庫。
將 find_library()
命令添加到您的 CMake 構建腳本中以定位 NDK 庫,並將其路徑存儲爲一個變量。您可使用此變量在構建腳本的其餘部分引用 NDK 庫。如下示例能夠定位 Android 特定的日誌支持庫並將其路徑存儲在 log-lib
中:
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 )
爲了確保您的原生庫能夠在 log
庫中調用函數,您須要使用 CMake 構建腳本中的 target_link_libraries()
命令關聯庫:
find_library(...) # Links your native library against one or more other native libraries. target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. ${log-lib} )
NDK 還以源代碼的形式包含一些庫,您在構建和關聯到您的原生庫時須要使用這些代碼。您可使用 CMake 構建腳本中的 add_library()
命令,將源代碼編譯到原生庫中。要提供本地 NDK 庫的路徑,您可使用 ANDROID_NDK
路徑變量,Android Studio 會自動爲您定義此變量。
如下命令能夠指示 CMake 構建 android_native_app_glue.c
,後者會將 NativeActivity
生命週期事件和觸摸輸入置於靜態庫中並將靜態庫關聯到 native-lib
:
add_library( app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ) # You need to link static libraries against your shared native library. target_link_libraries( native-lib app-glue ${log-lib} )
添加預構建庫與爲 CMake 指定要構建的另外一個原生庫相似。不過,因爲庫已經預先構建,您須要使用 IMPORTED
標誌告知 CMake 您只但願將庫導入到項目中:
add_library( imported-lib
SHARED
IMPORTED )
而後,您須要使用 set_target_properties()
命令指定庫的路徑,以下所示。
某些庫爲特定的 CPU 架構(或應用二進制接口 (ABI))提供了單獨的軟件包,並將其組織到單獨的目錄中。此方法既有助於庫充分利用特定的 CPU 架構,又能讓您僅使用所需的庫版本。要向 CMake 構建腳本中添加庫的多個 ABI 版本,而沒必要爲庫的每一個版本編寫多個命令,您可使用 ANDROID_ABI
路徑變量。此變量使用 NDK 支持的一組默認 ABI,或者您手動配置 Gradle 而讓其使用的一組通過篩選的 ABI。例如:
add_library(...) set_target_properties( # Specifies the target library. imported-lib # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import.
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libimported-lib.so ) #CMAKE_SOURCE_DIR 變量爲當前cmake文件所在的目錄
爲了確保 CMake 能夠在編譯時定位您的標頭文件,您須要使用 include_directories()
命令,幷包含標頭文件的路徑:
include_directories( imported-lib/include/ )
注:若是您但願打包一個並非構建時依賴項的預構建庫(例如在添加屬於 imported-lib
依賴項的預構建庫時),則不須要執行如下說明來關聯庫。
要將預構建庫關聯到您本身的原生庫,請將其添加到 CMake 構建腳本的 target_link_libraries()
命令中:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
在您構建應用時,Gradle 會自動將導入的庫打包到 APK 中。您可使用 APK 分析器驗證 Gradle 將哪些庫打包到您的 APK 中。如需瞭解有關 CMake 命令的詳細信息,請參閱 CMake 文檔。
要將 Gradle 關聯到您的原生庫,您須要提供一個指向 CMake 或 ndk-build 腳本文件的路徑。在您構建應用時,Gradle 會以依賴項的形式運行 CMake 或 ndk-build,並將共享的庫打包到您的 APK 中。Gradle 還使用構建腳原本瞭解要將哪些文件添加到您的 Android Studio 項目中,以便您能夠從 Project 窗口訪問這些文件。若是您的原生源文件沒有構建腳本,則須要先建立 CMake 構建腳本,而後再繼續。
將 Gradle 關聯到原生項目後,Android Studio 會更新 Project 窗格以在 cpp 組中顯示您的源文件和原生庫,在 External Build Files 組中顯示您的外部構建腳本。
注:更改 Gradle 配置時,請確保經過點擊工具欄中的 Sync Project 應用更改。此外,若是在將 CMake 或 ndk-build 腳本文件關聯到 Gradle 後再對其進行更改,您應當從菜單欄中選擇 Build > Refresh Linked C++ Projects,將 Android Studio 與您的更改同步。
您可使用 Android Studio UI 將 Gradle 關聯到外部 CMake 或 ndk-build 項目:
1.從 IDE 左側打開 Project 窗格並選擇 Android 視圖。
2.右鍵點擊您想要關聯到原生庫的模塊(例如 app 模塊),並從菜單中選擇 Link C++ Project with Gradle。您應看到一個如圖 4 所示的對話框。
3.從下拉菜單中,選擇 CMake 或 ndk-build。
1.若是您選擇 CMake,請使用 Project Path 旁的字段爲您的外部 CMake 項目指定 CMakeLists.txt
腳本文件。
2.若是您選擇 ndk-build,請使用 Project Path 旁的字段爲您的外部 ndk-build 項目指定 Android.mk
腳本文件。若是 Application.mk
文件與您的 Android.mk
文件位於相同目錄下,Android Studio 也會包含此文件。
圖 4. 使用 Android Studio 對話框關聯外部 C++ 項目
4.點擊ok。
要手動配置 Gradle 以關聯到您的原生庫,您須要將 externalNativeBuild {}
塊添加到模塊級 build.gradle
文件中,並使用 cmake {}
或 ndkBuild {}
對其進行配置:
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path "CMakeLists.txt" } } }
注:若是您想要將 Gradle 關聯到現有 ndk-build 項目,請使用 ndkBuild {}
塊而不是 cmake {}
,並提供 Android.mk
文件的相對路徑。若是 Application.mk
文件與您的 Android.mk
文件位於相同目錄下,Gradle 也會包含此文件。
您能夠在模塊級 build.gradle
文件的 defaultConfig {}
塊中配置另外一個 externalNativeBuild {}
塊,爲 CMake 或 ndk-build 指定可選參數和標誌。與 defaultConfig {}
塊中的其餘屬性相似,您也能夠在構建配置中爲每一個產品風味重寫這些屬性。
例如,若是您的 CMake 或 ndk-build 項目定義多個原生庫,您可使用 targets
屬性僅爲給定產品風味構建和打包這些庫中的一部分。如下代碼示例說明了您能夠配置的部分屬性:
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 ndkBuild {} cmake { // Passes optional arguments to CMake. arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang" // Sets optional flags for the C compiler. cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2" // Sets a flag to enable format macro constants for the C++ compiler. cppFlags "-D__STDC_FORMAT_MACROS" } } } buildTypes {...} productFlavors { ... demo { ... externalNativeBuild { cmake { ... // Specifies which native libraries to build and package for this // product flavor. If you don't configure this property, Gradle // builds and packages all shared object libraries that you define // in your CMake or ndk-build project. targets "native-lib-demo" } } } paid { ... externalNativeBuild { cmake { ... targets "native-lib-paid" } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
要詳細瞭解配置產品風味和構建變體,請參閱配置構建變體。如需瞭解您可使用 arguments
屬性爲 CMake 配置的變量列表,請參閱使用 CMake 變量。
默認狀況下,Gradle 會針對 NDK 支持的 ABI 將您的原生庫構建到單獨的 .so
文件中,並將其所有打包到您的 APK 中。若是您但願 Gradle 僅構建和打包原生庫的特定 ABI 配置,您能夠在模塊級 build.gradle
文件中使用 ndk.abiFilters
標誌指定這些配置,以下所示:
android { ... defaultConfig { ... externalNativeBuild { cmake {...} // or ndkBuild {...} } 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 {...} }
在大多數狀況下,您只須要在 ndk {}
塊中指定 abiFilters
(如上所示),由於它會指示 Gradle 構建和打包原生庫的這些版本。不過,若是您但願控制 Gradle 應當構建的配置,並獨立於您但願其打包到 APK 中的配置,請在 defaultConfig.externalNativeBuild.cmake {}
塊(或 defaultConfig.externalNativeBuild.ndkBuild {}
塊中)配置另外一個 abiFilters
標誌。Gradle 會構建這些 ABI 配置,不過僅會打包您在 defaultConfig.ndk{}
塊中指定的配置。
爲了進一步下降 APK 的大小,請考慮配置 ABI APK 拆分,而不是建立一個包含原生庫全部版本的大型 APK,Gradle 會爲您想要支持的每一個 ABI 建立單獨的 APK,而且僅打包每一個 ABI 須要的文件。若是您配置 ABI 拆分,但沒有像上面的代碼示例同樣指定 abiFilters
標誌,Gradle 會構建原生庫的全部受支持 ABI 版本,不過僅會打包您在 ABI 拆分配置中指定的版本。爲了不構建您不想要的原生庫版本,請爲 abiFilters
標誌和 ABI 拆分配置提供相同的 ABI 列表。
Demo:
https://github.com/derek022/voicer/blob/master/app/CMakeLists.txt