android studio 使用CMAKE

原文地址

前言

之前,每次需要邊寫C++代碼的時候,我的內心都是拒絕的。 
1. 它沒有代碼提示!!!這意味着我們必須自己手動敲出所有的代碼,對於一個新手來說,要一個字母都不錯且大小寫也要正確,甚至要記得住所有的jni函數等,真是太折磨人了…平時寫Java代碼的時候都是寫幾個字母會出來一大堆提示然後選擇的,這樣還有一個好處就是很多時候我們不知道有那些函數,但是我們可以通過obj.,然後就可以看到它有哪些方法函數了。 
2. 很多地方會顯示爲紅色,就像是錯誤提示的那種,當然,如果沒錯的話還是能編譯運行的,但是如果像編寫java代碼一樣,寫錯的地方纔給我紅色顯示不是更好嗎? 
這兩個問題可折磨死我這個強迫症了…在網上百度了很久如何能夠使用Android Studio編寫C++代碼時有代碼提示自動補全功能,但是一直沒有找到有效的(不使用CMake的情況下,若有人知道,麻煩告知)。好在一次偶然的機會,在網上看到在 Android Studio 2.2 中愉快地使用 C/C++這篇文章,看到上面說Android Studio2.2版本完善了對C/C++的支持,還提及到CMAKE,趕緊把Android Studio從2.0版本升級到了2.2版本,按照介紹新建了一個NDK工程,發現裏面居然有我夢寐以求的C++代碼自動補全提示!!!喜大普奔!!! 
趕緊了解學習下Android Studio2.2版本提供的CMAKE方式。打算以後都使用這種方式了,別的不說,就衝可以有C++代碼自動補全提示這個功能我就愛上它了。

工具安裝

Android Studio升級到2.2之後,我們可以先配置好NDK開發的一些所需工具,如圖,在SDK Tools中勾選安裝CMake、LLDB、NDK。 
這裏寫圖片描述

CMake: 外部構建工具。如果你準備只使用 ndk-build 的話,可以不使用它。  
LLDB: Android Studio上面調試本地代碼的工具。

Android Studio自帶DEMO瞭解CMAKE

Android Studio升級到2.2版本之後,在創建新的project時,界面上多了一個Include C++ Support的選項。勾選它之後將會創建一個默認的C++與JAVA混編的Demo程序。就讓我們先來看看這個官方標準Demo吧。

開始之前最好先下載好NDK,見NDK開發 從入門到放棄(一:基本流程入門瞭解),即在Project Structure界面Android NDK location處下載或選擇正確的路徑。或者使用上方提供的工具安裝方法來進行下載。否則,創建的新project也會報錯,需要配置好後clean。

File -> New -> New Project,在如下界面中勾選Include C++ Support,然後一路 Next,直到 Finish 爲止即可。 
這裏寫圖片描述
項目打開後我們查看目錄結構,與常規項目不同的是多了.externalNativeBuild文件夾、cpp文件夾、CMakeLists.txt文件,如下圖: 
這裏寫圖片描述 
這三個東西都是NDK部分: 
1. .externalNativeBuild文件夾:cmake編譯好的文件, 顯示支持的各種硬件等信息。系統生成。 
2. cpp文件夾:存放C/C++代碼文件,native-lib.cpp文件是該Demo中自帶的,可更改。需要自己編寫。 
3. CMakeLists.txt文件:CMake腳本配置的文件。需要自己配置編寫。

Gradle中也有兩處不同: 
這裏寫圖片描述

java代碼:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    // Example of a call to a native method
    TextView tv = (TextView) findViewById(R.id.sample_text);
    tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

從native-lib.cpp的代碼中我們能看到它使用的是靜態註冊的方式,動態註冊的方式代碼同傳統JNI。

#include <jni.h>
#include <string>

extern "C"
jstring
Java_com_example_person_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

CMakeLists.txt文件中我們需要注意的是下面這三個地方。兩個library的名字(需一致)以及一個cpp文件的路徑,彼此需要對應一致,當我們自己定義library以及自己創建cpp文件時需要對應修改。 
這裏寫圖片描述

運行代碼,就能看到效果,調用了C++方法在界面上顯示了Hello from C++字符串。這就是CMake方式進行NDK開發的Demo。 
還記得傳統JNI方式中嗎?我們使用了ndk -build來編譯C/C++文件爲so文件,對於使用過第三方庫的開發者來說,對so肯定不陌生。我們只能使用別人給的so文件,而無法看到C/C++源碼,更別說去修改了。但是在這裏我們好像一直沒看到so文件的影子,那麼,我們安裝運行的apk中,有對應的so文件嗎?如果想驗證一下apk是否有so文件,我們可以使用 APK Analyzer:

  1. 選擇 Build > Analyze APK。
  2. 選擇 apk,並點擊 OK。
  3. 如下圖,在 APK Analyzer 窗口中,選擇 lib/x86/,可以看見 libnative-lib.so 。 
    這裏寫圖片描述

Tips:Instant Run 並不兼容使用了 native code 的項目。Android Studio 會自動禁止 Instant Run 功能。

但是我個人目前更關注的問題是C++代碼自動補全提示的功能,當在cpp文件中寫代碼時,裏面不再是一大片的紅色,輸入若干個字母的時候,也能給出提示了,簡直叼渣天,至於原因…我就不清楚了,爲什麼在這裏就有這個強大的功能了呢?哪位大神能解釋下… 
這裏寫圖片描述

CMake編譯so文件

在Android Studio的Terminal中輸入cmake,會提示:

