Android NDK入門避坑指南

前言

本文基于自己所學(xué)到的NDk的知識和一些在網(wǎng)上查到的資料

因?yàn)閷W(xué)習(xí)NDK的時(shí)間不是很長秉剑,學(xué)到的內(nèi)容難免有所錯(cuò)漏,希望有問題的可以明確的指出來错英,我會積極采納

本文會竭盡可能的將我現(xiàn)在所學(xué)到的關(guān)于NDK的知識清晰的表達(dá)出來,本文主要以NDK的基本概念荆烈,NDK的組成部分淌山,NDK的注意事項(xiàng)三個(gè)部分組成

實(shí)踐部分因?yàn)楸酒恼乱呀?jīng)6000多字了裸燎,為了不讓文章過長,將會在后面的博客中

一. NDK的基本概念

在學(xué)習(xí)NDK之前泼疑,我首先得知道什么是NDK德绿,NDK可以干些什么,使用NDK的好處有哪些退渗,知道了這些移稳,我們才可以更好的學(xué)習(xí)NDK

1. 什么是NDK

NDK即Native Development Kit,是Android中的一個(gè)開發(fā)工具包,為我們提供native開發(fā)的環(huán)境

NDK是我們實(shí)現(xiàn)Java與Native進(jìn)行交互的一個(gè)手段

2. NDK可以干什么

可以快速開發(fā)CC++的動態(tài)庫会油,并自動將so和應(yīng)用一起打包成 APK

即可通過 NDK使 Java與native代碼(如 C个粱、C++)交互

NDK在現(xiàn)在很多熱門的技術(shù)中都有使用,如:Android 音視頻開發(fā)翻翩,熱更新都许,OpenCV,等等

3. 我們?yōu)槭裁匆褂肗DK

  1. 允許程序開發(fā)人員直接使用 C/C++ 源代碼嫂冻,極大的提高了 Android 應(yīng)用程序開發(fā)的靈活性

  2. 跨平臺應(yīng)用移植胶征、使用第三方庫。如:許多第三方庫只有 C/C++ 語言的版本桨仿,而 Android 應(yīng)用程序需要使用現(xiàn)有的第三方庫睛低,如 FFmpeg、OpenCV等服傍,則必須使用NDK

  3. 采用C++代碼來處理性能要求高的操作钱雷,提高了Android APP的性能

  4. 安全性高

4. NDK與SDK的關(guān)系

在Android開發(fā)中,最常用的是SDK吹零,那么SDK與NDK的關(guān)系是什么呢罩抗?

在SDK中,我們使用Java來進(jìn)行開發(fā),而在NDK中,我們使用C++來進(jìn)行開發(fā)

SDK支持了Android開發(fā)中的大部分操作搅荞,如UI展示发框,用戶與手機(jī)的交互等,主要是支持了Android APP開發(fā)的基礎(chǔ)功能

NDK支持了一些復(fù)雜的伸辟,比較高級的操作麻惶,如音視頻的解析,大量數(shù)據(jù)的運(yùn)算信夫,提高Android游戲的運(yùn)行速度等窃蹋,主要是Android APP的一些高級功能

所以NDK與SDK是并列關(guān)系卡啰,NDK是SDK的有效補(bǔ)充

img

二. NDK的組成部分

現(xiàn)在我們知道了NDK是什么,NDK的作業(yè)警没,優(yōu)點(diǎn)了匈辱,那我們該開始正式學(xué)習(xí)NDK了,但是工欲善其事杀迹,必先利其器亡脸,在使用NDK這個(gè)工具以前,我們必須先好好地了解NDK

所以本部分將分析NDK中的一些組成及他們的作用

本部分將講述NDK中的JNI 树酪,二進(jìn)制文件(.so 和 .a), ABI 浅碾,本機(jī)編譯工具,交叉編譯工具等等

