背景需求java
咱們須要在JNI的C代碼調用Java代碼。實現原理:使用JNI提供的反射藉口來反射獲得Java方法,進行調用。ide
JNI關鍵方法講解。函數
1. 在同一個類中,調用其餘方法spa
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1 (JNIEnv * env, jobject obj){ //在c代碼裏面調用java代碼裏面的方法 // java 反射 //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class裏面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .調用這個方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); (*env)->CallVoidMethod(env,obj,method1); }
注意: 看紅色的內容,如何得到呢? 這個是函數的簽名。函數簽名借住命令 javap -p -s(這兩個參數必定要加入)來得到,放到第二個參數便可。code
注意:blog
1. 要加入上面的參數 -p -sstring
2. signature後面有時候帶「;」,不要丟掉。 主要要仔細檢查it
示例:ast
void notifyOnStatusReport(int32_t status) { if (curEnv != NULL && curObj != NULL) { jclass clsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/LiveNativeSender"); jfieldID mUsercommandCallbackEventListnerFieldId = curEnv->GetFieldID(clsstring,"mStatusEventListener","Lcom/baidu/tieba/liveSdk/publisher/OnStatusEventListener;"); jobject mUsercommandCallbackEventListner = curEnv->GetObjectField(curObj,mUsercommandCallbackEventListnerFieldId); jclass onStatusEventListenerClsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/OnStatusEventListener"); jmethodID onStatusReport = curEnv->GetMethodID(onStatusEventListenerClsstring, "onStatusReport", "(I)V"); curEnv->CallVoidMethod(mUsercommandCallbackEventListner, onStatusReport, status); } }
這樣就能夠調用DataProvider中的helloFromJava方法了。class
2. 上面的方法是調用的返回值爲void的java方法。若是想調用其餘類型的。JNI中還提供的許多其餘返回類型的方法。
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
3. 若是java中的方法是靜態的,就須要調用GetStaticMethodID 和 CallStaticVoidMethod 方法。
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod4 (JNIEnv * env, jobject obj){ //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class裏面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); // 注意 :若是要尋找的方法是靜態的方法 那就不能直接去獲取methodid //jmethodID method4 = (*env)->GetMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); // jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method4 = (*env)->GetStaticMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); if(method4==0){ LOGI("find method4 error"); return; } LOGI("find method4 "); //3.調用一個靜態的java方法 // void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); (*env)->CallStaticVoidMethod(env,dpclazz,method4,(*env)->NewStringUTF(env,"static haha in c")); }
4. 若是C調用的Java方法不在一個類中。
分析:JNI提供的方法都有兩個參數:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上線文。下面的例子的obj不是所須要的上下午,因此要從新建立。
//obj DemoActivity JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DemoActivity_call_1dp_1method1 (JNIEnv * env, jobject obj){ //在c代碼裏面調用java代碼裏面的方法 // java 反射 //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class裏面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .調用這個方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); // jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); // jobject (*AllocObject)(JNIEnv*, jclass); jobject dpobj= (*env)->AllocObject(env,dpclazz); (*env)->CallVoidMethod(env,dpobj,method1); }
5. 提示
爲了不4中的內容,咱們儘可能讓C要調用的Java方法在同一個類中