'cmake' 不是內部或外部命令,也不是可運行的程序或批處理文件。     
  • 1
  • 1

需要在下載配置好CMake的環境變量,若沒這個問題可跳過這個步驟。在如下網址中下載好對應的文件: 
https://cmake.org/download/ 
這裏寫圖片描述

下載zip包後,解壓縮。然後將cmake.exe所在的路徑,添加到path環境變量中。cmake就成爲有效命令了。


在CMakeLists.txt文件上級目錄下執行cmake .命令,報錯,暫未解決:

-- Building for: NMake Makefiles
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
CMake Error in CMakeLists.txt:
  The CMAKE_C_COMPILER:

    cl

  is not a full path and was not found in the PATH.

  To use the NMake generator with Visual C++, cmake must be run from a shell
  that can use the compiler cl from the command line.  This environment is
  unable to invoke the cl compiler.  To fix this problem, run cmake from the
  Visual Studio Command Prompt (vcvarsall.bat).

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


CMake Error in CMakeLists.txt:
  The CMAKE_CXX_COMPILER:

    cl

  is not a full path and was not found in the PATH.

  To use the NMake generator with Visual C++, cmake must be run from a shell
  that can use the compiler cl from the command line.  This environment is
  unable to invoke the cl compiler.  To fix this problem, run cmake from the
  Visual Studio Command Prompt (vcvarsall.bat).

  Tell CMake where to find the compiler by setting either the environment
  variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.


-- Configuring incomplete, errors occurred!
See also "E:/AndroidDemo_XY/app/CMakeFiles/CMakeOutput.log".
See also "E:/AndroidDemo_XY/app/CMakeFiles/CMakeError.log".
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

待完成


CMake和傳統 JNI在目錄結構和配置文件上的區別

現在我們有了CMake和傳統JNI兩種開發NDK的方法,它們在目錄結構和Gradle上有所區別,下面我們將分別介紹目錄區別和Gradle配置的區別。 
一、目錄結構 
傳統JNI 
這裏寫圖片描述 
CMake 
這裏寫圖片描述

這兩種方式在目錄上的區別就是兩點: 
1. 以前的jni目錄改成cpp,名字更換了,下面還是存放C/C++文件。  
2. 之前對C/C++文件的編譯配置Android.mk、Application.mk文件放在jni目錄下,現在改成CMakeLists.txt文件。(事實上這些文件的位置是可任意存放的,只需要配置好就行。但最好還是按照默認習慣放置。)

二、Gradle 
傳統JNI 
這裏寫圖片描述

CMake 
這裏寫圖片描述

事實上,我們在使用傳統JNI方式的時候,上面的兩處地方我們都省略了,也不會造成什麼異常(若Android.mk存放位置在其他地方則需要配置)。CMake方式中第一處也可省略,但是第二處不能省略(同樣,位置路徑要寫對),因爲沒有它將無法Build生成.externalNativeBuild文件夾。

另外,傳統JNI開發還需要在項目根目錄下的gradle.properties文件中配置

android.useDeprecatedNdk=true
  • 1
  • 1

否則Build項目的時候會報錯。

CMake的優勢

  1. 可以直接的在C/C++代碼中加入斷點,進行調試
  2. java引用的C/C++中的方法,可以直接ctrl+左鍵進入
  3. 對於include的頭文件或者庫,也可以直接進入
  4. 不需要配置命令行操作,手動的生成頭文件,不需要配置android.useDeprecatedNdk=true屬性

普通Android項目轉NDK開發項目

我們之前說了,在創建新project時若勾選了Include C++ Support選項(需Android Studio版本不低於2.2),則該項目就已經是一個NDK開發項目了。那麼,若項目已經存在,該如何再轉爲NDK開發項目呢?

Tips: 在配置好NDK的前提下。且各種地方的配置均不再贅述。如Android.mk中如何配置、CMakeLists.txt文件中的配置、各個地方的統一等。

傳統JNI方式,在NDK開發 從入門到放棄(一:基本流程入門瞭解)中我們瞭解過:

  1. 新建jni目錄,寫好C/C++代碼。靜態註冊JNI時我們使用了javah -jni對JAVA類進行操作自動生成了jni目錄以及對應的頭文件(事實上,當我們有一定經驗後可以自己寫,而不再需要使用該輔助命令來保證不寫錯,另外動態註冊也是一個很值得提倡的方式),然後根據頭文件寫了C/C++代碼。但在動態註冊JNI時我們可以自己先創建好jni目錄且寫好C/C++代碼。
  2. 在jni目錄下創建且配置好Android.mk和Application.mk兩個文件。
  3. build.gradle文件中根據情況進行配置,可不進行配置使用默認值。
  4. 通過ndk-build操作,我們能得到對應的so文件,放置在相應位置,java代碼中即可調用C/C++代碼,運行程序。

回顧前面提到的CMake方式的NDK開發,我們得到如下步驟:

  1. 新建cpp目錄,寫好C/C++代碼。
  2. 創建且配置CMakeLists.txt文件。
  3. build.gradle文件中根據情況進行配置,CMakeLists.txt文件的路徑必須配置。
  4. java代碼中即可調用C/C++代碼,運行程序。
  5. project的build.gradle文件中,gradle版本不能低於2.2,否則會報錯。

Error: Could not find method externalNativeBuild() for arguments 
[build_e8k5d0w74qu1ajxjrrcr9snog$_run_closure1$_closure6@1398219d] on 
project ‘:app’ of type org.gradle.api.Project.。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章