Android Studio 2.2 更方便地建立JNI項目-CMake

前段時間寫了篇Android Studio 第一個NDK例子,它是在使用Android Studio2.1版本的實現方案,最近發現2.2穩定版本已經出來了,因此更新了版本,發現使用該版本建立Jni項目更加方便了。html

使用Android Studio 2.2建立JNI項目(基於CMake)


1. 建立一個新項目(Create New Project)

點擊File — New — New Project,把Include C++ Support前面的CheckBook勾上。android

接下來的步驟跟建立普通項目同樣。app

二、配置C++支持功能(Customize C++ Support)

Customize C++ Support界面默認便可。ide

  • C++ Standard
    指定編譯庫的環境,其中Toolchain Default使用的是默認的CMake環境;C++ 11也就是C++環境。兩種環境均可以編庫,至於區別,後續會跟進,當前博文使用的是CMake環境函數

  • Exceptions Support
    若是選中複選框,則表示當前項目支持C++異常處理,若是支持,在項目Module級別的build.gradle文件中會增長一個標識 -fexceptionscppFlags屬性中,而且在so庫構建時,gradle會把該屬性值傳遞給CMake進行構建。gradle

  • Runtime Type Information Support
    同理,選中複選框,項目支持RTTI,屬性cppFlags增長標識-frttiui

三、認識CMakeLists.txt構建腳本文件

CMakeLists.txt文件用於配置JNI項目屬性,主要用於聲明CMake使用版本、so庫名稱、C/CPP文件路徑等信息,下面是該文件內容:spa

# 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庫信息(爲當前當前腳本文件添加庫)debug

    • native-lib
      這個是聲明引用so庫的名稱,在項目中,若是須要使用這個so文件,引用的名稱就是這個。值得注意的是,實際上生成的so文件名稱是libnative-lib。當Run項目或者build項目是,在Module級別的build文件下的intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main下會生成相應的so庫文件。
  • 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++靜態庫與動態庫

下面的配置實際上與自定義的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來指定該文件路徑便可。

四、gradle腳本引用CMakeLists.txt文件

Run或者Build項目時,想要執行CMakeLists.txt構建腳本,須要把腳本配置到模塊級的build.gradle中。

android {
    externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
}

五、Run Module就能看到結果

六、拓展之構建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源代碼的根目錄。

七、拓展之使用第三方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 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。

相關文章
相關標籤/搜索