1. JNI

  • 定義

    JNI 即Java Native Interface,即Javanative接口

    JNI是一種編程框架续语,使得 Java 虛擬機(jī)中的 Java 程序可以調(diào)用本地應(yīng)用 / 或庫垂谢,也可以被其他程序調(diào)用。 本地程序一般是用其它語言(C疮茄、C++ 或匯編語言等)編寫的滥朱,并且被編譯為基于本機(jī)硬件和操作系統(tǒng)的程序

    上文中,NDK也是支持Java代碼與Native代碼的交互娃豹,那他們之間有什么區(qū)別呢焚虱?

    實(shí)際上,JNI是一個(gè)編程框架懂版,是一個(gè)抽象的東西鹃栽,NDK是一個(gè)工具包,是一個(gè)

    所以:NDK是實(shí)現(xiàn)JNI的一個(gè)手段

  • 作用 支持Java代碼與native代碼進(jìn)行交互躯畴,即Java代碼調(diào)用native代碼 或者 native代碼調(diào)用Java代碼 native代碼主要指CC++

  • 使用JNI的原因

    有些事情 Java 無法處理時(shí)民鼓,JNI 允許程序員用其他編程語言來解決,例如蓬抄,Java 標(biāo)準(zhǔn)庫不支持的平臺相關(guān)功能或者程序庫丰嘉。也用于改造已存在的用其它語言寫的程序,供 Java 程序調(diào)用

  • 使用JNI的步驟

    1. 使用Native關(guān)鍵字定義Java方法(即需要調(diào)用的native方法)

    2. 使用javac編譯上述 Java源文件 (即 .java文件)最終得到 .class文件

    3. 通過 javah 命令編譯.class文件,最終導(dǎo)出JNI的頭文件(.h文件)

    4. 使用 Java需要交互的native代碼嚷缭,以及實(shí)現(xiàn)在 Java中聲明的Native方法

    5. 編譯.so庫文件

    6. 通過Java命令執(zhí)行 Java程序饮亏,最終實(shí)現(xiàn)Java調(diào)用native代碼編譯生成的.so文件

    實(shí)際上2345步驟的目的就是生成.so 文件

    所以上面的步驟可以歸納為三步:

    1. 聲明Native方法

    2. 實(shí)現(xiàn)Native方法,經(jīng)過一系列操作阅爽,最終生成.so 文件

    3. 加載.so文件路幸,調(diào)用Native方法

      這里只簡單介紹JNI的步驟,具體實(shí)現(xiàn)的例子在后面的博客中

2 .so 和 .a 文件

上面我們已經(jīng)說到付翁,JNI 支持了Java代碼和native代碼的互相調(diào)用

但是JNI是直接調(diào)用Java代碼和native代碼嗎简肴?

實(shí)際上,JNI是調(diào)用java代碼和native代碼編譯后的.so.a文件來實(shí)現(xiàn)了Java代碼和native代碼的交互

那么.so.a文件是什么呢百侧?下面我列出了.so和.a文件的一些定義

  • 動態(tài)鏈接庫 (.so 后綴):

    運(yùn)行時(shí)才動態(tài)加載這個(gè)庫;

    動態(tài)鏈接庫砰识,也叫共享庫能扒,因?yàn)樵?NDK 中用 shared 來表示是動態(tài)庫

    現(xiàn)在熱門的插件化,熱更新以及縮小APK大小等技術(shù)都使用了 .so 文件

  • 靜態(tài)鏈接庫 (.a 后綴)

    編譯的時(shí)候, 就把靜態(tài)庫打包進(jìn) APK 中

    • 缺點(diǎn) : 使用靜態(tài)庫編譯, 編譯的時(shí)間比較長辫狼,同時(shí)也使得APK比較大

    • 優(yōu)點(diǎn) : 只導(dǎo)出一個(gè)庫, 可以隱藏自己調(diào)用的庫;

  • .so.a本質(zhì)上都是二進(jìn)制文件初斑,下文我將用二進(jìn)制文件統(tǒng)稱這兩個(gè)文件

  • 每個(gè)CPU系統(tǒng)只能使用相對應(yīng)的二進(jìn)制文件,即他們不像jar包一樣予借,所有的CPU系統(tǒng)都可以使用一個(gè)jar包越平,.so 和 .a 每個(gè)系統(tǒng)必須使用自己的,不能使用別的灵迫,如 armeabi.so文件秦叛,不能被應(yīng)用到x86

3. CPU架構(gòu)

Android 平臺,其支持的設(shè)備型號繁多瀑粥,單單就設(shè)備的核心 CPU 而言挣跋,都有三大類:ARM、x86 和 MIPS

**ARM主要應(yīng)用于手機(jī)中狞换,x86主要應(yīng)用于PC中

Android中使用x86主要是因?yàn)椋?strong>因?yàn)镻C是x86架構(gòu)避咆,所以PC上的手機(jī)模擬器需要x86的二進(jìn)制文件

