Android Studio 2.2 更方便地建立JNI專案-CMake
前段時間寫了篇Android Studio 第一個NDK例子,它是在使用
Android Studio2.1
版本的實現方案,最近發現2.2
穩定版本已經出來了,所以更新了版本,發現使用該版本建立Jni專案更加方便了。
使用Android Studio 2.2建立JNI專案(基於CMake)
1. 建立一個新專案(Create New Project)
點選File — New — New Project,把Include C++ Support
前面的CheckBook勾上。
接下來的步驟跟建立普通專案一樣。
2、配置C++支援功能(Customize C++ Support)
在Customize C++ Support介面預設即可。
-
C++ Standard
指定編譯庫的環境,其中Toolchain Default使用的是預設的CMake環境;C++ 11也就是C++環境。兩種環境都可以編庫,至於區別,後續會跟進,當前博文使用的是CMake環境。 -
Exceptions Support
如果選中複選框,則表示當前專案支援C++異常處理,如果支援,在專案Module級別的build.gradle
-fexceptions
到cppFlags
屬性中,並且在so庫構建時,gradle會把該屬性值傳遞給CMake進行構建。 -
Runtime Type Information Support
同理,選中複選框,專案支援RTTI,屬性cppFlags
增加標識-frtti
3、認識CMakeLists.txt構建指令碼檔案
CMakeLists.txt檔案用於配置JNI專案屬性,主要用於宣告CMake使用版本、so庫名稱、C/CPP檔案路徑等資訊,下面是該檔案內容:
# Sets the minimum version of CMake required to build the native # library. You should either keep the default value or only pass a # value of 3.4.0 or lower. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds it for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). # Associated headers in the same location as their source # file are automatically included. src/main/cpp/native-lib.cpp ) # 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 ) # 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 target library to the log library # included in the NDK. ${log-lib} )
-
cmake_minimum_required(VERSION 3.4.1)
CMake最小版本使用的是3.4.1。 -
add_library()
配置so庫資訊(為當前當前指令碼檔案新增庫)- native-lib
這個是宣告引用so庫的名稱,在專案中,如果需要使用這個so檔案,引用的名稱就是這個。值得注意的是,實際上生成的so檔名稱是libnative-lib。當Run專案或者build專案是,在Module級別的build檔案下的intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main
下會生成相應的so庫檔案。
- native-lib
-
SHARED
這個引數表示共享so庫檔案,也就是在Run專案或者build專案時會在目錄intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main
下生成so庫文。此外,so庫檔案都會在打包到.apk裡面,可以通過選擇選單欄的Build->Analyze Apk...*檢視apk中是否存在so庫檔案,一般它會存放在lib目錄下。 -
src/main/cpp/native-lib.cpp
構建so庫的原始檔。
STATIC:靜態庫,是目標檔案的歸檔檔案,在連結其它目標的時候使用。
SHARED:動態庫,會被動態連結,在執行時被載入。
MODULE:模組庫,是不會被連結到其它目標中的外掛,但是可能會在執行時使用dlopen-系列的函式動態連結。
更詳細的解釋請參考這篇文章:C++靜態庫與動態庫
- 標頭檔案
也可以配置標頭檔案路徑,方法是(注意這裡指定的是目錄而非檔案):
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
下面的配置實際上與自定義的JNI專案(自定義的so庫)沒有太大關係。
-
find_library()
這個方法與我們要建立的so庫無關而是使用NDK的Apis或者庫,預設情況下Android平臺集成了很多NDK庫檔案,所以這些檔案是沒有必要打包到apk裡面去的。直接宣告想要使用的庫名稱即可(猜測:貌似是在Sytem/libs目錄下)。在這裡不需要指定庫的路徑,因為這個路徑已經是CMake路徑搜尋的一部分。如示例中使用的是log相關的so庫。 -
log-lib
這個指定的是在NDK庫中每個型別的庫會存放一個特定的位置,而log庫存放在log-lib中 -
log
指定使用log庫 -
target_link_libraries()
如果你本地的庫(native-lib)想要呼叫log庫的方法,那麼就需要配置這個屬性,意思是把NDK庫關聯到本地庫。 -
native-lib
要被關聯的庫名稱 -
${log-lib}
要關聯的庫名稱,要用大括號包裹,前面還要有$符號去引用。
實際上,我們可以自己建立CMakeLists.txt檔案,而且路徑不受限制,只要在build.gradle中配置externalNativeBuild.cmake.path來指定該檔案路徑即可。
4、gradle指令碼引用CMakeLists.txt檔案
當Run或者Build專案時,想要執行CMakeLists.txt構建指令碼,需要把指令碼配置到模組級的build.gradle中。
android {
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
5、Run Module就能看到結果
6、拓展之構建NDK原始碼
實際上NDK除了有預置的庫還有一個原始碼(c/cpp),如果本地庫想要關聯這些程式碼可以這樣做:
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} )
-
app-glue
仍然是自定義庫的名稱 -
ANDROID_NDK
這個是Android Studio已經定義好的變數,可以直接使用它指定的是NDK原始碼的根目錄。
7、拓展之使用第三方so庫
在一些情況下,我們沒有能力開發so庫,當別人拋一個庫過來的時候我們直接使用就好了。
首先,我們告訴指令碼我們只需要匯入so庫,不需要構建操作。
add_library( imported-lib
SHARED
IMPORTED )
- IMPORTED
表示只需要匯入,不需要構建so庫。
接著,我們要設定so庫的路徑了
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
舉例:
set_target_properties(
imported-lib // so庫的名稱
PROPERTIES IMPORTED_LOCATION // import so庫
libs/libimported-lib.so // so庫路徑
)
當使用已經存在so庫時,不應該配置
target_link_libraries()
方法,因為只有在build 庫檔案時才能進行link操作。
拓展閱讀:https://developer.android.com/ndk/guides/build.html
作者:科大向陽
連結:https://www.jianshu.com/p/4eefb16d83e3
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授