Android NDK中JNI调用Java方法失败:找不到方法致App崩溃
下面是常见的错误原因和对应的修复方案,你可以逐一对照自己的代码排查:
类路径签名错误
JNI中引用Java类必须使用全限定类名(包名+类名,用/代替.),如果直接写类名,VM会找不到对应的类。
错误示例:jclass clazz = env->FindClass("MainActivity");修复(替换成你的实际包路径):
jclass clazz = env->FindClass("com/example/myapp/MainActivity");方法签名不匹配
JNI对方法签名的要求极其严格,必须和Java方法的参数、返回值完全对应。你可以通过javap -s -p 你的类路径命令生成正确的方法签名。
比如Java方法public void refreshJNIIntegration()的签名是()V。
错误示例(签名多了参数标识):jmethodID methodId = env->GetMethodID(clazz, "refreshJNIIntegration", "(I)V");修复:
jmethodID methodId = env->GetMethodID(clazz, "refreshJNIIntegration", "()V");误用静态方法API调用非静态方法
如果你用GetStaticMethodID去获取非静态方法的ID,必然会报错——非静态方法必须用GetMethodID获取ID。
错误示例:jmethodID methodId = env->GetStaticMethodID(clazz, "refreshJNIIntegration", "()V");修复:将
GetStaticMethodID替换为GetMethodID。没有持有有效的Activity对象引用
非静态方法必须依赖具体的对象实例调用,如果你在JNI里用了临时创建的Activity对象(Activity不能通过NewObject直接实例化),或者传入的Activity实例已经被GC回收,就会触发错误。
修复方案:在Java层的onCreate等生命周期方法中,将MainActivity的实例传递给JNI,并保存为全局引用(避免被GC回收):// 全局变量保存Activity引用 jobject g_mainActivity = NULL; // Java层调用该方法传入this JNIEXPORT void JNICALL Java_com_example_myapp_MainActivity_setActivityReference(JNIEnv *env, jobject obj) { // 创建全局引用 g_mainActivity = env->NewGlobalRef(obj); } // 调用目标方法时使用全局引用 void callRefreshMethod(JNIEnv *env) { if (g_mainActivity == NULL) return; jclass clazz = env->GetObjectClass(g_mainActivity); jmethodID methodId = env->GetMethodID(clazz, "refreshJNIIntegration", "()V"); env->CallVoidMethod(g_mainActivity, methodId); // 注意:在Activity销毁时记得释放全局引用,避免内存泄漏 // env->DeleteGlobalRef(g_mainActivity); }线程问题导致的混淆报错
如果JNI调用是在子线程中执行,直接调用Activity的UI方法会崩溃,部分场景下错误提示可能会被混淆为“找不到方法”。
修复:在Java层的refreshJNIIntegration方法中切换到主线程执行UI操作:public void refreshJNIIntegration() { runOnUiThread(new Runnable() { @Override public void run() { // 你的UI更新逻辑写在这里 } }); }
内容的提问来源于stack exchange,提问作者HX_unbanned