而在NDK r17中,有了大的變化:

在NDK r17 以后修噪,NDK 不在支持32位和64位 MIPSARM v5(armeabi)

所以現(xiàn)在NDK只支持ARMx86查库,而ARMx86又各自分為兩種:

簡單的來說:ARM 和 x86 各分為 32位和64位兩種,所以現(xiàn)在NDK一共支持4種CPU架構(gòu)

即:ARM 32位 黄琼,ARM 64位 樊销, x86 32位 ,x86 64位

4. ABI

ABI : Application Binary Interface

我們上面說了脏款,每個(gè)系統(tǒng)只能使用相對應(yīng)的二進(jìn)制文件围苫,

不同的 Android 設(shè)備使用不同的 CPU,而不同的 CPU 支持不同的指令集撤师。CPU 與指令集的每種組合都有專屬的應(yīng)用二進(jìn)制接口 (ABI)

簡而言之:而ABI定義了二進(jìn)制文件是怎么運(yùn)行在對應(yīng)的CPU中的

上文中我們大致了解了Android中常用的CPU架構(gòu)剂府,而且我們知道,ABI 定義了二進(jìn)制文件時(shí)怎么在CPU中運(yùn)行的剃盾,那么我們可以知道腺占,每一個(gè)CPU架構(gòu)必定有一個(gè)相對應(yīng)的ABI

上面我們已經(jīng)知道了有四種,那么ABI也有四種痒谴,他們分別是:armeabi-v7a衰伯,armeabi-v8a,x86闰歪,x86_64

ABI 對應(yīng)的CPU架構(gòu) 應(yīng)用
armeabi-v7a ARM 32位 手機(jī)
armeabi-v8a ARM 64位 手機(jī)
X86 X86 32位 PC
X86_64 X86 64位 PC

CPU架構(gòu)中64位的CPU架構(gòu)兼容32位的ABI和64位的ABI嚎研,32位的CPU架構(gòu)只支持32位的ABI

armeabi-v7a設(shè)備只兼容armeabi-v7a

armeabi-v8a設(shè)備兼容armeabi-v7a蓖墅,armeabi-v7a

X86設(shè)備只兼容X86_64

X86_64兼容X86库倘,X86_64

NDK編譯實(shí)際上默認(rèn)編譯出所有系統(tǒng)的文件

但是有時(shí)我們只需要使用指定的系統(tǒng)临扮,我們就可以指定編譯什么系統(tǒng),減少二進(jìn)制文件教翩,避免我們不會使用到的二進(jìn)制文件被打包到apk中杆勇,如我們在PC上使用模擬器來執(zhí)行APP時(shí),我們需要x86饱亿,但是我們APP最終是要在手機(jī)上運(yùn)行的蚜退,這樣我們只需要ARM的就行了,我們就可以在最終打包APK時(shí)彪笼,去掉x86的

我們可以使用下面的代碼來指定我們要編譯什么CPU架構(gòu)的二進(jìn)制文件

//在project的build.gradle中
android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'x86_64'
        }
    }

5. 編譯工具

5.1 本機(jī)編譯工具

我們已經(jīng)知道钻注,每個(gè)系統(tǒng)只能使用自己系統(tǒng)的二進(jìn)制文件,本機(jī)編譯工具正是編譯出本機(jī)系統(tǒng)可以使用的二進(jìn)制文件

在Android中可以使用的本機(jī)編譯工具有兩種:ndk-buildcmake

  1. cmake

    我們已經(jīng)知道配猫,每個(gè)系統(tǒng)只能使用自己的二進(jìn)制文件

    那么我們在開發(fā)中幅恋,就需要編譯出對應(yīng)的二進(jìn)制文件,而且如果我們的軟件想要跨平臺泵肄,那么我們就得保證在每一個(gè)平臺上都可以編譯

    即:如果我們的軟件想在Mac OS 和 Windows上運(yùn)行捆交,那么我們的軟件在Mac OS上運(yùn)行時(shí),要生成可以在Mac OS上運(yùn)行的二進(jìn)制文件腐巢,在Windows上運(yùn)行品追,要生成Windows上可以運(yùn)行的二進(jìn)制文件

    這樣的話,那我們得為每一個(gè)平臺都要編寫一次MakeFile文件冯丙,這將是一個(gè)很無趣肉瓦,很令人抓狂的操作

