NDK Mapping 發(fā)布啦

首先感謝一下醫(yī)生,若是沒(méi)有你催命般的催稿,還真就沒(méi)有這篇了。作為催我的代價(jià),請(qǐng)客可樂(lè)是沒(méi)跑的了:)


首先,給出章魚(yú)貓地址:rarnu/ndkmapping


NDK Mapping 的主要工作就是完成 class 從 JVM 層到 JNI 層的映射。通常情況下,當(dāng)我們進(jìn)行 JNI 開(kāi)發(fā)時(shí),無(wú)可避免的要進(jìn)行類(lèi)的傳遞操作,而 JNI 提供的 API 卻讓代碼簡(jiǎn)單不起來(lái),大量的容易出錯(cuò)的體力勞動(dòng)也是這么來(lái)的。來(lái)看看以下的代碼:

DemoInc *ret = NULL;
if (env && obj) {
    ret = new DemoInc();
    jclass cls = env->FindClass("com/sample/DemoInc");
    jmethodID m = env->GetMethodID(cls, "getId", "()I");
    ret->id = env->CallIntMethod(obj, m);
}
return ret;

大家都能讀懂的吧?就是調(diào)用一下 JVM 層 DemoInc 類(lèi)的 getId 方法,卻花費(fèi)了如此多的代碼。那么再設(shè)想一下如果是操作 ListMap 或是其他復(fù)雜類(lèi)型呢?幾十行代碼都不一定做得下來(lái)。而這正是 NDK Mapping 誕生的初衷,即幫助開(kāi)發(fā)者完成類(lèi)的映射。


來(lái)個(gè)具體的實(shí)例看看效果吧,要特別說(shuō)明的是,NDK Mapping 接受的映射類(lèi)文件必須是 Kotlindata class,原因很簡(jiǎn)單,一方面是因?yàn)檫@樣的 class 足夠簡(jiǎn)單,方便解析,另一方面就是我懶??纯催@樣一個(gè) class:

data class Demo(
    var v1: Int, var v2: String, var v3: Context?, 
    var v4: IntArray?, var v5: List<String>?, var v6: Map<Int, View?>?
)

想一下用 JNI 來(lái)操作這樣的類(lèi)需要多少代碼,你是否還記得 ListAdd 方法簽名是什么樣的?當(dāng)然現(xiàn)在你說(shuō)不記得也沒(méi)關(guān)系了,在 NDK Mapping 的幫助下,開(kāi)發(fā)者不需要記憶任何與類(lèi)操作有關(guān)的東西。

簡(jiǎn)單的看一下 NDK Mapping 的命令參數(shù),當(dāng)直接輸入 ndkmapping 命令時(shí),即可看到如下的參數(shù)提示:

ndkmapping <options> <Kotlin Class File Path>

options:
    -l language (cpp, pas)
    -b build option (mk, mksh)
    -m max array size (must >= 0)
    -o output path

-l表示目標(biāo)語(yǔ)言,目前可以生成 C++ 和 Pascal 的類(lèi)映射,-b表示生成 Makefile,-m表示數(shù)組傳參時(shí),數(shù)組的最大下標(biāo),-o表示生成的文件輸出的位置,若是沒(méi)有該目錄,則會(huì)新建一個(gè)。當(dāng)然在最后還得再跟上 Kotlin Class 的所在目錄,ndkmapping 會(huì)自動(dòng)的映射所有的 class 文件。

完整的命令如下:

$ ndkmapping -l cpp -b mksh -m 100 -o ./out/ ./kotlin/
$ cd out
$ ./build.sh

是的,你沒(méi)有看錯(cuò),生成的代碼是可以直接編譯的,并不需要再經(jīng)過(guò)任何的修改,此時(shí)在 JNI 層的代碼內(nèi),就有了一個(gè)與 JVM 層形態(tài)完全一樣的類(lèi),可以直接操作。

而最關(guān)鍵的,是生成了兩個(gè)方法:

static Demo* Demo::fromJObject(JNIEnv *env, jobject obj);
jobject Demo::toJObject(JNIEnv *env);

顧名思議也很清晰了,一個(gè)是將 jobject 所對(duì)應(yīng)的類(lèi),翻譯成 JNI 的類(lèi),而另一個(gè),是將 JNI 的類(lèi)翻譯回 jobject。有了這兩個(gè)方法,就可以實(shí)現(xiàn)映射。而在實(shí)際開(kāi)發(fā)中,基本上也只需要調(diào)用這兩個(gè)方法,其他的一切操作,都是與平臺(tái)和語(yǔ)言本身相關(guān)的了。


下面是映射關(guān)系表,參考這個(gè)表,可以知道在生成代碼時(shí)的規(guī)則。

Kotlin C++ Pascal JNI
Int int Integer jint
Byte unsigned char Byte jbyte
Short short ShortInt jshort
Long long long Int64 jlong
Float float Extended jfloat
Double double Double jdouble
Boolean bool Boolean jboolean
Char char Char jchar
String string String jstring
List list FPGList jobject
Map map FPGMap jobject
Set set FPGList jobject
Array [array] [array] jobjectArray

對(duì)于一份生成好的代碼來(lái)說(shuō),進(jìn)行驗(yàn)證是有必要的。NDK Mapping 同樣也提供了驗(yàn)證的能力。使用 ndktester 即可。

ndktester <options> <Kotlin Class File Path>

options:
  -l language (java, kotlin)
  -x exported JNI code language (cpp, pas)
  -b build option (mk, mkshcp)
  -p base package name
  -c copy path
  -o output path

參數(shù)基本上都與ndkmapping類(lèi)似,要額外選擇驗(yàn)證代碼的語(yǔ)言,和原始生成的代碼語(yǔ)言,另外還需要用于 JVM 驗(yàn)證的包名,如果你需要在編譯驗(yàn)證庫(kù)后復(fù)制到其他項(xiàng)目中,可以使用-c參數(shù)。

命令的樣本如下:

ndktester -l kotlin -x cpp -b mkshcp -p com.sample.ndk -c ./jniLibs/ -o ./out/ ./kotlin/

此時(shí)就會(huì)生成用于 Kotlin 驗(yàn)證的代碼,直接引入到一個(gè)項(xiàng)目即可。

保險(xiǎn)起見(jiàn),另外還提供了一份較為復(fù)雜的類(lèi)的映射樣例代碼,可以從項(xiàng)目的 README 內(nèi)找到下載地址。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容