Android JNI的初步使用--1
上一篇做了一個jni靜态加載的示例,這一篇來看一下jni的方法的動态加載。
我先展示一下cpp中動态加載的示範代碼:
jstring fun1(JNIEnv *env, jobject jobj) {
std::string hello = "動态注冊";
return env->NewStringUTF(hello.c_str());
}
jstring fun2(JNIEnv *env, jobject jobj) {
std::string hello = "動态注冊";
LOGD("%s", hello.c_str());
return env->NewStringUTF(hello.c_str());
}
static const char *mClassName = "com/hao/minovel/jni/DragCrash";
static const JNINativeMethod mMethods[] = {
//參數一:java方法名
//參數二:()中為調用時需要的傳殘參類型後面為傳回類型
//參數三:jni中對應的方法
{"getString2", "()Ljava/lang/String;", (jstring *) fun1},
{"initDate", "(Lcom/hao/minovel/jni/Test;)Ljava/lang/String;", (jstring *) fun2},
};
//在調用java的load的時候 會調用此方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *res) {
JNIEnv *env = NULL; //獲得 JniEnv
int r = vm->GetEnv((void **) &env, JNI_VERSION_1_4);
if (r != JNI_OK) { return -1; }
jclass mainActivityCls = env->FindClass(mClassName); // 注冊 如果小于0則注冊失敗
r = env->RegisterNatives(mainActivityCls, mMethods, 2);//第三個參數為你需要加載的mMethods中的數量
if (r != JNI_OK) { return -1; }
return JNI_VERSION_1_4;
}
在上面的代碼中,我們需要關注的是JNI_Onload中的兩個方法
jclass mainActivityCls = env->FindClass(mClassName); // 注冊 如果小于0則注冊失敗
r = env->RegisterNatives(mainActivityCls, mMethods, 2);//第三個參數為你需要加載的mMethods中的數量
其中mClassName為java中的native方法的類路徑,FindClass方法會通過此路徑擷取到需要加載的類ID;
而RegisterNatives則通過擷取的類ID和方法介紹及方法加載數來注冊native方法。
ps:注冊多個方法時,需要記得修改RegisterNatives方法的第3個參數。
而RegisterNatives方法中的第二個參數mMethods中包含的是需要注冊的ative方法重要資訊,mMethods是一個jni.h中的一個結構體,代碼如下:
typedef struct {
const char* name;//方法名
const char* signature;//方法簽名
void* fnPtr;//jni中的方法名和傳回類型
} JNINativeMethod;
name:java中native方法的方法名。
signature:java方法的簽名。
例如:(I)Ljava/lang/String;表示該方法的是傳入了一個int類型的參數,傳回一個String。具體類型解釋見下面的簽名介紹;
fnPtr:jni中對應的方法。
例如:(jstring *) fun2 對應的就是 cpp中的fun2方法,()為方法的傳回類型。
java中的簽名介紹:
Java類型 相應的簽名 例子
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
Object L用"/"分割的完整類名; ex: Ljava/lang/String;
Array [簽名 ex: [I [Ljava/lang/String;
Method (參數1類型簽名參數2類型簽名...)傳回值類型簽名
我們也可以通過javap指令來擷取方法的簽名;
指令:javap -s -p 類.class
public static native java.lang.String getString2();
descriptor: ()Ljava/lang/String;
public static native java.lang.String initDate(com.hao.minovel.jni.Test);
descriptor: (Lcom/hao/minovel/jni/Test;)Ljava/lang/String;
這個是我擷取的測試兩個方法的簽名。
以上是我對jni動态注冊的了解,歡迎大佬指正。
Android JNI的初步使用--3