而CMake就是針對上述問題的一個(gè)工具

允許開發(fā)者編寫一種與平臺無關(guān)的CMakeList.txt文件來定制整個(gè)編譯流程,然后再根據(jù)目標(biāo)用戶的平臺逐步生成所需的本地化Makefile和工程文件银还,如Unix的Makefile或Windows的Visual Studio工程

從而達(dá)到“只寫一次风宁,到處運(yùn)行

即:我們只要寫一個(gè) cmakeLists.txt文件,那么就可以在所有平臺中編譯出對應(yīng)的二進(jìn)制文件

這樣的話蛹疯,當(dāng)運(yùn)行在Windows上時(shí)戒财,自動生成Windows的,在Mac OS行運(yùn)行捺弦,自動生成MacOS的饮寞,但是,我們只需要寫一個(gè)cmakeList.txt文件即可A泻稹S谋馈!

使用 CMake 生成 Makefile 并編譯的流程如下:

  1. 編寫 CMake 配置文件 CMakeLists.txt 寞钥。
  2. 執(zhí)行命令 cmake PATH 或者 ccmake PATH 生成 Makefile(ccmakecmake 的區(qū)別在于前者提供了一個(gè)交互式的界面)慌申。其中, PATH 是 CMakeLists.txt 所在的目錄。
  3. 使用 make 命令進(jìn)行編譯蹄溉。

當(dāng)然咨油,在Android開發(fā)過程中,我們不需要執(zhí)行上面的流程柒爵,因?yàn)樵?Android studio 當(dāng)中已經(jīng)為我們集成了役电,我們只需要編寫cmakeLists.txt文件,剩下的就交給 Android studio 就行了

在Android開發(fā)過程中棉胀,使用cmake只需要兩個(gè)文件法瑟,xxx.cppCMakeLists.txt

  • cmakeLists.txt 就如上面所述,定義整個(gè)的編譯流程
  • xxx.cpp 則是要被編譯的 C++ 文件

具體的實(shí)現(xiàn)方式我會在下面列出

  1. ndk-build

ndk-build是一個(gè)和cmake功能差不多的工具唁奢,他們都減少了我們定制編譯流程的操作

但是ndk-build是以前常使用的工具霎挟,我們現(xiàn)在常用cmake,ndk-build的操作要比cmake復(fù)雜一些

ndk-build本質(zhì)上是一個(gè)腳本,它的位置就在NDK目錄的最上層麻掸,即在< NDK >/ndk-build路徑下

因?yàn)槭且粋€(gè)腳本氓扛,所以下面的命令等同于ndk-build

# $GNUMAKE 指 GNU Make 3.81 或更高版本
# <ndk> 則指向 NDK 安裝目錄
$GNUMAKE -f <ndk>/build/core/build-local.mk <parameters>

#等同于
ndk-build

使用ndk-build我們需要兩個(gè)文件: Android.mk 和 Application.mk

  1. Android.mk

    Google的官方文檔對Android.mk的定義如下

    Android.mk 文件位于項(xiàng)目 jni/ 目錄的子目錄中,用于向構(gòu)建系統(tǒng)描述源文件和共享庫论笔。它實(shí)際上是構(gòu)建系統(tǒng)解析一次或多次的微小 GNU makefile 片段采郎。Android.mk 文件用于定義 Application.mk、構(gòu)建系統(tǒng)和環(huán)境變量所未定義的項(xiàng)目級設(shè)置狂魔。它還可替換特定模塊的項(xiàng)目級設(shè)置蒜埋。

    Android.mk 的語法支持將源文件分組為“模塊”。模塊是靜態(tài)庫最楷、共享庫或獨(dú)立的可執(zhí)行文件整份。您可在每個(gè) Android.mk 文件中定義一個(gè)或多個(gè)模塊,也可在多個(gè)模塊中使用同一個(gè)源文件籽孙。構(gòu)建系統(tǒng)只將共享庫放入您的應(yīng)用軟件包烈评。此外,靜態(tài)庫可生成共享庫犯建。

    除了封裝庫之外讲冠,構(gòu)建系統(tǒng)還可為您處理各種其他事項(xiàng)。例如适瓦,您無需在 Android.mk 文件中列出頭文件或生成的文件之間的顯式依賴關(guān)系竿开。NDK 構(gòu)建系統(tǒng)會自動計(jì)算這些關(guān)系。因此玻熙,您應(yīng)該能夠享受到未來 NDK 版本中支持的新工具鏈/平臺功能帶來的益處否彩,而無需處理 Android.mk 文件。

    此文件的語法與隨整個(gè) Android 開源項(xiàng)目分發(fā)的 Android.mk 文件中使用的語法非常接近嗦随。雖然使用這些語法的構(gòu)建系統(tǒng)實(shí)現(xiàn)并不相同列荔,但通過有意將語法設(shè)計(jì)得相似,可使應(yīng)用開發(fā)者更輕松地將源代碼重復(fù)用于外部庫。

