android — JNI注册方法说明
Jni中還可以采用RegisterNatives來注冊jni的方法,注冊以后的jni函數的命名可以不需要符合類似javah命令生成的函數的規則
RegisterNatives為JNIEnv的成員函數,聲明為:
??? jint (JNICALL *RegisterNatives) (JNIEnv *env, jclass clazz, const JNINativeMethod *methods,jint nMethods);
其對應的取消注冊的函數為聲明為:
??? jint (JNICALL *UnregisterNatives) (JNIEnv *env, jclass clazz);
在java中調用System.loadLibrary("somelib");的時候,系統會自動調用jni的函數JNI_OnLoad,
在程序退出的時候,系統卸載“somelib”,會自動調用jni的函數JNI_OnUnload,
所以我們需要在jni的接口文件中重寫這兩個函數
以上一篇建立的HelloJni的例子來說明:
先定義一個字符串,內容為類名const char* JNIT_CLASS = "com/example/hellojni/HelloJni";
再定義一個函數的說明的數組
static JNINativeMethod gMethods[] = {
?? ??? ?{"stringFromJNI", "()Ljava/lang/String;",(void*)stringFromJNI},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
?? ?JNIEnv *env = NULL;
?? ?if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)){
?? ??? ?return JNI_ERR;
?? ?}
??? jclass cls = (*env)->FindClass(env, JNIT_CLASS);
?? ?if (cls == NULL)
?? ?{
?? ??? ?return JNI_ERR;
?? ?}
?? ?jint nRes = (*env)->RegisterNatives(env, cls, gMethods, sizeof(gMethods)/sizeof(gMethods[0]));
?? ?if (nRes < 0)
?? ?{
?? ??? ?return JNI_ERR;
?? ?}
?? ?return JNI_VERSION_1_4;
}
JNIEXPORT void JNICALL
JNI_OnUnLoad(JavaVM *jvm, void *reserved)
{
?? ?JNIEnv *env = NULL;
?? ?if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)){
?? ??? ?return;
?? ?}
?? ?jclass cls = (*env)->FindClass(env, JNIT_CLASS);
?? ?if (cls == NULL)
?? ?{
?? ??? ?return;
?? ?}
?? ?jint nRes = (*env)->UnregisterNatives(env, cls);
?? ?return;
}
其中JNIT_CLASS 表示的是要調用jni的java類的名稱
gMethods[]為RegisterNatives的第三個函數,表示的是所有jni的函數的集合。
JNINativeMethod是表示jni方法的結構體,其結構如下:
typedef struct {
?? ?
?? ? char *name;
???? char *signature;
????? void *fnPtr;
} JNINativeMethod;
第一個變量name為java類中native函數的名稱,
第二個變量signature為java類中native函數的java類型描述,
第三個變量fnPtr為jni中對應的函數名稱,格式為類似(void*)MethodName,
函數和變量的java類型描述可以通過命令 javap -s -p classname來獲得,classname與使用javah時寫的名稱一致,javah生成的頭文件的每個函數的注釋中也有這個描述
對于“()Ljava/lang/String;”一個描述,表示該函數沒有參數,返回值為String。括號內的是參數列表,后面跟的是返回值
java中簡單類型和jni中的描述的對應關系如下表所示:
| Field Descriptor | Java Language Type |
| Z | boolean |
| B | byte |
| C | char |
| S | short |
| I | int |
| J | long |
| F | float |
| D | double |
?
對于復雜類型,字符串描述以“L”開頭,以“;”結束,例如java中的 String ,在jni中的描述為"Ljava/lang/String;"
對于數組,以“[”開頭,接類型描述,例如int[ ],在jni中的描述為“[I”;String[ ], 對應為“[Ljava/lang/String;”;如果是數組維數增加一維,則"["增加一個,例如int[ ][ ],對應為“[[I”;
?
以上內容具體參見《The Java? Native? Interface?? Programmer’s Guide and Specification》一書,JNI中使用的各類型參見第12章 JNI TYPE
在使用JNI_OnLoad之時,我們不能把classname傳遞給jni,所以const char* JNIT_CLASS 是一個固定的名稱,我們在生成SO文件的同時這個classname就固定下來了,所以,當提供so文件的同時,需要提供一個調用該so文件的java文件,類似c++中提供dll時需要提供的.h文件一樣。
轉載于:https://www.cnblogs.com/xunbu7/p/4183368.html
總結
以上是生活随笔為你收集整理的android — JNI注册方法说明的全部內容,希望文章能夠幫你解決所遇到的問題。