前言
完成C基本文法的學習之後,就進入了NDK的正式開發,在Android Studio2.2及以上時android支援了Android Studio + CMake來開發 NDK,我們将用這兩個工具進行NDK開發。
沒有接觸過c/c++ 基礎的可以看下我上一篇文章 我的NDK之旅– (1) c語言基礎
可以科學上網的可以參照 android官方NDK開發文檔
相關概念認知
- 交叉編譯
- 在一個平台上去編譯另一個平台上可以執行的本地代碼
- 在NDK中指針對cpu平台編譯 arm x86 mips
-
.so檔案 (動态連結庫)
編譯c或c++代碼生成的檔案
-
native 關鍵字
本地方法聲明。
工具準備
- 需要工具
- NDK
- CMake
- 工具擷取
- 打開android studio 2.2 以上版本
- 打開settings
- 打開Android SDK
- 切換到SDK tools
- 勾選 CMake LLDB NDk
- 點選應用,等待安裝完成
CMAke :CMake是一款開源的跨平台自動化建構系統,它通過CMakeLists.txt來聲明建構的行為,控制整個編譯流程,我們在接下來的NDK開發中将會使用它配合Gradle來進行相關開發。
LLDB:LLDB是一個高效的c/c++的調試器
第一個NDkDemo
現在就讓我們打開android studio開始第一個NDK項目吧
勾選 include c++ support
選擇C++ standard
* 這裡選擇預設的CMake的設定
* Exceptions Support是添加C++中對于異常的處理,如果選中,Android Studio會
将 -fexceptions标志添加到子產品級build.gradle檔案的cppFlags中,Gradle會将其傳遞到CMake。
- Runtime Type Information Support是啟用支援RTTI,如果選中,Android Studio會将-frtti标志添加到子產品級build.gradle檔案的cppFlags中,Gradle會将其傳遞到 CMake。
自動建構完成
點選Finish按鈕等待android studio 自動建構完成,運作程式即可看到效果,這樣就完成了第一個NDK項目:
代碼分析
将代碼切換成Project模式
代碼改變
我們可以發現在代碼中增加了CMakeLists.txt,以及main下cpp的檔案夾。接下來我們将逐個分析
CMakeLists.txt
CMakeLists.txt 是在NDK是定義打包.so 檔案建構行為
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
# 設定在編譯本地庫時最小的CMake版本
cmake_minimum_required(VERSION .)
add_library( # Sets the name of the library.
# 用來設定編譯生成的本地庫的名字為native-lib
native-lib
# Sets the library as a shared library.
# SHARED表示編譯生成的是動态連結庫
SHARED
# Provides a relative path to your source file(s).
# 表示參與編譯的檔案的路徑,這裡面可以寫多個檔案的路徑。
src/main/cpp/native-lib.cpp )
# find_library:添加一些我們在編譯我們的本地庫的時候需要依賴的一些庫 ,cmake已經知道系統庫的路徑,這裡的意思是指定使用log庫,然後給log庫起别名為log-lib便于我們後面引用
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 )
# 關聯我們自己的庫和一些第三方庫或者系統庫,這裡把我們把自己的庫native-lib庫和log庫關聯起來。
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
子產品下 build.gradle
- 在android 的defaultConfig大括号内:cmake的配置資訊如果勾選了異常支援和RTTI支援,這裡就會有相關的配置資訊。
externalNativeBuild {
cmake {
cppFlags ""
}
}
- android 大括号内:CMakeLists.txt檔案的路徑,這裡是指檔案相對于build.gradle檔案的位置,由于build.gradle檔案和CMakeLists.txt檔案在同一目錄下,是以此處就直接寫檔案名。
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
MainActivity
- 在靜态代碼塊中加載編譯生成的動态庫,native-lib,即我們在CMakeLists.txt檔案中指定的名稱
static {
System.loadLibrary("native-lib");
}
- 聲明需要實作的本地方法,即 native 方法
public native String stringFromJNI();
FirstNDKDemo\app\src\main\cpp
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_aj_firstndkdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
cpp : 使用c++語言編寫
方法名命名規則:Java_包名類名方法名 的形式
JNIEnv *env :是JniNativeInterface這個結構體的一級指針,JniNativeInterface這個結構體定義了大量的函數指針,env 就是結構體JniNativeInterface這個結構體的二級指針,(*env)->調用結構體中的函數指針
jobject: 調用本地函數的java對象就是這個jobject
實踐:
- 上面的demo都是由android studio 自動建構的,對于一個動手能力的強的程式猿來說肯定不夠,接下來我們就一起寫個hello world的NDK程式。
- 首先我們在cpp檔案夾下建立一個helloworld.c ,代碼如下
#include <jni.h> JNIEXPORT jstring JNICALL Java_com_aj_firstndkdemo_MainActivity_helloworld(JNIEnv *env, jobject instance) { return (*env)->NewStringUTF(env,"hello world !"); }
- 修改CMakeLists.txt 檔案,加入我們添加的類
add_library( # Sets the name of the library. # 用來設定編譯生成的本地庫的名字為native-lib native-lib # Sets the library as a shared library. # SHARED表示編譯生成的是動态連結庫 SHARED # Provides a relative path to your source file(s). # 表示參與編譯的檔案的路徑,這裡面可以寫多個檔案的路徑。 src/main/cpp/native-lib.cpp src/main/cpp/helloworld.c )
- 在activity中聲明native方法
` public native String helloworld();
- 接下來調用就好了,然後就可以運作了
開發流程總結
- 在CMakeLists.txt 聲明編譯成的本地庫名字
- 建立c或c++檔案并在CMakeLists.txt中聲明
- 在java代碼中加載編譯生成的本地庫(可用靜态代碼塊)
- 在java中聲明需要用到的本地方法,并在對應的c檔案中根據命名規則建立對應的方法(android studio中按住Alt + Enter 可自動建立避免錯誤)
- 修改CMakeLists.txt 檔案,加入我們添加的類