這個(gè)的定義很長贴浙,簡單的來說筷转,Android.mk的作用如下:

  1. 描述了源文件的位置和名字
  2. 描述了生成什么文件,如共享庫悬而,靜態(tài)庫等
  3. 自動處理構(gòu)建中的一些事項(xiàng),如文件之間的依賴關(guān)系
  4. 語法設(shè)置得與Android開源項(xiàng)目相似锭汛,使得我們可以輕易的將源代碼重復(fù)使用

Android.mk的一些常用的變量如下:

  # 這個(gè)是源文件的路徑笨奠,call my-dir表示了返回當(dāng)前Android.mk所在的目錄
  LOCAL_PATH := $(call my-dir)
  
  # 清除許多 LOCAL_XXX 變量
  # 注意:不會清除 LOCAL_PATH 
  include $(CLEAR_VARS)
  
  # LOCAL_MODULE 變量存儲要構(gòu)建的模塊的名稱
  # 這里最終會生成叫 libhello-jni.so 的文件
  LOCAL_MODULE := hello-jni
  
  # 源文件名字
  # 可以有多個(gè)源文件,使用空格隔開
  LOCAL_SRC_FILES := hello-jni.c
  
  # 指定編譯出什么二進(jìn)制文件
  # 這里編譯出共享庫唤殴,即:.so文件
  # 編譯出靜態(tài)庫可以使用: BUILD_STATIC_LIBRARY
  include $(BUILD_SHARED_LIBRARY)
  1. Application.mk

    Application.mk 指定 ndk-build 的項(xiàng)目范圍設(shè)置般婆。默認(rèn)情況下,它位于應(yīng)用項(xiàng)目目錄中的 jni/Application.mk

    簡單的來說朵逝,Application.mk的功能主要是:主要是描述了Android Native開發(fā)需要的模組(module)

    一些常用的變量如下:

# 定義生成的二進(jìn)制文件要生成的CPU架構(gòu)
# 這里指定生成 arm64-v8a 可以用的二進(jìn)制文件
APP_ABI := arm64-v8a

# 定義可以使用該二進(jìn)制文件的Android版本
APP_PLATFORM := android-21

# 默認(rèn)情況下蔚袍,ndk-build 假定 Android.mk 文件位于項(xiàng)目根目錄的相對路徑 jni/Android.mk 中。
# 要從其他位置加載 Android.mk 文件配名,將 APP_BUILD_SCRIPT 設(shè)置為 Android.mk 文件的絕對路徑啤咽。
APP_BUILD_SCRIPT

?

  1. cmake 和 ndk-build 都可以在Android開發(fā)中使用,但是現(xiàn)在默認(rèn)使用的是cmake渠脉,以前常用的是ndk-build

    ndk-build 的實(shí)現(xiàn)過程比cmake復(fù)雜的多,所以現(xiàn)在推薦使用cmake

    但是因?yàn)橐郧暗捻?xiàng)目常用 ndk-build 宇整,如果我們要參與以前 NDK項(xiàng)目 的開發(fā),那么 ndk-build也是需要了解的

    所以芋膘,如果要新建一個(gè)項(xiàng)目鳞青,那么推薦使用cmake,要參與以前老項(xiàng)目的開發(fā),ndk-build也不可落下

5.2交叉編譯工具

與本機(jī)編譯對應(yīng)的为朋,有時(shí)我們需要編譯出其他系統(tǒng)的二進(jìn)制文件臂拓,如我們在PC上寫Android文件,那么我們PC中就需要編譯出Android中可以運(yùn)行的二進(jìn)制文件

交叉編譯工具习寸,又叫交叉編譯鏈( toolchain)

