天天看點

安卓JNI精細化講解,讓你徹底了解JNI(一):環境搭建與HelloWord

目錄

1、基礎概念

├──1.1、JNI

├──1.2、NDK

├──1.3、CMake與ndk-build

2、環境搭建

3、Native C++ 項目(HelloWord案例)

├── 3.1、項目建立(java、kotlin)

├── 3.2、CMake的應用(詳細講解)

├── 3.3、ndk-build的應用(詳細講解)

JNI(Java Native Interface)Java本地接口,使得Java與C/C++具有互動能力
NDK(Native Development Kit) 本地開發工具包,允許使用原生語言(C和C++)來實作應用程式的部分功能

Android NDK開發的主要作用:

當我們基于NDK開發出native功能後,通常需要編譯成庫檔案,給Android項目使用。

目前,有兩種主流的編譯方式:CMake__與__ndk-build

__CMake__與__ndk-build__是兩種不同的編譯工具(與Android代碼和C/C++代碼無關)

CMake

ndk-build

JNI安裝 JNI 是JDK裡的内容,電腦上正确安裝并配置JDK即可 (JDK1.1之後就正式支援了);
NDK安裝 可從官網自行下載下傳、解壓到本地,也可基于AndroidStudio下載下傳解壓到預設目錄;
編譯工具安裝 cmake 可基于AndroidStudio下載下傳安裝; ndk-build 是NDK裡的腳本工具,NDK安裝好即可使用ndk-build;

目前示範,使用的Android Studio版本如下(目前最新版):

啟動Android Studio --> 打開SDK Manager --> SDK Tools,如下圖所示:

我們選擇NDK、CMake、LLDB(調試Native時才會使用),選擇Apply進行安裝,等安裝成功後,NDK開發所依賴的環境也就都齊全了。

建立項目,選擇 Native C++,如下圖:

新建立的項目,預設已包含完整的native 示例代碼、cmake配置 ,如下圖:

這樣,我們就可以自己定義Java native方法,并在cpp目錄中寫native實作了,很友善。

但是,當我們寫完native的實作代碼,希望運作APP,檢視JNI的互動效果,此時,就需要使用編譯工具了,咱們還是先看一下Android Studio預設的Native編譯方式吧:CMake

在CMake編譯之前,咱們應該先做哪些準備工作?

除此之外,咱們還應該學習CMake的哪些重要知識?

帶着這些問題,咱們開始CMake之旅吧:

3.2.1、NDK環境檢查

編譯前,建議先檢查下工程的NDK配置情況(不然容易報一些亂七八糟的錯誤):

File --> Project Structure --> SDK Location,如下圖(我本地的Android Studio預設沒有給配置NDK路徑,那麼,需要自己手動指定一下):

3.2.2、C/C++功能實作

因為本節主講CMake編譯工具,代碼就不單獨寫了,咱們直接使用工程預設生成的native-liv.cpp,簡單調整一下native實作方法的代碼吧(修改傳回文本資訊):

因Native C++工程預設已配置好了CMakeLists.txt和gradle,是以咱們可直接運作工程看效果,如下圖:

JNI互動效果我們已經看到了,說明CMake編譯成功了。那麼,這究竟是怎麼做到的呢?咱們接着分析一下吧:

3.2.3、CMake生成的庫檔案與apk中的庫檔案

安卓工程編譯時,會執行CMake編譯,在 工程/app/build/.../cmake/ 中會産生對應的so檔案,如下圖:

繼續編譯安卓工程,會根據build中的内容,生成我們的*.apk安裝封包件。我們找到、反編譯apk安裝封包件,查找so庫檔案。原來在apk安裝包中,so庫都被存放在lib目錄中,如下圖:

3.2.4、CMake是如何編譯生成so庫的呢?

在前面介紹CMake定義時,提到了CMake是基于CMakeLists.txt檔案和gradle配置實作編譯Native類的。那麼,咱們先來看一下CMakeLists.txt檔案吧:

實際上,CMakeList.txt可配置的内容遠不止這些,如:so輸出目錄,生成規則等等,有需要的同學可查下官網。

