Android Studio 2.2以上支持了Cmake的配置JNI的相關參數,簡化了通過Android.mk配置。並很好的繼承了C++的編輯方式。以下是對應的引入第三方so和第三方.cpp文件的路徑腳本編寫。對應於:CMakeLists.txt
設置CMake插件的版本
# 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.
#語法,參考:https://cmake.org/cmake/help/latest/command/add_library.html
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
# 語法#########################################
# 示例
add_library(
#編譯生成的庫的名稱,注意最終生成時會在前面加`lib`.
# Specifies the name of the library.
native-lib
# Sets the library as a shared library.
# 生成的庫的類型,有SHARED,STATIC,MODULE
SHARED
# Provides a relative path to your source file(s).
# 要編譯的源代碼文件
src/main/cpp/native-lib.cpp )
包含要編譯的源碼頭文件
如果有源碼文件有頭文件,自然需要包含:
# 語法, 參考:https://cmake.org/cmake/help/latest/command/include_directories.html
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
# 語法#########################################
# Specifies a path to native header files.
# 注意這里指定的是頭文件的目錄
include_directories(src/main/cpp/include/)
使用NDK中的Api
有時候我們發現需要使用到NDK中定義的Api,因為NDK中的API都已經是編譯好的,而且CMake會自動去NDK目錄中查找這些我們需要使用的庫,所以這里只需要提供庫的名稱就可以了,一下舉例加載NDK中的log庫,因為我們在NDK開發中,總是少不了要打印日志的。
- 首先查找要使用的庫,使用變量保存它的路徑。
# 語法,參考:https://cmake.org/cmake/help/latest/command/find_library.html # A short-hand signature is: # name1 保存庫路徑的變量 find_library (<VAR> name1 [path1 path2 ...]) # The general signature is: find_library ( <VAR> name | NAMES name1 [name2 ...] [NAMES_PER_DIR] [HINTS path1 [path2 ... ENV var]] [PATHS path1 [path2 ... ENV var]] [PATH_SUFFIXES suffix1 [suffix2 ...]] [DOC "cache documentation string"] [NO_DEFAULT_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_CMAKE_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] [NO_CMAKE_SYSTEM_PATH] [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | NO_CMAKE_FIND_ROOT_PATH] ) # 語法######################################### # 示例 # Searches for a specified prebuilt library and stores the path as a # variable. Because system libraries are included in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log ) 為了編譯時可以使用,需要將上面一步找到的庫鏈接到我們要編譯的庫中。 # 語法,參考: https://cmake.org/cmake/help/latest/command/target_link_libraries.html target_link_libraries(<target> ... <item>... ...) # 語法 end ####################### # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in the # build script, prebuilt third-party libraries, or system libraries. # 注意這里可以同時鏈接多個庫 target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. # 此處使用上面保存的變量 ${log-lib} )
NDK中也有一些庫是以源代碼的方式存在的,這個時候如果我們要使用它,就需要把它編譯到一個本地靜態庫中,再鏈接到我們要生成的庫中。
# 這樣就會在\app\.externalNativeBuild\cmake\debug\${ANDROID_ABI}\ 目錄下生成libapp-glue.a/靜態庫 add_library( app-glue # 以靜態的方式添加 STATIC # 該源碼用於管理`NativeActivity`生命周期事件和觸摸事件 ${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} )
添加第三方的庫
使用add_library添加第三庫
# 語法,因為已經編譯好了,所以使用`IMPORTED`關鍵字
add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED [GLOBAL])
# 示例
add_library( imported-lib SHARED IMPORTED )
當第三方庫有針對不同架構編譯了不同的庫版本時,有時候我們只需要引入我們想要的版本的庫,當我們想要引入多個版本的庫時,可以使用ANDROID_ABI變量,它表示默認的ABI架構和NDK支持的架構,如果我們在build.gradle中設置了過濾值,則表示過濾后的架構集合。
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是在項目的app目錄下的 imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
同時為了在編譯時的使用,我們需要導入所依賴的庫的頭文件
include_directories( imported-lib/include/ )
添加鏈接,以便在編譯的時候使用,注意如果要添加的第三方庫在編譯我們要產出的庫時不需要直接用到(比如一個庫是imported-lib所依賴的),則不需要執行以下步驟。
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
在build.gradle中配置編譯庫的腳本
android {
......
defaultConfig {
......
//在默認配置中配置 cmake 的一些參數
externalNativeBuild {
cmake {
arguments "-DANDROID_TOOLCHAIN=clang"
cFlags ""
cppFlags ""
}
}
//ndk 配置
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'
}
}
//配置庫編譯的腳本
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
//定義不同的產品類型(多渠道打包),通過復寫externalNativeBuild,使用target字段實現打包不同的so庫。
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"
}
}
}
}
}
