Android NDK開發(fā)(二) 底層實(shí)現(xiàn)HEX的編碼和解碼

開始之前

本篇博文承接上篇Android NDK開發(fā)(一) 入門, 如果大家沒有接觸過NDK開發(fā)請(qǐng)移至上篇
本篇主要通過HEX的編碼和解碼案例來進(jìn)一步了解NDK的開發(fā).

什么是HEX ?

就是16進(jìn)制!

什么是HEX的編碼和解碼 ?

編碼: 就是將字節(jié)數(shù)組每個(gè)字節(jié)使用16進(jìn)制的可見字符串來顯示 bytes --> String

解碼: 就是將16進(jìn)制的可見字符串轉(zhuǎn)換為原來的字節(jié)數(shù)組 String --> bytes

來張圖說明一下:

HEX.png

開始開發(fā)

今天我們不采用上一篇中創(chuàng)建工程時(shí)直接勾選出 Include C++ Support, 而是創(chuàng)建一個(gè)普通的工程, 后期如何擴(kuò)展為NDK的工程

創(chuàng)建工程

  1. 創(chuàng)建普通工程, 修改local.properties文件, 添加ndk.dir=XXX;

  2. 手動(dòng)在app目錄下創(chuàng)建CMakeLists.txt文件, 內(nèi)容和注釋如下:

    # CMake的編譯腳本配置文件
    
    # 1. 標(biāo)注需要支持的CMake最小版本
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # 2. add_library 定義需要編譯的代碼庫(kù) 名稱, 類型, 包含的源碼
    
    add_library(
                # Sets the name of the library.
                codec
    
                # Sets the library as a shared library.
                SHARED
    
                src/main/cpp/com_lulu_encodedemo_Codec.c
    )
    
    # 3. find_library 定義當(dāng)前代碼庫(kù)需要依賴的系統(tǒng)或者第三方庫(kù)文件
    
    find_library(
    
            log_lib # 指定要查找的系統(tǒng)庫(kù), 給一個(gè)名字
            log     # 真正要查找的liblog.so或者liblog.a
    
    )
    
    # 可以寫多個(gè) find_library
    
    # 4. target_link_libraries設(shè)置最終編譯的目標(biāo)代碼庫(kù)
    
    target_link_libraries(
         codec  # add_library 生成的
    
         ${log_lib} # find_library 找到的系統(tǒng)庫(kù)
    )
    
    
  3. 修改app目錄下的build.gradle文件, 在android便簽下添加

        externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
    
  4. 在src/main目錄下創(chuàng)建cpp文件夾. 至此工程創(chuàng)建完畢

編寫業(yè)務(wù)邏輯

創(chuàng)建Codec.java類, 用于綁定C代碼


public class Codec {

    static {
        //一定不要忘記調(diào)用!!!!
        System.loadLibrary("codec");
    }
    public static native String hexEncode(byte[] data);
    public static native byte[] hexDecode(String data);
}

Note : 給大家忠告, System.loadLibrary("codec");一定不要忘記調(diào)用,否則會(huì)報(bào)一下錯(cuò)誤


Paste_Image.png

實(shí)現(xiàn)C語言核心部分

