我正在尝试从Android应用程序中的本机C代码调用java方法。使用JNI听起来很简单,但是当我最终调用方法本身时,我的代码总是崩溃。 这是我的代码: 原生C代码:
JNIEXPORT void JNICALL
Java_com_path_to_my_package_renderStuff(JNIEnv* env, jobject jobj){
//...
jclass clazz = env->FindClass("com/path/to/the/class");
jmethodID showCar = env->GetMethodID(clazz,"showCar","()V" );
env->CallVoidMethod(jobj,showCar); //If I comment this out, it won't crash
//...
}
Java代码:
public void showCar(){
doSomething()
}
甚至没有达到doSomething(),我可以在那里设置断点,永远不会被击中。如上所述,只要我注释掉CallVoidMethod调用,它就不会崩溃,但显然也不会调用showCar()。任何提示?
答案 0 :(得分:11)
为您提供的4个想法:
...
jclass clazz = env-> FindClass(“com / path / to / the / class”);
您能确认名称不是“com / path / to / the / MyClass”,其中classname是大写的第一个字符,显然名称“class”是保留字。在您的示例中,使用JNI C符号名称“Java_com_path_to_my_package_renderStuff”与“com / path / to / the / class”上的FindClass()查找之间存在轻微的差异。但由于您的stackoverflow不是关于UnsatisfiedLinkageError,我只能猜测您提供的示例与自身不一致。
使用我的示例,我希望JNI C符号名称为“Java_com_path_to_the_MyClass_renderStuff”,并且“com / path / to / the / MyClass”上的FindClass()查找。使用大写的第1个字母和小写的方法名称第1个字母对于链接目的可能很重要。
...
你确定传递的“jobj”与你正在查找的“com / path / to / the / class”的类型相同吗?也许在您的Java代码中,您可以使用以下内容包装您的原生代码:
public void renderStuff() {
if((this instanceof com.path.to.the.MyClass) == false)
throw new RuntimeException("Unexpected class expected: com.path.to.the.MyClass");
renderStuff_internal();
}
private native void renderStuff_internal();
这将确保Java代码中的问题而不会导致JVM崩溃。您还需要调整C符号名称以将“_1internal”附加到末尾,使“Java_com_path_to_the_MyClass_renderStuff_1internal”(额外的“1”字符是预期的)
...
也许在你列出的每个陈述之间尝试腰带和括号异常检查:
if(env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
当可能不允许进行反射时,这会触发安全违规等事情。
...
jclass cls = env->GetObjectClass(jobj); // instead of FindClass
jmethodID mid = env->GetMethodID(cls, "showCar", "()V");
if(!mid) return; // whoops method does not exist
env->CallVoidMethod(jobj, mid);
删除FindClass()调用的另一个想法。这适用于任何GetMethodID工作的类,有点类似于dyhamic类型/后期绑定。
答案 1 :(得分:1)
就我而言 我正在调用 Kotlin 函数。并且要调用 kotlin 函数,您需要在 kotlin 中的函数名称前写上 @JvmStatic。
Kotlin 代码
@JvmStatic
fun ReceiveDataFromCpp(data: ShortArray)
{
Log.d("Kotlin array Return -----> ", "arr: " + data
.contentToString()
);
}
Cpp 代码
JNIEnv * g_env;
g_env = getEnv();
jmethodID jmethodId = g_env->GetStaticMethodID(clientClass, "ReceiveDataFromCpp",
"([S)V");
if (jmethodId == NULL)
{
return;
}
jshortArray dataArray = nullptr;
dataArray = g_env->NewShortArray(480);
g_env->SetShortArrayRegion(dataArray, 0, 480, mData);
g_env->CallStaticVoidMethod(clientRecorderClass, jmethodId, dataArray);