前言
自Android Studio 2.2發布之后,AS開始支持CMake構建工具編譯構建原生代碼庫,谷歌推薦使用CMake來構建新建的原生庫,不過為了兼顧老項目,AS還是支持ndk-build構建,除此之外,谷歌還推出了實驗性Gradle插件來構建原生庫,至此AS工具支持3種方式來構建原生庫。
實驗性Gradle插件由于依賴開發中的Gradle API,所以它是不穩定的,不過谷歌稱Android Studio團隊會繼續支持實驗性Gradle插件,谷歌希望將來該插件能取代當前的Gradle插件,因為其緊密集成的特性對于C/C++開發者更為便利,例如,更靈活的依賴管理。因此,對于想在IDE與構建系統之間建立最靈活的接口的開發者,可以嘗試使用實驗性Gradle插件。
這里主要介紹下谷歌推薦的方式—Cmake。
PS:以下內容主要來自谷歌官方文檔。
1、CMake
1.1、構建工具準備
- 下載NDK:Android C/C++代碼工具集
- 下載Cmake:外部構建工具
- 下載LLDB:Android Studio 上面調試本地代碼的工具
使用 SDK Manager 來安裝上述組件:
- 打開一個項目,從菜單欄中選擇 Tools > Android > SDK Manager。
- 點擊 SDK Tools 選項卡。
- 勾選 LLDB,CMake 和 NDK。如圖:
1.2 創建 CMake 構建腳本
創建一個CMakeList.txt構建腳本文件,然后用CMake命令來配置腳本文件。
為了讓 CMake 將源代碼(native source code)編譯成 native library。需要在編譯文件中添加 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(),將一個源文件(source file)或庫添加到 CMake 構建腳本,同步項目,然后 Android studio 將關聯的頭文件也顯示了。然而,為了讓 CMake 在編譯時期能定位到頭文件,需要在 CMake 構建腳本中添加 include_directories() 命令,并指定頭文件路徑:
add_library(...)
# Specifies a path to native header files.
include_directories(src/main/cpp/include/)
1.3、添加 NDK APIs
Android NDK 提供了一些有用的 native APIs。將 NDK librarys 添加到 CMakeLists.txt 腳本文件中,就可以使用這些 API 了。
預編譯的 NDK librarys 已經存在在 Android 平臺中了,所以你不需要編譯它們,或者是將其打包到你的 APK 中。因為這些 NDK librarys 已經是 CMake 搜索路徑的一部分,你甚至不需要提供你本地安裝的 NDK 路徑。你只需要向 CMake 提供你想使用的 library 名字。
將 find_library() 命令添加到你的 CMake 構建腳本中,這樣就可以定位 NDK library 的位置,并將其位置存儲在一個變量之中。你可以在構建腳本的其他地方使用這個變量,來代指 NDK library。下面的示例代碼將 Android-specific log support library 的位置存儲到變量 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 )
NDK 同樣也包含一些只包含源碼的 library,這些就需要你去編譯,然后鏈接到你的本地庫(native library)。你可以在 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} )
1.4、添加其他的預編譯庫
添加預編譯庫和添加本地庫(native library)類似。由于預編譯庫是已經構建好的,你想就要使用 IMPORTED 標志去告訴 CMake ,你只需要將其導入到你的項目中即可:
add_library( imported-lib
SHARED
IMPORTED )
然后你需要使用 set_target_properties()
命令去指定庫的路徑,就像下面的代碼那樣。
一些庫會根據不同的 CPU 使用不同的包,或者是 Application Binary Interfaces(ABI)
,并且將他們歸類到不同的目錄中。這樣做的好處是,可以充分發揮特定的 CPU 架構。你可以使用 ANDROID_ABI
路徑變量,將多個 ABI 版本的庫添加到你的 CMake 構建腳本中。這個變量使用了一些 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.
imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
為了讓 CMake 在編譯時期能找到你的頭文件,你需要使用 include_directories() 命令,并且將你的頭文件地址傳進去:
nclude_directories( imported-lib/include/ )
在 CMake 構建腳本中使用 target_link_libraries() 命令,將預構建庫與你本地庫相關聯:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
當你構建你的 APP 的時候,Gradle 會自動將導入的庫打包到你的 APK 中。你可以使用 APK Analyzer 來檢查。
1.5、關聯本地庫與 Gradle
為了將本地庫與 Gradle 相關聯,你需要在 CMake 或 ndk-build 構建腳本中提供一個路徑地址。當你構建你的 APP 時,Gradle 會將 CMake 或 ndk-build 作為一個依賴運行,然后將共享庫(.so 文件)打包到你的 APK 中。
1.5.1、使用 Android Studio 圖形化界面
- 打開 IDE 左邊的 Project 面板,選擇 Android 視圖。
- 右鍵點擊你想鏈接本地庫的 module,比如 app module,然后從菜單中選擇 Link C++ Project with Gradle。你應該能看見一個和下圖很像的對話框。
- 在下拉菜單中,選擇 CMake 或者 ndk-build。
a. 如果你選擇 CMake,需要在 Project Path 中指定 CMakeLists.txt 腳本文件的路徑。
b. 如果你選擇 ndk-build,你需要在 Project Path 中指定 Android.mk 腳本文件的路徑。
1.6、手動配置 Gradle
如果要手動將 Gradle 與你的本地庫相關聯,你需要在 module 層級的 build.gradle 文件中添加 externalNativeBuild {} 代碼塊,并且在該代碼塊中配置 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"
}
}
}
1.6.1、可選配置
你可以在你的 module 層級的 build.gradle 文件中的 defaultConfig {} 代碼塊中,添加 externalNativeBuild {} 代碼塊,為 CMake 或 ndk-build 配置一些額外參數。當然,你也可以在你的構建配置中,為其他每一個生產渠道重寫這些屬性。
比如,如果你的 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 "-DCMAKE_VERBOSE_MAKEFILE=TRUE"
// 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"
}
}
}
}
// You use this block to link Gradle to your CMake or ndk-build script.
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
}
1.6.2、指定 ABI
如果你想 Gradle 構建并打包某個特定的 ABI 。你可以在你的 module 層級的 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 構建、依賴你希望的東西,你就需要在 defaultConfig.externalNativeBuild.cmake {} 代碼塊或 defaultConfig.externalNativeBuild.ndkBuild {} 代碼塊中,配置其他的 abiFilters 標簽。Gradle 會構建這些 ABI 配置,但是只會將 defaultConfig.ndk {} 代碼塊中指定的東西打包到 APK中。
官方文檔:
https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script
推薦一篇不錯的相關文章:
http://blog.csdn.net/mabeijianxi/article/details/68525164
2、ndk-build
ndk-build這里不做詳細介紹,請自行查看官方文檔:
https://developer.android.com/ndk/guides/ndk-build.html
3、experimental-gradle-plugin
experimental-gradle-plugin這里不做詳細介紹,請自行查看官方文檔:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental
官方網址可能打不開,可查看轉載網址:
http://www.cnblogs.com/tanlon/p/4731283.html