Android JNI和NDK簡單使用

一:JNI介紹

1.簡介:Java Native Interface,即java本地接口,本地接口就是指用C和C++開發的接口。

2.由來:實際使用中,java需要與本地代碼進行交互,因為java具備跨平臺的特點,所以java與本地代碼交互能力非常弱,所以采用JNI特性增強java與本地代碼交互的能力。

3.作用:使得java與本地其他類型語言(如c、c++)交互,即在java代碼里調用c、c++等語言的代碼或c、c++代碼調用java代碼。

4.JNI開發主要流程:

(1) 編寫聲明了native方法的Java類

(2) 將Java源代碼編譯成class字節碼文件

(3)用javah -jni命令生成.h頭文件(javah是jdk自帶的一個命令,-jni參數表示將class中用native聲明的函數生成JNI規則的函數)

(4) 用本地代碼實現.h文件中的函數

(5) 將本地代碼編譯成動態庫(Windows:\*.dll,linux/unix:\*.so,mac os x:\*.jnilib)

(6) 拷貝動態庫至java.library.path本地庫搜索目錄下,并運行Java程序。

5.注意點:(1) JNI是java調用Native語言的一種特性, (2) JNI是屬于java的,與Android沒有直接關聯。

二:NDK介紹

1.簡介:Native Development Kit,是Android的一個開發工具包,NDK是屬于Android,與java沒有直接關聯

2.作用:快速開發c、c++的動態庫,并自動將so和應用一起打包成APK即可通過NDK在android中,使用JNI與本地代碼(如c、c++)交互。

3.應用場景:在Android的場景下使用JNI即Android開發的功能需要本地代碼(c\c++)實現。

4.特點:用下面的圖來直觀的了解它的特點

5.使用流程:

(1) 配置Android NDK環境

(2) 創建Android項目,并于NDK關聯

(3) 在Android項目中生命所需要調用的Native方法

(4) 使用Android需要交互的本地代碼,實現在Android中聲明的Native方法,比如Android需要與C++交互,那么就用C++實現Java的Native方法

(5) 通過ndk-build命令編譯產生.so庫文件

(6) 編譯Android Studio工程,從而實現Android 調用本地代碼

6.額外注意點:

三:NDK與JNI關系:

1.NDK與JNI關系:NDK可以為我們生成了C/C++的動態鏈接庫,JNI是java和C/C++溝通過的接口,兩者與android沒有半毛錢關系,只因為安卓是java程序語言開發,然后通過JNI又能與C/C++溝通,所以我們可以使用NDK+JNI來實現Java+C的開發方式。

2.使用NDK開發的好處:

(1) 項目需要調用底層的一些C/C++的一些東西(java無法直接訪問到操作系統底層(系統硬件等)),或者已經在C/C++環境下實現了功能代碼(大部分現存的開源庫都是用C/C++代碼編寫的。)直接使用即可

(2) 為了效率更加高效些。將要求高性能的應用邏輯使用C/C++開發,從而提高應用程序的執行效率。但是C/C++代碼雖然是高效的,在java與C/C++相互調用時卻增大了開銷

(3) 基于安全性考慮。防止代碼被反編譯,為了安全起見,使用C/C++語言來編寫重要的部分以增大系統的安全性,最后生成so庫(用過第三方庫的應該都不陌生)便于給人提供方便

(4) 便于移植。用C/C++寫的庫可以方便在其他的嵌入式平臺上再次使用

四:配置及具體使用

1.下載安裝NDK:NDK的下載方式有兩種方式,可以直接去 https://developer.android.com/ndk/downloads?hl=zh-cn;另一種就是直接在我們的Android Studio中下載,打開我們Studio項目下的Project Structure界面,如下:

在SDK Location目錄下,有SDK和NDK的路徑,我這里已經安裝NDK。如果還沒有安裝配置過NDK,Android Studio會提示下載Android NDK如下圖:

點擊Download Android NDK來進行下載。這里Android Studio會下載最新版本的NDK進行安裝,默認會下載保存在SDK的路徑下。我們在上圖中還能看到有一段介紹文字,說SDK以及NDK的路徑配置會保存在local.properties文件內,安裝完成后我們刷新Project,進local.properties文件查看也能看到SDK與NDK的路徑。

注意:以前有些版本需要在gradle.properties文件中加上一行? android.useDeprecatedNdk=true ,3.0版本不再支持了。

2.添加插件:為了省去控制臺輸入命令麻煩。我們借助強大的Android Studio的插件功能,在External Tools下配置兩個非常有用的插件。進入Setting->Tools->ExternalTools,點擊+號增加,如下圖:

3.javah -jni命令:根據java文件生成.h頭文件,會自動根據java文件中的類名(包含包名)與方法名生成對應的C/C++里面的方法名。

參數及其含義:

(1) Program:$JDKPath$\bin\javah\java.exe這里配置的是JDK目錄下的javah.exe的路徑

