NI通識
NDK是什麼
原生開發工具包 (NDK) 是一組可讓您在 Android 應用中利用 C 和 C++ 代碼的工具。 可用以從您自己的源代碼構建,或者利用現有的預構建庫。
-來自Google 官方文檔
為什麼要使用NDK
從設備獲取卓越性能以用於計算密集型應用,例如遊戲或物理模擬。
重複使用您自己或其他開發者的 C 或 C++ 庫。
如果不滿足上面的條件, 那麼你還是不要引入NDK, 這樣會把你的應用變得非常非常地複雜.
主要組件
ndk-build
ndk-build 腳本用於在 NDK 中心啟動構建腳本
Java
Android 構建過程從 Java 來源生成 .dex (Dalvik EXecutable) 文件,這些文件是 Android OS 在 Dalvik 虛擬機(“DVM”)中運行的文件。 即使您的應用根本未包含任何 Java 源代碼,構建過程仍會生成原生組件在其中運行的 .dex 可執行文件。
原生共享庫
NDK 從原生源代碼構建這些庫或 .so 文件。
原生靜態庫
NDK 也可構建靜態庫或 .a 文件,您可以關聯到其他庫。
Java 原生接口 (JNI)
JNI 是 Java 和 C++ 組件用以互相溝通的接口。
應用二進制界面 (ABI)
ABI 可以非常精確地定義應用的機器代碼在運行時如何與系統交互。 NDK 根據這些定義構建 .so 文件。 不同的 ABI 對應不同的架構:NDK 包含對 ARMEABI(默認)、MIPS 和 x86 的 ABI 支持。
清單文件
如果您要編寫沒有 Java 組件的應用,必須在清單文件中聲明 NativeActivity 類。
兩個重要的配置文件
Android.mk
必須在 jni 文件夾內創建 Android.mk 配置文件。 ndk-build 腳本將查看此文件,其中定義了模塊及其名稱、要編譯的源文件、版本標誌以及要鏈接的庫。
概覽
Android.mk 文件位於項目 jni/ 目錄的子目錄中,用於向構建系統描述源文件和共享庫。事實上就是告訴ndk去編譯哪些
c/c++
文件還有怎麼去編譯它們
NDK定義的變量
常用
編譯目標目錄聲明
LOCAL_PATH := $(call my-dir)
必須定義, LOCAL_PATH
表示需要編譯的源文件的目錄, $(call my-dir)
表示使用宏函數my-dir
的返回值, 對應的就是當前Android.mk的所在目錄
重置全局變量
include $(CLEAR_VARS)
CLEAR_VARS
變量指向特殊 GNU Makefile, 可為您清除許多LOCAL_XXX
變量. 不包括LOCAL_PATH
因為系統在單一 GNU Make 執行環境(其中所有變量都是全局的)中解析所有構建控制文件. 在描述每個模塊之前, 必須聲明(重新聲明)此變量
指定需要編譯的模塊
LOCAL_MODULE := recorder-jni
LOCAL_MODULE
指定模塊的名稱, 唯一且不含空格, 之後會編譯出librecorder-jni.so
, 如果模塊名已包含前綴lib
, 則不會自動添加lib前綴
.
LOCAL_SRC_FILES
表示該模塊需要編譯哪些源文件, 多個源文件使用空格
分割
上面的意思就是, 編譯video.c和audio.c並輸出為librecorder-jni.so
整合
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY
變量指向GNU Makefile
腳本, 用於收集您自最近 include 後在 LOCAL_XXX 變量中定義的所有信息. 其實就是讓上一次include
到這裡之間的內容生效
如果引用了其他的so文件, 那麼ndk會清掉庫目錄下的所有so文件, 默認是jnilibs
, 所以必須使用預構建庫解決這問題
其他
構建系統提供許多可用於 Android.mk 文件中的變量。其中許多變量已預先賦值。 另一些變量由您賦值。
除了這些變量之外,您還可以定義自己的任意變量。在定義變量時請注意,NDK 構建系統會預留以下變量名稱:
以 LOCAL_ 開頭的名稱,例如 LOCAL_MODULE。
以 PRIVATE_、NDK_ 或 APP 開頭的名稱。構建系統在內部使用這些變量。
小寫名稱,例如 my-dir。構建系統也是在內部使用這些變量。
如果為了方便而需要在 Android.mk 文件中定義自己的變量,建議在名稱前附加 MY_。
編譯指定平臺庫
TARGET_ARCH_ABI := arm64-v8a
當構建系統解析此 Android.mk 文件時,此變量將 CPU 和架構的名稱存儲到目標。 您可以指定以下一個或多個值,使用空格
作為多個目標之間的分隔符。其實就是指定需要編譯的平臺
CPU和架構 | 設置 |
---|---|
ARMv5TE | armeabi |
ARMv7 | armeabi-v7a |
ARMv8 AArch64 | arm64-v8a |
i686 | x86 |
x86-64 | x86_64 |
mips32 (r1) | mips |
mips64 (r6) | mips64 |
全部 | all |
指定Android版本
TARGET_PLATFORM := android-22
作為構建系統目標的 Android API 級別號
更多請參考Google文檔的NDK 定義的變量
模塊描述的變量
每個模塊描述應遵守以下基本流程:
使用 CLEAR_VARS 變量初始化或取消定義與模塊相關的變量。
為用於描述模塊的變量賦值。
使用 BUILD_XXX 變量設置 NDK 構建系統,以便為模塊使用適當的構建腳本。
編譯目錄路徑
LOCAL_PATH
, 表示需要編譯的源文件的目錄
編譯模塊名稱
LOCAL_MODULE
, 指定模塊的名稱, 唯一且不含空格, 之後會編譯出librecorder-jni.so
, 如果模塊名已包含前綴lib
, 則不會自動添加lib前綴
.
編譯模塊輸出名稱
LOCAL_MODULE_FILENAME
, 真正的庫輸出文件名. 如果不喜歡系統自動生成的文件名, 可以指定這個值
LOCAL_MODULE := foo
上面表示輸出libnewfoo.so
更多參考Google文檔的模塊描述變量
待編譯的源文件
LOCAL_SRC_FILES
,指定源文件列表, 多個文件使用空格
分割. 可以使用相對文件路徑(指向 LOCAL_PATH)和絕對文件路徑
Application.mk
此文件枚舉並描述您的應用需要的模塊。
Android.mk
有效的前提是依靠該文件的保證 位於jni
的目錄下
該文件信息包括:
用於針對特定平臺進行編譯的 ABI。
工具鏈。
要包含的標準庫(靜態和動態 STLport 或默認系統)。
工程路徑
APP_PROJECT_PATH
, 應用項目根目錄的絕對路徑. 如果將Application.mk 文件放在 $NDK/apps/<myapp>/ 下,則必須定義此變量。 如果將其放在 $PROJECT/jni/ 下,則此變量可選。
編譯平臺
APP_ABI
, 默認情況下, NDK 構建系統為 armeabi ABI 生成機器代碼.多個值使用空格分割
指令集 | 值 |
---|---|
基於 ARMv7 的設備上的硬件 FPU 指令 | APP_ABI := armeabi-v7a |
ARMv8 AArch64 | APP_ABI := arm64-v8a |
IA-32 | APP_ABI := x86 |
Intel64 | APP_ABI := x86_64 |
MIPS32 | APP_ABI := mips |
MIPS64 (r6) | APP_ABI := mips64 |
所有支持的指令集 | APP_ABI := all |
編譯Android版本
APP_PLATFORM
, 此變量包含目標 Android 平臺的名稱.
其他
更多參考Google文檔的Application.mk
由於Android Studio以強大的方式集成了NDK, 所以上面很多配置都不需要寫. 方便了很多.
NDK配置
環境
環境 | 版本 |
---|---|
OS | OSX 10.12.3 |
IDE | Android Studio 2.3 |
JDK | Oracle JDK1.7 |
Android Studio 2.3集成NDK比以前方便多了, 因為NDK已經在SDK Manager中提供下載.
下載安裝
File
->Settings
->Appearance & Behavior
->System Settings
->Android SDK
->SDK Tools
->勾上NDK
->Apply
->OK
NDK配置.png
然後就開始下載了, 下載完成後
finish
就可以了.