對(duì)應(yīng)Codec類有兩個(gè)方法分別用于編碼和解碼, 代碼中已經(jīng)做了詳細(xì)的注釋加以說明

  1. 編碼方法:

    // 代表可以被 Java 調(diào)用
    JNIEXPORT
    // 返回值類型
    jstring
    //聲明遵守JNI Java 調(diào)用C的規(guī)則
    JNICALL
    Java_com_lulu_encodedemo_Codec_hexEncode(JNIEnv *env, jclass clazz, jbyteArray array) {
        // 1. 數(shù)組長(zhǎng)度斑司;2. new StringBuilder(); or char[len * 2] 3. char[] -> jstring
        jstring ret = NULL;
        if (array != NULL) {
            //得到數(shù)組的長(zhǎng)度
            jsize len = (*env)->GetArrayLength(env, array);
            if (len > 0) {
                //存儲(chǔ)編碼后的字符, +1的原因是考慮到\0
                char chs[len * 2 + 1];
                jboolean b = JNI_FALSE;
                //得到數(shù)據(jù)的原始數(shù)據(jù) 此處注意要取b的地址!
                jbyte *data = (*env)->GetByteArrayElements(env, array, &b);
                int index;
                for (index = 0; index < len; index++) {
                    jbyte bc = data[index];
                    //拆分成高位, 低位
                    jbyte h = (jbyte) ((bc >> 4) & 0x0f);
                    jbyte l = (jbyte) (bc & 0x0f);
                    //把高位和地位轉(zhuǎn)換成字符
                    jchar ch;
                    jchar cl;
    
                    if (h > 9) {
                        ch = (jchar) ('A' + (h - 10));
                    } else {
                        ch = (jchar) ('0' + h);
                    }
    
                    if (l > 9) {
                        cl = (jchar) ('A' + (l - 10));
                    } else {
                        cl = (jchar) ('0' + l);
                    }
                    //轉(zhuǎn)換之后拼接
                    chs[index * 2] = (char) ch;
                    chs[index * 2 + 1] = (char) cl;
                }
                //最后一位置為0
                chs[len * 2] = 0;
                //釋放數(shù)組
                (*env)->ReleaseByteArrayElements(env, array, data, JNI_ABORT);
                ret = (*env)->NewStringUTF(env, chs);
            }
    
        }
        return ret;
    }
    
    
  2. 解碼方法:

    
    JNIEXPORT jbyteArray JNICALL
    Java_com_lulu_encodedemo_Codec_hexDecode(JNIEnv *env, jclass type, jstring str) {
        jbyteArray ret = NULL;
        if (str != NULL) {
            // TODO
            jsize len = (*env)->GetStringLength(env, str);
            //判斷只有在長(zhǎng)度為偶數(shù)的情況下才繼續(xù)
            if (len % 2 == 0) {
                jsize dLen = len >> 1;
                jbyte data[dLen];
                jboolean b = JNI_FALSE;
                const jchar *chs = (*env)->GetStringChars(env, str, &b);
                int index;
                for (index = 0; index < dLen; index++) {
                    //獲取到單個(gè)字符
                    jchar ch = chs[index * 2];
                    jchar cl = chs[index * 2 + 1];
                    jint h = 0;
                    jint l = 0;
                    //得到高位和低位的 ascii
                    if (ch >= 'A') {
                        h = ch - 'A' + 10;
                    } else if (ch >= 'a') {
                        h = ch - 'a' + 10;
                    } else if(ch >= '0') {
                        h = ch - '0';
                    }
                    if (cl >= 'A') {
                        l = cl - 'A' + 10;
                    } else if (cl >= 'a') {
                        l = cl - 'a' + 10;
                    } else if(cl >= '0'){
                        l = cl - '0';
                    }
                    //高位和地位拼接
                    data[index] = (jbyte) ((h << 4) | l);
                }
                //釋放
                (*env)->ReleaseStringChars(env, str, chs);
                //創(chuàng)建新的字節(jié)數(shù)組
                ret = (*env)->NewByteArray(env, dLen);
                //給新創(chuàng)建的數(shù)組設(shè)置數(shù)值
                (*env)->SetByteArrayRegion(env, ret, 0,dLen, data);
            }
        }
        return ret;
    }
    

代碼測(cè)試:


String s = Codec.hexEncode(new byte[]{0x3c, 0x7c});
Log.d(TAG, "onCreate: s ==> " + s);
byte[] bytes = Codec.hexDecode(s);

for (byte aByte : bytes) {
    Log.d(TAG, "onCreate: byte ==> " + String.format(Locale.CANADA, "%x",aByte ));
}
        

測(cè)試結(jié)果:

D/MainActivity: onCreate: s ==> 3C7C
D/MainActivity: onCreate: byte ==> 3c
D/MainActivity: onCreate: byte ==> 7c

完整代碼

代碼已上傳至Github上, 歡迎大家Clone

總結(jié)

至此NDK的博客完成了, 本人也是菜鳥一枚, 希望更多的是拋磚引玉, 讓各位大神們指出修改意見!
寫博客不易, 期待大家的鼓勵(lì)和支持, 謝謝v

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妙蔗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子免猾,更是在濱河造成了極大的恐慌是辕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猎提,死亡現(xiàn)場(chǎng)離奇詭異获三,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锨苏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門疙教,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚓炬,你說我怎么就攤上這事松逊。” “怎么了肯夏?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵经宏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我驯击,道長(zhǎng)烁兰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任徊都,我火速辦了婚禮沪斟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己主之,他們只是感情好择吊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著槽奕,像睡著了一般几睛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上粤攒,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天所森,我揣著相機(jī)與錄音,去河邊找鬼夯接。 笑死焕济,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盔几。 我是一名探鬼主播晴弃,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼问欠!你這毒婦竟也來了肝匆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤顺献,失蹤者是張志新(化名)和其女友劉穎旗国,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體注整,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡能曾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肿轨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寿冕。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖椒袍,靈堂內(nèi)的尸體忽然破棺而出驼唱,到底是詐尸還是另有隱情,我是刑警寧澤驹暑,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布玫恳,位于F島的核電站,受9級(jí)特大地震影響优俘,放射性物質(zhì)發(fā)生泄漏京办。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一帆焕、第九天 我趴在偏房一處隱蔽的房頂上張望惭婿。 院中可真熱鬧,春花似錦、人聲如沸财饥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钥星。三九已至式散,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間打颤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工漓滔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留编饺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓响驴,卻偏偏與公主長(zhǎng)得像透且,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豁鲤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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