(2) Parametes:-classpath .-jni -d $ModuleFileDir$/src/main/jni $FileClass$ 這里$FileClass$指的是要執行操作的類名(類的全名(包名+類名))(即我們操作的文件),$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頭文件(名字有點長,可以自己重命名)

4.ndk-build命令:

ndk -build命令,是根據C/C++文件生成so文件的,具體參數配置及其含義:

(1) Program:F:\apk\sdk\ndk-bundle\ndk-build.cmd這里配置的是ndk下的ndk-build.cmd的路徑(根據實際情況填寫)

(2) Working:$ModuleFileDir$\src\main\

5.使用方法:選中C/C++文件->右鍵->External Tools->ndk-build,將在main文件夾下生成libs文件夾以及多個so文件,我們可以移動至jniLibs目錄下去,接下來通過一個簡單的實例來了解它的使用。

(1) 創建Java類:隨意創建一個訪問本地C/C++方法的java類:

? ? ? ? public class JniTest {

? ? ? ? /** * 將用C++代碼實現,在android代碼中調用的方法:獲取一段文字 */ public static native String? ? ? ? getStrFromC();

? ? ? ? /** * 配置加載的so庫的文件名字===>如 :libmyLib.so */

? ? ? ? static {?

? ? ? ? System.loadLibrary("myLib");

? ? ? ? ? ? }

? ? ? ? }

(2) 該類的getStrFromC會報錯提示,不用管。

生成.h頭文件:對該文件執行javah -jni操作,生成對應的.h頭文件。

如圖,已經根據我們的java類在jni文件夾下生成了對應的.h文件,文件名為包名類名.h,我們可以手動改.h文件名,里面只有一個方法,返回值為String(jstring),方法名為java類的包名類名方法名(包名中的分級不是用.而是_),前面兩個參數是C++里面必須有的(JNIEnv代表指向JVM的指針,jclass是調用該方法的java對象),第三個jobject就是我們java類的方法里面的參數Object。注意,這是java函數與C++函數對應的靜態注冊方法,即通過特定的規則來寫。此處方法名可以隨意起名字,然后還可以用動態注冊的方式關聯兩個方法。

(3) 創建C或C++文件:在jni文件夾下,新建一個.c(c語言)或者.cpp(C++)的文件,來實現.h文件里聲明的方法:把.h文件里面聲明的方法拷貝到新建的c文件里面,然后在文件里面引入.h文件,如下圖:

至此,.h文件和c++文件已完成,想生成so文件還需要在這個jni目錄下增加兩個文件,Android.mk和Application.mk。

注意LOCAL_MODULE的值與之前的java類中設置要生成so庫的名字相對應,LOCAL_SRC_FILES的值寫C++文件的名字,這兩個值成對設置,可設置多組。(:=是賦值的意思,$是引用某變量的值)

LOCAL_PATH := $(call my-dir)? ? // 設置當前的編譯目錄(Android.mk所在的目錄)

include $(CLEAR_VARS)? ? ? ? ? ? // 清除LOCAL_XX變量(LOCAL_PATH除外)

LOCAL_MODULE := myLib // 指定當前編譯模塊的名稱?

LOCAL_SRC_FILES := jnittest.c? ? // 編譯模塊需要的源文件

include $(BUILD_SHARED_LIBRARY)

// 指定編譯出的庫類型,BUILD_SHARED_LIBRARY:動態庫;BUILD_STATIC_LIBRARY:靜態庫, BUILD_EXECUTEABLE指:可執行文件

在一個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,APP_ABI有四種類型(默認armeabi),armeabi、armeabi-v7a、x86、mips,設置時以空格隔開,all表示所有。該文件中有個可選配置的APP_MODULES,類似于上面Android.mk文件中的LOCAL_MODUEL,以空格隔開,且會覆蓋掉Android.mk文件中的LOCAL_MODULE設置(比如Android.mk文件中的寫了兩個jni庫的配置,LOCAL_MODULE:=JNI1、LOCAL_MODULE:=JNI2,而Application.mk中設置的APP_MODULES:=JNI1,則只能生成JNI1的so文件,要生成JNI2的so文件的時候會報錯,除非寫成APP_MODULE:=JNI1 JNI2,這里我們直接省略默認使用Android.mk中的)

APP_ABI := all,生成so文件對C++文件執行ndk-build操作,生成相應的so文件

如圖,在main/libs目錄下生成了多個so文件,名字為lib+我們指定的庫名(同時還生成了obj文件夾,中間文件)。這時候我們可以生成的main/libs文件夾內的東西復制到app/libs下,并刪除main下新生成的jni、libs、obj三個文件夾。

配置app/gradle:

調用在Activity中測試調用,在TextView上顯示我們通過C++代碼實現的方法getStrFromC獲取字符串。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 如有侵權,請及時于我聯系

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容