1. 程式人生 > >Android Studio 2.2 更方便地建立JNI專案-CMake

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

    檔案中會增加一個標識 -fexceptionscppFlags屬性中,並且在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庫檔案。
  • 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來指定該檔案路徑即可。

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
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授