接着,咱們再看一下app的gradle又是如何配置CMake的呢?

實際上,gradle可配置的cmake内容也遠不止這些,如:abi、cppFlags、arguments等,有需要的同學可查下官網。

3.2.5、如何指定庫檔案的輸出目錄?

如果希望将so庫生成到特定目錄,并讓項目直接使用該目錄下的so,應該如何配置呢?

比較簡單:需要在CMakeList.txt中配置庫的輸出路徑資訊,即:

CMAKE_LIBRARY_OUTPUT_DIRECTORY

還需要在gradle中配置 jniLibs.srcDirs 屬性(即:指定了lib庫目錄):

接着,重新build就會在cpp相同目錄級别位置生成jniLibs目錄,so庫也在其中了:

3.2.5、如何生成指定CPU平台對應的庫檔案呢?

我們可以在cmake中設定abiFilters,也可在ndk中設定abiFilters,效果是一樣的:

按照新的配置,我們重新運作工程,如下圖:

再反編譯看下工程,果然隻有arm64-v8a的so庫了,不過庫檔案在apk中仍然是放在lib目錄,而非jniLibs(其實也很好了解,jniLibs隻是我們本地的目錄,便于我們管理庫檔案,真正生成apk時,仍然會按照lib目錄放置庫檔案),如下圖:

至此,CMake的主要技術點都講完了,接下來咱們看下NDK-Build吧~

3.3、ndk-build的應用

在ndk-build編譯之前,咱們又應該先做哪些準備工作?

除此之外,咱們還應該學習ndk-build的哪些重要知識?

帶着這些問題,咱們繼續ndk-build之旅吧:

3.3.1、環境變量配置

介紹NDK-Build定義時,提到了其實它是NDK的腳本工具。那麼,咱們還是先進NDK目錄找一下吧,ndk-build工具的位置如下圖:

如果我們希望任意情況下都能便捷的使用這種腳本工具,通常做法是配置其環境變量,否則我們在cmd、Mac終端、Terminal中執行 ndk-build 指令時,會報錯:“未找到指令”

配置NDK的環境變量,也很簡單,以Mac電腦舉例(如果是Windows電腦,網上也有很多關于配置環境變量的文章,如果有需要可自行查下):

當我們在cmd、Mac終端、Terminal中執行 ndk-build 指令時,如果出現下圖所示内容,則代表配置成功了:

3.3.2、C/C++功能實作

咱們使用比較常用的一種ndk-build方式吧:ndk-build + Android.mk + gradle配置

項目中建立jni目錄,拷貝一份CMake的代碼實作吧:

接着,編寫Android.mk檔案内容:

配置gradle:

現在,native代碼、ndk-build配置都完成了,咱們運作看一下效果吧,如下圖:

3.3.4、如何指定庫檔案的輸出目錄?

通常,可在Android.mk檔案中配置NDK_APP_DST_DIR

指定源目錄與輸出目錄(與CMake類似)

3.3.5、如何生成指定CPU平台對應的庫檔案呢?

可在gradle中配置abiFilters(與Cmake類似)

3.3.6、如何在Terminal中直接通過ndk-build指令建構庫檔案呢?

除了執行AndroidStudio的build指令,基于gradle配置 + Android.mk編譯生成庫檔案,我們還可以在cmd、Mac 終端、Terminal中直接通過ndk-build指令建構庫檔案,此處以Terminal為例進行示範吧:

先進入包含Android.mk檔案的jni目錄(Android Studio中可直接選中jni目錄并拖拽到Terminal中,會自動跳轉到該目錄),再執行ndk-build指令,如下圖:

同樣,編譯也成功了,如下圖:

因是直接在Terminal中執行了ndk-build指令,是以隻會根據Android.mk進行編譯(不包含gradle配置内容,也就不會執行abiFilters過濾),生成了所有預設CPU平台的so庫檔案。

ndk-build指令其實也可以配上一些參數使用,此處就不再詳解了。日常開發時,還是建議選擇CMake作為Native編譯工具,因為是安卓主推的,而且更簡單一些。

繼續閱讀