detected:发现,发觉,查明
这个是运行时出现报的错,指的是TestAliPayActivity 里面的showDialog传的jobject应该是 Activity而不应该是JnitUtil这个类;
主要原因是native方法在JniUtil中定义。这边需要弹出一个弹窗,Dialog需要的Context是Activity
所以报实例对象不正确;
改正方法: 将native方法定义在Activity中然后用c代码调用。在C中通过反射的原理可以调用Java代码显示弹窗。
JNI DETECTED ERROR IN APPLICATION:
can't call void test.com.zh.testicbclient.ui.TestAliPayActivity.showDailog(java.lang.String)
on instance of test.com.zh.testicbclient.JniUtils.JniUtil
2.以下是用反射C调取Java的方法:达到Java调c,c调java的闭环。
/**
* 显示Java的对话框
* @param env
* @param obj
* @param str c的字符串
*/
void showJavaDialog(JNIEnv *env, jobject obj, char *cstr) {
// c调 java 利用反射的原理 jclass (*FindClass)(JNIEnv*, const char*);
// 1 加载类的字节码文件 第一个文件时JVM第二个参数是字符串也就是类的全路径
// 需要注意全路径C代码不能用点表示了,c中用/
jclass jclzz = (*env)->FindClass(env, "test/com/zh/testicbclient/ui/TestAliPayActivity");
// 2.查找类的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第一个参数是JVM,第二个参数是字节码,jclass;第三个参数是字符串方法的名称;第四个参数是
// 第三个参数是方法名字
// 第四个参数是方法的签名
/* public void showDailog(java.lang.String);
descriptor: (Ljava/lang/String;)V
(Ljava/lang/String;)V
解析: (Ljava/lang/String;) 参数类型 Java Lang包的 String 类型 ,后面一个是返回值类型 V void
public void dismissDialog();
descriptor: ()V
*/
jmethodID method = (*env)->GetMethodID(env, jclzz, "showDailog", "(Ljava/lang/String;)V");
// 3.调用方法; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
// 这地方需要注意最后一个参数传的是 jstring java中的 字符串
(*env)->CallVoidMethod(env, obj, method, (*env)->NewStringUTF(env, cstr));
}
3.关于C调java中查找类中的方法签名的获取方法:
第三个参数是方法名,第四个参数是方法的签名
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
关于方法的签名获取的方法需要知道 javap命令:
Android Studio 下获取某个类的方法签名步骤:
Project------>app ---------->build----->intermediates(中间者)------>javaC---->debug---->compileDebugJavaWithJavac-->
classes--------->包名类名对应的方法类下执行 javap -s 可以获取到对应方法的方法签名
在Terminal中 :
eg. cd 项目名\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\包名+类名
执行:javap -s 获取类中方法的签名。