一乡数、NDK
什么是NDK炼绘?
在Android OS上開發(fā)應(yīng)用程序嗅战,Google提供了兩種開發(fā)包:SDK和NDK。
NDK---全稱:Native Develop Kit俺亮,是Android的一個工具開發(fā)包
Android的開發(fā)語言是Java驮捍,而且Android是基于Linux的,其核心庫很多都是C/C++代碼的一個工作脚曾。NDK其實本身其實就是一個交叉工作鏈嘹悼,包含了Android上的一些庫文件义钉,而且NDK為了方便使用心赶,提供了一些腳本严沥,使得更容易編譯C/C++代碼。簡單的來說囤踩,Android NDK就是一套工具集合旨椒,允許你使用C/C++語言來實現(xiàn)應(yīng)用程序的部分功能。
為什么要使用NDK堵漱?NDK的優(yōu)點综慎?
作用
快速開發(fā)c、c++的動態(tài)庫勤庐,并自動將so和應(yīng)用一起打包成APK示惊,即可通過NDK在android中,使用JNI與本地代碼(如c愉镰、c++)交互
應(yīng)用場景
在Android的場景下使用JNI即Android開發(fā)的功能需要本地代碼(c\c++)實現(xiàn)
額外注意
NDK提供了把.so和.apk打包的工具,而JNI開發(fā)沒有米罚,只是把.so文件放到文件按系統(tǒng)的特定位置
NDK提供的庫有限,僅用于處理算法效率和處理敏感的問題
提供了交叉編譯器丈探,用于生成特定的CPU平臺動態(tài)庫
NDK到SO
因為C語言的不跨平臺性录择,需要使用NDK編譯Linux下能執(zhí)行的函數(shù)庫---so文件(其本質(zhì)就是一堆C、C++的頭文件和實現(xiàn)文件打包成一個庫)目前Android系統(tǒng)支持以下七種不用的CPU架構(gòu),每一種對應(yīng)著各自的應(yīng)用程序二進制接口ABI:(Application Binary Interface)定義了二進制文件(尤其是.so文件)如何運行在相應(yīng)的系統(tǒng)平臺上隘竭,從使用的指令集塘秦,內(nèi)存對齊到可用的系統(tǒng)函數(shù)庫。對應(yīng)關(guān)系如下:
ARMv5——armeabi
ARMv7 ——armeabi-v7a
ARMv8——arm64- v8a
x86——x86
MIPS ——mips
MIPS64——mips64
x86_64——x86_64
二动看、JNI
什么是JNI尊剔?
JNI,全稱:Java Native Interfave,即Java本地接口菱皆,JNI是Java調(diào)用Native語言的一種特性须误。通過JNI可以使得Java與C/C++交互,即可以在Java代碼中調(diào)用C/C++等語言的代碼或者在C/C++代碼中調(diào)用Java代碼仇轻。
但是開發(fā)JNI程序會受到系統(tǒng)環(huán)境限制京痢,因為用C/C++ 語言寫出來的代碼或模塊,編譯過程當(dāng)中要依賴當(dāng)前操作系統(tǒng)環(huán)境所提供的一些庫函數(shù)拯田,并和本地庫鏈接在一起历造。而且編譯后生成的二進制代碼只能在本地操作系統(tǒng)環(huán)境下運行,因為不同的操作系統(tǒng)環(huán)境船庇,有自己的本地庫和CPU指令集,這個時候就需要NDK將本地代碼在不同的操作系統(tǒng)平臺下編譯出相應(yīng)的動態(tài)庫侣监。
為什么需要JNI
實際使用中鸭轮,java需要與本地代碼進行交互,因為java具備跨平臺的特點橄霉,所以java與本地代碼交互能力非常弱窃爷,所以采用JNI特性增強java與本地代碼交互的能力。
作用
使得java與本地其他類型語言(如c姓蜂、c++)交互即在java代碼里調(diào)用c按厘、c++等語言的代碼或c、c++代碼調(diào)用java代碼钱慢。
JNI開發(fā)流程6步驟
1.編寫聲明了native方法的Java類
2.將Java源代碼編譯成class字節(jié)碼文件
3.用javah -jni命令生成.h頭文件(javah是jdk自帶的一個命令逮京,-jni參數(shù)表示將class中用native聲明的函數(shù)生成JNI規(guī)則的函數(shù))
4.用本地代碼實現(xiàn).h文件中的函數(shù)
5.將本地代碼編譯成動態(tài)庫(Windows:\*.dll,linux/unix:\*.so,mac os x:\*.jnilib)
6.拷貝動態(tài)庫至java.library.path本地庫搜索目錄下,并運行Java程序束莫。
特別注意
1.JNI是java調(diào)用Native語言的一種特性
2.JNI是屬于java的懒棉,與Android無直接關(guān)系
三、在Android studio中配置---我使用的是Android studio3.4.1
1.下載NDK
首先找到studio右上角的SDK Manager 并點擊
然后找到下方的SDK tools览绿,找到LLDB,CMake,NDK下載策严,然后apply 和OK 即可
接著找到我們的SDK location,然后將NDK的路徑填寫在紅框中的地方饿敲,如果是studio中下載的SDK妻导,路徑就在配置的sdk文件夾中,配置好后點擊OK 即可
SDK以及NDK的路徑配置會保存在local.properties文件內(nèi),安裝完成后刷新Project倔韭,進local.properties文件查看就能看到SDK與NDK的路徑术浪。
注意:以前有些版本需要在gradle.properties文件中加上一行android.useDeprecatedNdk=true,3.0版本不再支持了狐肢。
2.添加插件
為省去控制臺輸入命令麻煩添吗。我們借助強大的Android Studio的插件功能,在External Tools下配置兩個非常有用的插件份名。進入Setting->Tools->ExternalTools,點擊+號增加碟联。
javah -jni命令
javah -jni命令,根據(jù)java文件生成.h頭文件僵腺,會自動根據(jù)java文件中的類名(包含包名)與方法名生成對應(yīng)的C/C++里面的方法名鲤孵。下面是參數(shù)配置及其含義:
1.Program:$JDKPath$\bin\javah\java.exe這里配置的是JDK目錄下的javah.exe的路徑。
2.Arguments:-classpath $ModuleFileDir$\src\main\java -jni -d $ModuleFileDir$\src\main\jni $FileClass$
注:在老版本的studio中沒有Arguments辰如,為Parametes:-classpath .-jni -d $ModuleFileDir$/src/main/jni $FileClass$ 這里$FileClass$指的是要執(zhí)行操作的類名(類的全名(包名+類名))(即我們操作的文件)普监,$ModuleFileDir$/src/main/jni表示生成的文件保存在這個module目錄的src/main/jni目錄下。
3.Working :$ModuleFileDir$\src\main\java表示module目錄下的src\main\java目錄琉兜。使用方式:選中java文件->右鍵->External Tools->javah -jni,將生成jni文件夾以及文件夾下的包名.類名的.h頭文件(名字有點長凯正,可以自己重命名)。
ndk -build命令
ndk -build命令,是根據(jù)C/C++文件生成so文件的豌蟋。下面是參數(shù)配置及其含義:
1.Program:F:\apk\sdk\ndk-bundle\ndk-build.cmd這里配置的是ndk下的ndk-build.cmd的路徑(根據(jù)實際情況填寫
2.Working:$ModuleFileDir$\src\main\
使用方法:選中C/C++文件->右鍵->External Tools->ndk-build,將在main文件夾下生成libs文件夾以及多個so文件廊散,我們可以移動至jniLibs目錄下去。
四梧疲、簡單使用
1.創(chuàng)建java類隨意創(chuàng)建一個訪問本地C/C++方法的java類允睹,生成.h頭文件,然后對該文件執(zhí)行javah -jni操作幌氮,生成對應(yīng)的.h頭文件缭受。
如圖,已經(jīng)根據(jù)我們的java類在jni文件夾下生成了對應(yīng)的.h文件该互,文件名為包名類名.h米者,我們可以手動改.h文件名,里面只有一個方法慢洋,返回值為String(jstring)塘雳,方法名為java類的包名類名方法名(包名中的分級不是用.而是_),前面兩個參數(shù)是C++里面必須有的(JNIEnv代表指向JVM的指針普筹,jclass是調(diào)用該方法的java對象)败明,第三個jobject就是我們java類的方法里面的參數(shù)Object。注意太防,這是java函數(shù)與C++函數(shù)對應(yīng)的靜態(tài)注冊方法妻顶,即通過特定的規(guī)則來寫酸员。此處方法名可以隨意起名字,然后還可以用動態(tài)注冊的方式關(guān)聯(lián)兩個方法讳嘱。
2.創(chuàng)建c或c++文件
在jni文件夾下幔嗦,新建一個.c(c語言)或者.cpp(C++)的文件,來實現(xiàn).h文件里聲明的方法:
把.h文件里面聲明的方法拷貝到新建的c文件里面沥潭,然后在文件里面引入.h文件邀泉,如下圖:
至此,.h文件和c++文件已完成钝鸽,想生成so文件還需要在這個jni目錄下增加兩個文件汇恤,Android.mk和Application.mk。
Android.mk
注意LOCAL_MODULE的值與之前的java類中設(shè)置要生成so庫的名字相對應(yīng)拔恰,LOCAL_SRC_FILES的值寫C++文件的名字因谎,這兩個值成對設(shè)置,可設(shè)置多組颜懊。(:=是賦值的意思财岔,$是引用某變量的值)
LOCAL_PATH := $(call my-dir) ????// 設(shè)置當(dāng)前的編譯目錄(Android.mk所在的目錄)
include $(CLEAR_VARS) ???????????// 清除LOCAL_XX變量(LOCAL_PATH除外)
LOCAL_MODULE := myLib // 指定當(dāng)前編譯模塊的名稱 ?
LOCAL_SRC_FILES := jnittest.c ???// 編譯模塊需要的源文件
include $(BUILD_SHARED_LIBRARY)
?// 指定編譯出的庫類型,BUILD_SHARED_LIBRARY:動態(tài)庫河爹;BUILD_STATIC_LIBRARY:靜態(tài)庫匠璧, BUILD_EXECUTEABLE指:可執(zhí)行文件
在一個Android.mk文件中配置多個Module的方式如下(include $(CLEAR_VARS)、include $(BUILD_SHARED_LIBRARY)兩個語句也需要加上)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myLib
LOCAL_SRC_FILES := jnittest.c
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := myLib2
LOCAL_SRC_FILES := jnittest2.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
Application.mk咸这,APP_ABI有四種類型(默認armeabi)患朱,armeabi、armeabi-v7a炊苫、x86、mips冰沙,設(shè)置時以空格隔開侨艾,all表示所有。該文件中有個可選配置的APP_MODULES,類似于上面Android.mk文件中的LOCAL_MODUEL,以空格隔開拓挥,且會覆蓋掉Android.mk文件中的LOCAL_MODULE設(shè)置(比如Android.mk文件中的寫了兩個jni庫的配置唠梨,LOCAL_MODULE:=JNI1、LOCAL_MODULE:=JNI2,而Application.mk中設(shè)置的APP_MODULES:=JNI1,則只能生成JNI1的so文件侥啤,要生成JNI2的so文件的時候會報錯当叭,除非寫成APP_MODULE:=JNI1 JNI2,這里我們直接省略默認使用Android.mk中的)
APP_ABI := all
生成so文件
對C++文件執(zhí)行ndk-build操作,生成相應(yīng)的so文件
如圖盖灸,在main/libs目錄下生成了多個so文件蚁鳖,名字為lib+我們指定的庫名(同時還生成了obj文件夾,中間文件)赁炎。這時候我們可以生成的main/libs文件夾內(nèi)的東西復(fù)制到app/libs下醉箕,并刪除main下新生成的jni、libs、obj三個文件夾讥裤。
在項目的build.gradle中配置app/gradle
調(diào)用
在Activity中測試調(diào)用放棒,在TextView上顯示我們通過C++代碼實現(xiàn)的方法getStrFromC獲取字符串。
//配置加載的so庫的文件名字===>如 :libmyLib.so */
?static { ?
?????? System.loadLibrary("myLib");
?}
Android studio 下載NDK和構(gòu)建工具
1.Android原生開發(fā)工具包(NDK):這套工具集允許您開發(fā)Android使用C和C++代碼己英,并提供眾多平臺庫间螟,讓您可以管理原生Activity和訪問物理設(shè)備組件,例如傳感器和觸摸輸入损肛。
2.CMake:一款外部構(gòu)建工具厢破,可與Gradle搭配使用來構(gòu)建原生庫。如果您只計劃使用ndk-build荧关,則不需要此組件溉奕。
3.LLDB:一種調(diào)試程序,Android Studio使用它來調(diào)試原生代碼忍啤。
注:在前面下載ndk的時候已經(jīng)提示過如何下載
創(chuàng)建支持C/C++的新項目
創(chuàng)建支持原生代碼的項目與創(chuàng)建任何其他Android Studio項目類似加勤,不過支持原生代碼的項目還需要額外幾個步驟:
1.在向?qū)У?b>Configure your new project部分,選中Include C++ Support復(fù)選框同波。
2.點擊Next鳄梅。
3.正常填寫所有其他字段并完成向?qū)Ы酉聛淼膸讉€部分。
4.在向?qū)У?b>Customize C++ Support部分未檩,您可以使用下列選項自定義項目
1.C++ Standard:使用下拉列表選擇您希望使用哪種C++標準戴尸。選擇 Toolchain Default 會使用默認的CMake 設(shè)置,這個選項如果你現(xiàn)在還不確定該選哪個冤狡,最好選擇C++11的標準孙蒙。
2.Exceptions Support:如果您希望啟用對C++異常處理的支持,請選中此復(fù)選框悲雳。如果啟用此復(fù)選框挎峦,Android Studio 會將 -fexceptions 標志添加到模塊級 build.gradle 文件的 cppFlags 中,Gradle 會將其傳遞到 CMake合瓢。
3.Runtime Type Information Support:如果您希望支持RTTI坦胶,請選中此復(fù)選框。如果啟用此復(fù)選框晴楔,Android Studio 會將 -frtti 標志添加到模塊級 build.gradle 文件的 cppFlags 中顿苇,Gradle 會將其傳遞到 CMake。