交叉編譯鏈(編譯器胶惰、鏈接器等)來生成可以在其他系統(tǒng)中運(yùn)行的二進(jìn)制文件

在NDK中,交叉編譯工具主要有兩種:clanggcc

三. NDK中一些值得注意的事情

1. NDK版本變化的問題

1.1 NDK中編譯工具的變化

cmake 和 ndk-build 都可以在Android開發(fā)中使用霞溪,但是現(xiàn)在默認(rèn)使用的是cmake童番,以前常用的是ndk-build

ndk-build 的實(shí)現(xiàn)過程比cmake復(fù)雜的多,所以現(xiàn)在推薦使用cmake

但是因?yàn)橐郧暗捻?xiàng)目常用 ndk-build ,如果我們要參與以前 NDK項(xiàng)目 的開發(fā)威鹿,那么 ndk-build也是需要了解的

所以剃斧,如果要新建一個(gè)項(xiàng)目,那么推薦使用cmake,要參與以前老項(xiàng)目的開發(fā)忽你,ndk-build也不可落下

1.2 NDK中交叉編譯的工具的變化

在ndk r17c 以后默認(rèn)使用的變成了clang幼东,而不是gcc

庫文件和頭文件的變化

在r17c以前,頭文件,庫文件以及gcc的路徑如下:

# 庫文件路徑
android-ndk-r17c/platforms/android-21/arch-arm/usr/lib

# 頭文件路徑
android-ndk-r17c/sysroot/usr/include

#gcc的路徑
android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin

而在r17以后根蟹,如 r20 中脓杉,頭文件和庫文件統(tǒng)一放到了sysroot中:

 #頭文件
 toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include
 
 #庫文件
 toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib

我們可以發(fā)現(xiàn) r20 把頭文件和庫文件弄到了一起

但是,r20 中也沒有把 r17 中的庫文件刪除简逮,即我們也可以在下面的路徑中找到頭文件

android-ndk-r17c/platforms/android-21/arch-arm/usr/lib

交叉編譯工具位置的變化

NDK r19以前ndk 內(nèi)置了一個(gè)可以自動生成交叉編譯工具(toolchain).py文件球散,放在

ndk路徑下面的build/tool/make_standalone_toolchain.py

要生成toolchain,使用下面的命令

$NDK_HOME/build/tools/make_standalone_toolchain.py --arch arm --api 21 --install-dir /Users/fczhao/Desktop

后面的幾個(gè)都是必要的

--arch 指定了生成的toolchain要在哪個(gè)CPU框架中使用

--api 指定了生成的toolchain要在哪個(gè)Android API 中使用

--install-dir 生成的toolchain的路徑

如果使用的是NDK r19以前的散庶,可以參考下面的這個(gè)文章

https://developer.android.com/ndk/guides/standalone_toolchain?hl=zh-cn

但是NDK r19以后的NDK已經(jīng)內(nèi)置了這些文件蕉堰,如果運(yùn)行上面的命令,會出現(xiàn)這樣的日志

WARNING:__main__:make_standalone_toolchain.py is no longer necessary. The

#$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin 這個(gè)路徑已經(jīng)有了我們要生成的文件
$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin directory contains target-specific scripts that perform
the same task. For example, instead of:

    $ python $NDK/build/tools/make_standalone_toolchain.py \
        --arch arm --api 21 --install-dir toolchain
    $ toolchain/bin/clang++ src.cpp

Instead use:

    $ $NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang++ src.cpp

Installation directory already exists. Use --force.

然后讓我們?nèi)ド厦孑敵龅穆窂街锌纯幢辏涂梢钥吹絅DK的確已經(jīng)提供了很多的clang,這里我只截取了一部分

image-20200601130753041

1.3 NDK支持的CPU架構(gòu)的變化

上文中我們在ABI已經(jīng)提到了CPU架構(gòu)相關(guān)的東西屋讶,但是為了增加印象,這里稍微重新提一下

Android 平臺核心 CPU有三大類:ARM须教、x86 和 MIPS

而在NDK r17中皿渗,有了大的變化:

在NDK r17 以后,NDK 不在支持32位和64位 MIPSARM v5(armeabi)

所以現(xiàn)在NDK中只支持armeabi-v7a轻腺,armeabi-v8a乐疆,x86,x86_64四類

2. NDK 的系統(tǒng)是否適用的問題

