JNI 基礎(chǔ) - JNIEnv 的實(shí)現(xiàn)原理

一.JNI 開(kāi)發(fā)的一般流程

在 windows 系統(tǒng)上面我們經(jīng)常能看到很多類(lèi)似于 xxx.dll 的文件锈玉,在做 android 開(kāi)發(fā)的時(shí)候我們能看到很多 xxx.so 的文件。這些都是啥呢芹壕?其實(shí)就是用 c 和 c++ 實(shí)現(xiàn)生成的動(dòng)態(tài)庫(kù)窟绷,供 windows 和 android 系統(tǒng)來(lái)調(diào)用锯玛。

我們解壓 QQ 和支付寶的 apk 找到它的 libs 目錄下,會(huì)發(fā)現(xiàn)有大量的 .so 庫(kù)文件兼蜈,還有很多是動(dòng)態(tài)下載加載的我們看不到攘残,能看到的就已經(jīng)有好幾百個(gè)了。為什么要這么弄饭尝?直接就用 java 開(kāi)發(fā)不行嗎肯腕?其實(shí)好處有很多,比如安全钥平,高效实撒,跨平臺(tái)等等。今天我們就來(lái)看下 JNI 開(kāi)發(fā)的一般開(kāi)發(fā)流程涉瘾。

1.1 編寫(xiě) native 方法

public class NdkTest {
    public static void main(String[] args) {
        NdkTest ndkTest = new NdkTest();
        
        System.out.println("簽名密鑰:"+ndkTest.getSignaturePassword());
    }
    
    // 獲取簽名密鑰
    public native String getSignaturePassword();
    
    static{
        // 加載某個(gè)路徑下的動(dòng)態(tài)庫(kù)
        System.load("C:/Users/hcDarren/Desktop/android/NDK/NDK_Day12/x64/Debug/NDK_Day12.dll");
    }
}

1.2 生成 xxx.h 頭文件

javah -d ../jni -jni com.darren.ndk12.NdkTest

1.3 VS 編寫(xiě)實(shí)現(xiàn)方法生成 dll 動(dòng)態(tài)庫(kù)

// 引入頭文件
#include "com_darren_ndk12_NdkTest.h"

JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkTest_getSignaturePassword
(JNIEnv *env, jobject jobj){
    return (*env)->NewStringUTF(env,"940223");
}

