Andoird 中使用了一種不同傳統(tǒng)Java JNI的方式來定義其native的函數(shù)。其中很重要的區(qū)別是Andorid使用了一種Java 和 C 函數(shù)的映射表數(shù)組,并在其中描述了函數(shù)的參數(shù)和返回值。這個(gè)數(shù)組的類型是JNINativeMethod,定義如下:
typedef struct {const char* name;const char* signature;void* fnPtr;} JNINativeMethod;
第一個(gè)變量name是Java中函數(shù)的名字。
第二個(gè)變量signature,用字符串是描述了函數(shù)的參數(shù)和返回值
第三個(gè)變量fnPtr是函數(shù)指針,指向C函數(shù)。
其中比較難以理解的是第二個(gè)參數(shù),例如
"()V" "(II)V" "(Ljava/lang/String;Ljava/lang/String;)V"
實(shí)際上這些字符是與函數(shù)的參數(shù)類型一一對(duì)應(yīng)的。
“()” 中的字符表示參數(shù),后面的則代表返回值。例如”()V” 就表示void Func();
“(II)V” 表示 void Func(int, int);
具體的每一個(gè)字符的對(duì)應(yīng)關(guān)系如下
字符 Java類型 C類型 長度
V void void n/aZ jboolean boolean 8I jint int 32J jlong long 64D jdouble double 64F jfloat float 32B jbyte byte 8C jchar char 16S jshort short 16
數(shù)組則以”[“開始,用兩個(gè)字符表示
[I jintArray int[][F jfloatArray float[][B jbyteArray byte[][C jcharArray char[][S jshortArray short[][D jdoubleArray double[][J jlongArray long[][Z jbooleanArray boolean[]
上面的都是基本類型。如果Java函數(shù)的參數(shù)是class,則以”L”開頭,以”;”結(jié)尾中間是用”/” 隔開的包及類名。而其對(duì)應(yīng)的C函數(shù)名的參數(shù)則為jobject. 一個(gè)例外是String類,其對(duì)應(yīng)的類為jstring
Ljava/lang/String; String jstringLjava/net/Socket; Socket jobject
如果JAVA函數(shù)位于一個(gè)嵌入類,則用$作為類名間的分隔符。
例如 “(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z”
字符操作
◆GetStringUTFChars 將jstring轉(zhuǎn)換成為UTF-8格式的char*
◆GetStringChars 將jstring轉(zhuǎn)換成為Unicode格式的char*
◆ReleaseStringUTFChars 釋放指向UTF-8格式的char*的指針
◆ReleaseStringChars 釋放指向Unicode格式的char*的指針
◆NewStringUTF 創(chuàng)建一個(gè)UTF-8格式的String對(duì)象
◆NewString 創(chuàng)建一個(gè)Unicode格式的String對(duì)象
◆GetStringUTFLength 獲取UTF-8格式的char*的長度
◆GetStringLength 獲取Unicode格式的char*的長度
注冊(cè)JNI
static int registerMethods(JNIEnv* env) {static const char* const kClassName ="com/taner/ledservice/LedService";jclass clazz; /* look up the class */clazz = env->FindClass(kClassName);if (clazz == NULL) {LOGE("Can't find class %s\n", kClassName);return -1;} /* register all the methods */if (env->RegisterNatives(clazz, gMethods,sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK){LOGE("Failed registering methods for %s\n", kClassName);return -1;} /* fill out the rest of the ID cache */return 0;}
JNI_OnLoad
jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env = NULL;jint result = -1;LOGI("JNI_OnLoad"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {LOGE("ERROR: GetEnv failed\n");goto fail;}assert(env != NULL); if (registerMethods(env) != 0) {LOGE("ERROR: PlatformLibrary native registration failed\n");goto fail;} /* success -- return valid version number */result = JNI_VERSION_1_4; fail:return result;}