在Eclipse
的時代,咱們進行NDK
的開發通常須要經過手動執行NDK
腳本生成*.so
文件,再將.so
文件放到對應的目錄以後,以後再進行打包。html
而若是使用的是Android Studio
進行NDK
開發,在2.2
的版本之後,咱們能夠不須要手動地運行NDK
腳原本生成*.so
文件,而是將這一過程做爲Gradle
構建過程的依賴項,事先編寫好編譯的腳本文件,而後在build.gradle
中指定編譯腳本文件的路徑就能夠一次性完成生成原生庫並打包成APK
的過程。java
目前這種AS + Gradle
的NDK
開發方式又能夠分爲三種:ndk-build
、CMake
和Experimental Gradle
:android
ndk-build
:和上面談到的傳統方式相比,它們兩個的目錄結構相同,Gradle
腳本其實最終仍是依賴於Android.mk
文件,對於使用傳統方式的項目來講,比較容易過分。CMake
:Gradle
腳本依賴的是CMakeLists.txt
文件。Experimental Gradle
:須要引入實驗性的gradle
插件,所有的配置均可以經過build.gradle
來完成,再也不須要編寫Android.mk
或者CMakeLists.txt
,可能坑比較多,對於舊的項目來講過分困難。目前,Android Studio
已經將CMake
做爲默認的NDK
實現方式,而且官網上對於NDK
的介紹也是基於CMake
,聲稱要永久支持。按照官方的教程使用下來,感受這種方式有幾點好處:android-studio
javah
根據java
文件生成頭文件,並根據頭文件生成的函數聲明編寫cpp
文件Java
文件中定義完native
接口,能夠在cpp
文件中自動生成對應的native
函數,所須要作的只是補全函數體中的內容ndk-build
命令獲得so
,再將so
拷貝到對應的目錄cpp
文件的過程當中,能夠有提示了CMakeLists.txt
要比Android.mk
更加容易理解下面,咱們就來介紹一下如何使用CMake
進行簡單的NDK
開發,整個內容主要包括兩個方面:bash
C/C++
的全新項目C/C++
代碼C/C++
的全新項目在新建項目以前,咱們須要經過SDK Manager
安裝一些必要的組件:app
NDK
CMake
LLDB
在安裝完必要的組件以後,咱們建立一個全新的工程,這裏須要記得勾選include C++ Support
選項: ide
Next
,在最後一步咱們會看見以下的幾個選項,它們的含義爲:
C++ Standard
:選擇C++
的標準,Toolchain Default
表示使用默認的CMake
配置,這裏咱們選擇默認。Excptions Support
:若是您但願啓用對C++
異常處理的支持,請選中此複選框。若是啓用此複選框,Android Studio
會將-fexceptions
標誌添加到模塊級 build.gradle
文件的cppFlags
中,Gradle
會將其傳遞到CMake
。Runtime Type information Support
:若是您但願支持RTTI
,請選中此複選框。若是啓用此複選框,Android Studio
會將-frtti
標誌添加到模塊級 build.gradle
文件的cppFlags
中,Gradle
會將其傳遞到CMake
。(1) cpp 文件夾函數
用於存放C/C++
的源文件,在磁盤上對應於app/src/main/cpp
文件夾,當新建工程時,它會生成一個native-lib.cpp
的事例文件,其內容以下:工具
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_demo_lizejun_cmakenewdemo_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
複製代碼
(2) 增長 CMakeList.txt 腳本學習
構建腳本,在磁盤上對應於app/
目錄下的txt
文件,其內容爲以下圖所示,這裏面涉及到的CMake
語法包括下面四種,關於CMake
的語法,能夠查看 官方的 API 說明
cmake_minimum_required
add_library
find_library
target_link_libraries
# 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_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 them 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).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries 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 this
# 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} )
複製代碼
(3) build.gradle 腳本
與傳統的項目相比,該模塊所對應的build.gradle
須要在裏面指定CMakeList.txt
所在的路徑,也就是下面externalNativeBuild
對應的選項。
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.demo.lizejun.cmakenewdemo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
複製代碼
(4) 打印字符串
在MainActivity
中,咱們加載原生庫,並調用原生庫中的方法獲取了一個字符串展現在界面上:
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");
}
}
複製代碼
(5) 運行結果
最後,咱們運行一下這個工程,會獲得下面的結果:
經過APK Analyzer
工具,咱們能夠看到在
APK
當中,增長了
libnative-lib.so
文件:
下面,咱們來解釋一下這一過程:
build.gradle
中path
所指定的路徑,找到CMakeList.txt
,解析其中的內容。src/main/cpp/native-lib.cpp
編譯到共享的對象庫中,並將其命名爲libnative-lib.so
,隨後打包到APK
中。MainActivity
的static
代碼塊的內容,使用System.loadLibrary()
加載原生庫。onCreate()
函數中,調用原生庫的函數獲得字符串並展現。當經過CMake
來對應用程序增長C/C++
的支持時,對於應用程序的開發者,只須要關注如下三個方面:
C/C++
源文件CMakeList.txt
腳本build.gradle
中經過externalNativeBuild/cmake
進行配置C/C++
代碼下面,咱們演示一下如何在現有的項目中添加對於C/C++
代碼的支持。
(1) 建立一個工程
和第二步不一樣,此次建立的時候,咱們不勾選nclude C++ Support
選項,那麼會獲得下面這個普通的工程:
(2) 定義接口
這一次,咱們將它定義在一個單獨的文件當中:
public class NativeCalculator {
private static final String SELF_LIB_NAME = "calculator";
static {
System.loadLibrary(SELF_LIB_NAME);
}
public native int addition(int a, int b);
public native int subtraction(int a, int b);
}
複製代碼
這時候由於沒有找到對應的本地方法,所以會有以下的錯誤提示:
(3) 定義 cpp 文件
在模塊根目錄下的src/main/
新建一個文件夾cpp
,在其中新增一個calculator.cpp
文件,這裏,咱們先只引入頭文件:
#include <jni.h>
複製代碼
(4) 定義 CMakeLists.txt
在模塊根目錄下新建一個CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.4.1)
add_library(calculator SHARED src/main/cpp/calculator.cpp)
複製代碼
(5) 在 build.gradle 中進行配置
以後,咱們須要讓Gradle
腳本肯定CMakeLists.txt
所在的位置,咱們能夠在CMakeLists.txt
上點擊右鍵,以後選擇Link C++ Project with Gradle
:
build.gradle
就會新增下面這句:
在這步完成以後,咱們選擇
Build -> Clean Project
。
**(6) 實現 C++ **
在配置完上面的信息以後,會發現一個神奇的地方,以前咱們定義native
接口的地方,多出了一個選項,它能夠幫助咱們直接在對應的C++
文件中生成函數的定義:
Create function
以後,咱們的
calculator.cpp
文件變成了下面這樣:
#include <jni.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_demo_lizejun_cmakeolddemo_NativeCalculator_addition(JNIEnv *env, jobject instance, jint a, jint b) {
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_demo_lizejun_cmakeolddemo_NativeCalculator_subtraction(JNIEnv *env, jobject instance, jint a, jint b) {
}
複製代碼
下面咱們在函數體當中添加實現:
#include <jni.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_demo_lizejun_cmakeolddemo_NativeCalculator_addition(JNIEnv *env, jobject instance, jint a, jint b) {
return a + b;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_demo_lizejun_cmakeolddemo_NativeCalculator_subtraction(JNIEnv *env, jobject instance, jint a, jint b) {
return a - b;
}
複製代碼
(9) 調用本地函數
public class MainActivity extends AppCompatActivity {
private NativeCalculator mNativeCalculator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNativeCalculator = new NativeCalculator();
Log.d("Calculator", "11 + 12 =" + (mNativeCalculator.addition(11,12)));
Log.d("Calculator", "11 - 12 =" + (mNativeCalculator.subtraction(11,12)));
}
}
複製代碼
最終運行的結果爲:
以上就是使用Android Studio 2.2
以上版本,經過CMake
來進行NDK
開發的一個簡單例子,主要是學習一下開發的流程,下一篇文章,要學習一下CMakeLists.txt
中的語法。
(1) 向您的項目添加 C 和 C++ 代碼
(2) NDK筆記(二) - 在Android Studio中使用 ndk-build
(3) NDK開發 從入門到放棄(一:基本流程入門瞭解)
(4) NDK開發 從入門到放棄(七:Android Studio 2.2 CMAKE 高效 NDK 開發)
(5) The new NDK support in Android Studio
(6) Google NDK 官方文檔
(7) Android Studio 2.2 對 CMake 和 ndk-build 的支持
(8) Android開發學習之路--NDK、JNI之初體驗
(9) NDK- JNI實戰教程(一) 在Android Studio運行第一個NDK程序
(10) cmake-commands
(11) CMake
(12) 開發本身的 NDK 程序
(13) NDK開發-Android Studio+gradle-experimental 開發 ndk
(14) Android NDK 開發入門指南