二.詳解 .h 頭文件和實(shí)現(xiàn)文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h" // 引入頭 jni.h 文件
/* Header for class com_darren_ndk12_NdkTest */
// 打個(gè)標(biāo)記知态,防止反復(fù)引入 copy 內(nèi)容
#ifndef _Included_com_darren_ndk12_NdkTest
#define _Included_com_darren_ndk12_NdkTest
#ifdef __cplusplus 
// 如果是 c++ 則統(tǒng)一用 C 的編譯方式
// 會(huì)指示編譯器這部分代碼按C語(yǔ)言的進(jìn)行編譯,而不是C++的立叛。
// C語(yǔ)言并不支持函數(shù)重載负敏,因此編譯C語(yǔ)言代碼的函數(shù)時(shí)不會(huì)帶上函數(shù)的參數(shù)類(lèi)型,一般只包括函數(shù)名秘蛇。
extern "C" { 
#endif
/*
 * Class:     com_darren_ndk12_NdkTest
 * Method:    getSignaturePassword
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkTest_getSignaturePassword
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
// 引入頭文件
#include "com_darren_ndk12_NdkTest.h"
// JNIEXPORT:在Jni編程中所有本地語(yǔ)言實(shí)現(xiàn)Jni接口的一個(gè)標(biāo)志
// jstring:對(duì)應(yīng) java 中的數(shù)據(jù)類(lèi)型 String
// JNICALL:也是一個(gè)標(biāo)記可以去掉其做,編譯運(yùn)行也不會(huì)有問(wèn)題
// JNIEnv:c 與 java 相互調(diào)用的橋梁顶考,它提供了很多函數(shù)方法
// jobj:java 傳遞下來(lái)的對(duì)象,即上面的 NdkTest
JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkTest_getSignaturePassword
(JNIEnv *env, jobject jobj){
        //  通過(guò) JNIEnv 把 c 字符串轉(zhuǎn)為 jstring
    return (*env)->NewStringUTF(env,"940223");
}

三.JNIEnv 的實(shí)現(xiàn)原理

JNI 的基礎(chǔ)學(xué)習(xí)我們主要搞清 JNIEnv 就可以了妖泄,只要熟悉它里面的函數(shù)方法驹沿。但是學(xué)習(xí)的時(shí)候肯定不光要搞清它的方法函數(shù),還需要搞清它的實(shí)現(xiàn)原理蹈胡。如果有留意我之前寫(xiě)的一些文章你會(huì)發(fā)現(xiàn) c 和 c++ 有所不同渊季,c++ 是這樣的。

JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkTest_getSignaturePassword
(JNIEnv *env, jobject jobj){
    return env -> NewStringUTF("940223");
}

為什么會(huì)有這樣的不同罚渐?c++ 的實(shí)現(xiàn)方式我們后面的文章再去詳細(xì)講解却汉,我們先來(lái)模擬一下 c 的實(shí)現(xiàn)方式:

// 引入頭文件
#include <stdio.h>

// 定義結(jié)構(gòu)體指針別名
typedef const struct JNINativeInterface *JNIEnv;

// 定義一個(gè)結(jié)構(gòu)體
struct JNINativeInterface{
    // 定義的不是函數(shù),函數(shù)指針
    char*(*NewStringUTF)(JNIEnv*, char*);
};

// 只是做一個(gè)模擬
char* Java_com_darren_ndk12_NdkTest_getSignaturePassword(JNIEnv *env){
    return (*env)->NewStringUTF(env, "940223");
}

// NewStringUTF 方法的實(shí)現(xiàn)
char* NewStringUTF(JNIEnv* jniEnv, char* str){
    // 一連串的實(shí)現(xiàn) char* -> jstring
    return str;
}

void main(){
    // 中間還會(huì)有很多的流程荷并,我們能看到的就是調(diào)用 Java_com_darren_ndk12_NdkTest_getSignaturePassword
    // 模擬 JNIEnv 創(chuàng)建過(guò)程
    struct JNINativeInterface nativeInterface;
    nativeInterface.NewStringUTF = NewStringUTF;
    JNIEnv jniEnv = &nativeInterface;// 一級(jí)指針
    // Java_com_darren_ndk12_NdkTest_getSignaturePassword 參數(shù)需要的是 JNIEnv*
    JNIEnv* env = &jniEnv;// 雖然只有一個(gè) * 合砂,但是其實(shí)他是一個(gè)二級(jí)指針

    char* singnature = Java_com_darren_ndk12_NdkTest_getSignaturePassword(env);
    printf("singnature = %s", singnature);
    // 然后將 jstring 返回給 java

    getchar();
}

視頻鏈接:https://pan.baidu.com/s/1vyxCSn0SWo3-YnoD7Rzryw
視頻密碼:uqmc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市璧坟,隨后出現(xiàn)的幾起案子既穆,更是在濱河造成了極大的恐慌赎懦,老刑警劉巖雀鹃,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異励两,居然都是意外死亡黎茎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)当悔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)傅瞻,“玉大人,你說(shuō)我怎么就攤上這事盲憎⌒峤荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵饼疙,是天一觀的道長(zhǎng)溺森。 經(jīng)常有香客問(wèn)我,道長(zhǎng)窑眯,這世上最難降的妖魔是什么屏积? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮磅甩,結(jié)果婚禮上炊林,老公的妹妹穿的比我還像新娘。我一直安慰自己卷要,他們只是感情好渣聚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布独榴。 她就那樣靜靜地躺著,像睡著了一般奕枝。 火紅的嫁衣襯著肌膚如雪括眠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天倍权,我揣著相機(jī)與錄音掷豺,去河邊找鬼。 笑死薄声,一個(gè)胖子當(dāng)著我的面吹牛当船,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播默辨,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼德频,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缩幸?” 一聲冷哼從身側(cè)響起壹置,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎表谊,沒(méi)想到半個(gè)月后钞护,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡爆办,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年难咕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片距辆。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡余佃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跨算,到底是詐尸還是另有隱情爆土,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布诸蚕,位于F島的核電站步势,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏挫望。R本人自食惡果不足惜立润,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媳板。 院中可真熱鬧桑腮,春花似錦、人聲如沸蛉幸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至提陶,卻和暖如春烫沙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背隙笆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工锌蓄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撑柔。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓瘸爽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铅忿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剪决,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容