值得注意的是:
在下載NDK時(shí),不像我們下載JDK一樣

當(dāng)下載同一版本的JDK時(shí)贬养,所有的電腦(不論是macOS诀拭,Windows還是Linus)下載的都是一樣

而當(dāng)我們下載相同版本的NDK時(shí),會發(fā)現(xiàn)Google提供了適合于不同系統(tǒng)的NDK煤蚌,如下圖

NDK截圖

之所以提供針對每個(gè)系統(tǒng)的NDK的原因是是

因?yàn)镴ava良好的跨平臺性耕挨,所以所有的系統(tǒng)都可以使用同一個(gè)JDK

而NDK調(diào)用的是C++代碼,C++沒有這么好的跨平臺性尉桩,從而我們必須為每一個(gè)平臺配置適合于它的NDK

所以在我們看別人的NDK博客時(shí)筒占,一定要注意是否與自己使用的NDK是一個(gè)系統(tǒng)的,一個(gè)版本的蜘犁,否則一定會出現(xiàn)問題

3. NDK 中Java與native代碼的交互

Java 和 c/c++ 有兩種交互方式:

  • Java調(diào)用 native 代碼

  • native 代碼調(diào)用 Java 代碼

也就是說翰苫,交互是Java與C++之間的互相調(diào)用

但是在NDK中他們實(shí)際上的順序是:

Java調(diào)用C++代碼,然后C++調(diào)用Java代碼返回C++執(zhí)行后的數(shù)據(jù)这橙,如圖所示

image-20200528190701126

從圖中可以看到奏窑,我們使用NDK的目的實(shí)際上是:

? Java調(diào)用C++,讓C++處理一些復(fù)雜的操作屈扎,然后把處理后的數(shù)據(jù)返回到Java中

? 而我們?yōu)槭裁床恢苯邮褂肑ava來進(jìn)行處理埃唯,而是繞了一圈,通過 Java -> C++ -> Java的方式來實(shí)現(xiàn)鹰晨,其中的原因是:

? C++速度比Java快

? 舉個(gè)簡單的例子墨叛,在ACM或者LeetCode中止毕,C++代碼運(yùn)行的超時(shí)時(shí)間是 1s,而Java的是 2s

? 所以對于一些計(jì)算量很大的操作漠趁,如音視頻的渲染等我們采用C++可以有效的減少計(jì)算時(shí)間和內(nèi)存占用扁凛,減少手機(jī)發(fā)熱和耗電量等


現(xiàn)在我們已經(jīng)大致了解了一些NDK的東西了,后面的博客我將分別分析cmake闯传,ndk-build谨朝,clang,gcc的具體實(shí)現(xiàn)過程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甥绿,一起剝皮案震驚了整個(gè)濱河市字币,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妹窖,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件收叶,死亡現(xiàn)場離奇詭異骄呼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)判没,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門蜓萄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人澄峰,你說我怎么就攤上這事嫉沽。” “怎么了俏竞?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵绸硕,是天一觀的道長。 經(jīng)常有香客問我魂毁,道長玻佩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任席楚,我火速辦了婚禮咬崔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烦秩。我一直安慰自己垮斯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布只祠。 她就那樣靜靜地躺著兜蠕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抛寝。 梳的紋絲不亂的頭發(fā)上牺氨,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天狡耻,我揣著相機(jī)與錄音,去河邊找鬼猴凹。 笑死夷狰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的郊霎。 我是一名探鬼主播沼头,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼书劝!你這毒婦竟也來了进倍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤购对,失蹤者是張志新(化名)和其女友劉穎猾昆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骡苞,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垂蜗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了解幽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贴见。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖躲株,靈堂內(nèi)的尸體忽然破棺而出片部,到底是詐尸還是另有隱情,我是刑警寧澤霜定,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布档悠,位于F島的核電站,受9級特大地震影響望浩,放射性物質(zhì)發(fā)生泄漏站粟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一曾雕、第九天 我趴在偏房一處隱蔽的房頂上張望奴烙。 院中可真熱鬧,春花似錦剖张、人聲如沸切诀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幅虑。三九已至,卻和暖如春顾犹,著一層夾襖步出監(jiān)牢的瞬間倒庵,已是汗流浹背褒墨。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留擎宝,地道東北人郁妈。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像绍申,于是被迫代替她去往敵國和親噩咪。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359