1.環(huán)境搭建
開發(fā)工具:AndroidStudio
打開AndroidStudio,進(jìn)入settings
,找到Android SDK
目錄,點(diǎn)擊SDK tools
,分別找到如圖三個(gè)配置,勾上,下載。
分別介紹一下:
- cmake
類似于Android studio中的gradle,是對(duì)ndk的一個(gè)配置管理 - LLDB
c/c++的一個(gè)調(diào)試工具,安裝后可以對(duì)c/c++代碼進(jìn)行debug - NDK
ndk的開發(fā)工具包
安裝完成后,新建一個(gè)工程,注意勾選下方的include c++ support
,一路next
,直到項(xiàng)目構(gòu)建完成,這樣,我們的整體的ndk項(xiàng)目開發(fā)環(huán)境就配置好了。
2.配置文件介紹
項(xiàng)目構(gòu)建完畢后,我們會(huì)發(fā)現(xiàn)多了配置和文件,如圖:
先介紹一下這幾個(gè)參數(shù)的作用:
點(diǎn)開CMakeLists.txt
,如下所示:
# 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.
# 配置so庫信息
add_library( # Sets the name of the library.
# 生成的so庫名稱,此處生成的so文件名稱是libnative-lib.so
native-lib
# Sets the library as a shared library.
# STATIC:靜態(tài)庫,是目標(biāo)文件的歸檔文件,在鏈接其它目標(biāo)的時(shí)候使用
# SHARED:動(dòng)態(tài)庫,會(huì)被動(dòng)態(tài)鏈接,在運(yùn)行時(shí)被加載
# MODULE:模塊庫,是不會(huì)被鏈接到其它目標(biāo)中的插件,但是可能會(huì)在運(yùn)行時(shí)使用dlopen-系列的函數(shù)動(dòng)態(tài)鏈接
SHARED
# Provides a relative path to your source file(s).
# 資源文件,可以多個(gè),
# 資源路徑是相對(duì)路徑,相對(duì)于本CMakeLists.txt所在目錄
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.
# 從系統(tǒng)查找依賴庫
find_library( # Sets the name of the path variable.
# android系統(tǒng)每個(gè)類型的庫會(huì)存放一個(gè)特定的位置,而log庫存放在log-lib中
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
# android系統(tǒng)在c環(huán)境下打log到logcat的庫
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.
# 配置庫的鏈接(依賴關(guān)系)
target_link_libraries( # Specifies the target library.
# 目標(biāo)庫
native-lib
# Links the target library to the log library
# included in the NDK.
# 依賴于
${log-lib} )
看注釋就能明白每個(gè)方法參數(shù)代表什么意思了,如果你覺得里面注釋太多,看起來不是很順眼,可以下載CMake simple highligher
插件來提高代碼亮度
關(guān)于cmake的配置還有許多,這里只是先簡單介紹一個(gè)。
我們?cè)賮砜匆幌耣uild.gradle中的配置方法的作用,在
defultConfig
中有個(gè)這個(gè)參數(shù),
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'armeabi','arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
}
}
我們主要關(guān)注 abiFilters
,它是用來設(shè)置編譯生成什么類型的so的,我們的cup架構(gòu)主要有以下幾種:
- armeabi
- armeabi-v7a
- arm64-v8a
- x86
- x86_64
- mips
- mips_64
其中,armeabi-v7a
是目前大部分手機(jī)的主流架構(gòu),它是基于armeabi
的一種升級(jí)架構(gòu),因此,它們是互相兼容的,但目前各手機(jī)廠商的旗艦級(jí),都已經(jīng)開始采用arm64-v8a
的cpu,不過不要慌,它也是兼容armeabi
的,所以,如果我們只需要開發(fā)普通應(yīng)用的話,我們只需要關(guān)注armeabi
和armeabi-v7a
就可以了,而像x86
等這種類型的架構(gòu)多用于平板等設(shè)備,因此我們只需要了解即可。
與此相同的還有一個(gè)配置:
ndk{
abiFilters "armeabi","armeabi-v7a"
}
它也是用來配置需要什么類型的so的,但它是負(fù)責(zé)打包到apk里有什么類型的so,而不是編譯出什么so,兩者還是有區(qū)別的。例如我在cmake
里設(shè)置一個(gè) "armeabi","armeabi-v7a",在ndk
里設(shè)置一個(gè)armeabi,我make project
一下,它會(huì)生成兩個(gè)cpu類型的so,但是我運(yùn)行打包apk,在apk的lib目錄里就只有一個(gè)armeabi的so了,所以:
當(dāng)我們不需要編譯so庫時(shí),例如引用的第三方庫,可以使用ndk
來過濾,完全不需要cmake
接下來說一下android
下的方法:
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
其實(shí)很顯然,它就是指定我們的CMakeLists
文件路徑的,當(dāng)然我們的這個(gè)路徑是可以更改的。
這里教大家一個(gè)小技巧,在cmd中執(zhí)行:adb shell
cat /proc/cpuinfo
可以查看當(dāng)前手機(jī)的cpu架構(gòu)哦,效果圖如下:
CPU architecture: 8
說明我的手機(jī)是arm64-v8a
架構(gòu)
接下來我們來看cpp文件,這個(gè)文件是干嘛的呢,它是c里.h文件的實(shí)現(xiàn)的源文件,你可以把它看作是與java交互的橋梁,里面包含了java層需要調(diào)用到的函數(shù)方法,點(diǎn)開可以看到以下函數(shù):
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_jie_ndkdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
主要是看這個(gè)函數(shù):
Java_com_jie_ndkdemo_MainActivity_stringFromJNI
,它是有格式要求的,由Java_包名類名函數(shù)名組成,定義的時(shí)候一定要按照這個(gè)格式來,其中,MainActivity
是我聲明native方法的類的類名。