You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Fix FindClass() failing to find Dictionary on Android leading to crash
This commit is contained in:
@@ -123,7 +123,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
if (ref.is_valid()) {
|
if (ref.is_valid()) {
|
||||||
if (Object::cast_to<JavaObject>(ref.ptr())) {
|
if (Object::cast_to<JavaObject>(ref.ptr())) {
|
||||||
Ref<JavaObject> jo = ref;
|
Ref<JavaObject> jo = ref;
|
||||||
jclass c = env->FindClass(cn.utf8().get_data());
|
jclass c = jni_find_class(env, cn.utf8().get_data());
|
||||||
if (!c || !env->IsInstanceOf(jo->instance, c)) {
|
if (!c || !env->IsInstanceOf(jo->instance, c)) {
|
||||||
arg_expected = Variant::OBJECT;
|
arg_expected = Variant::OBJECT;
|
||||||
} else {
|
} else {
|
||||||
@@ -223,7 +223,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
if (cn.begins_with("[L") && cn.ends_with(";")) {
|
if (cn.begins_with("[L") && cn.ends_with(";")) {
|
||||||
cn = cn.substr(2, cn.length() - 3);
|
cn = cn.substr(2, cn.length() - 3);
|
||||||
}
|
}
|
||||||
jclass c = env->FindClass(cn.utf8().get_data());
|
jclass c = jni_find_class(env, cn.utf8().get_data());
|
||||||
if (c) {
|
if (c) {
|
||||||
for (int j = 0; j < arr.size(); j++) {
|
for (int j = 0; j < arr.size(); j++) {
|
||||||
Ref<JavaObject> jo = arr[j];
|
Ref<JavaObject> jo = arr[j];
|
||||||
@@ -316,7 +316,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
argv[i].d = *p_args[i];
|
argv[i].d = *p_args[i];
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BOOLEAN: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BOOLEAN: {
|
||||||
jclass bclass = env->FindClass("java/lang/Boolean");
|
jclass bclass = jni_find_class(env, "java/lang/Boolean");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.z = (bool)(*p_args[i]);
|
val.z = (bool)(*p_args[i]);
|
||||||
@@ -325,7 +325,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BYTE: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BYTE: {
|
||||||
jclass bclass = env->FindClass("java/lang/Byte");
|
jclass bclass = jni_find_class(env, "java/lang/Byte");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.b = (int)(*p_args[i]);
|
val.b = (int)(*p_args[i]);
|
||||||
@@ -334,7 +334,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_CHAR: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_CHAR: {
|
||||||
jclass bclass = env->FindClass("java/lang/Character");
|
jclass bclass = jni_find_class(env, "java/lang/Character");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.c = (int)(*p_args[i]);
|
val.c = (int)(*p_args[i]);
|
||||||
@@ -343,7 +343,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_SHORT: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_SHORT: {
|
||||||
jclass bclass = env->FindClass("java/lang/Short");
|
jclass bclass = jni_find_class(env, "java/lang/Short");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.s = (int)(*p_args[i]);
|
val.s = (int)(*p_args[i]);
|
||||||
@@ -352,7 +352,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_INT: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_INT: {
|
||||||
jclass bclass = env->FindClass("java/lang/Integer");
|
jclass bclass = jni_find_class(env, "java/lang/Integer");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.i = (int)(*p_args[i]);
|
val.i = (int)(*p_args[i]);
|
||||||
@@ -361,7 +361,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_LONG: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_LONG: {
|
||||||
jclass bclass = env->FindClass("java/lang/Long");
|
jclass bclass = jni_find_class(env, "java/lang/Long");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.j = (int64_t)(*p_args[i]);
|
val.j = (int64_t)(*p_args[i]);
|
||||||
@@ -370,7 +370,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_FLOAT: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_FLOAT: {
|
||||||
jclass bclass = env->FindClass("java/lang/Float");
|
jclass bclass = jni_find_class(env, "java/lang/Float");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.f = (float)(*p_args[i]);
|
val.f = (float)(*p_args[i]);
|
||||||
@@ -379,7 +379,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
to_free.push_back(obj);
|
to_free.push_back(obj);
|
||||||
} break;
|
} break;
|
||||||
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_DOUBLE: {
|
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_DOUBLE: {
|
||||||
jclass bclass = env->FindClass("java/lang/Double");
|
jclass bclass = jni_find_class(env, "java/lang/Double");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.d = (double)(*p_args[i]);
|
val.d = (double)(*p_args[i]);
|
||||||
@@ -572,7 +572,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
|
|
||||||
if (p_args[i]->get_type() == Variant::ARRAY) {
|
if (p_args[i]->get_type() == Variant::ARRAY) {
|
||||||
Array arr = *p_args[i];
|
Array arr = *p_args[i];
|
||||||
a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
|
a = env->NewObjectArray(arr.size(), jni_find_class(env, "java/lang/String"), nullptr);
|
||||||
for (int j = 0; j < arr.size(); j++) {
|
for (int j = 0; j < arr.size(); j++) {
|
||||||
String s = arr[j];
|
String s = arr[j];
|
||||||
jstring jStr = env->NewStringUTF(s.utf8().get_data());
|
jstring jStr = env->NewStringUTF(s.utf8().get_data());
|
||||||
@@ -581,7 +581,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
}
|
}
|
||||||
} else if (p_args[i]->get_type() == Variant::PACKED_STRING_ARRAY) {
|
} else if (p_args[i]->get_type() == Variant::PACKED_STRING_ARRAY) {
|
||||||
PackedStringArray arr = *p_args[i];
|
PackedStringArray arr = *p_args[i];
|
||||||
a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
|
a = env->NewObjectArray(arr.size(), jni_find_class(env, "java/lang/String"), nullptr);
|
||||||
for (int j = 0; j < arr.size(); j++) {
|
for (int j = 0; j < arr.size(); j++) {
|
||||||
String s = arr[j];
|
String s = arr[j];
|
||||||
jstring jStr = env->NewStringUTF(s.utf8().get_data());
|
jstring jStr = env->NewStringUTF(s.utf8().get_data());
|
||||||
@@ -595,7 +595,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
} break;
|
} break;
|
||||||
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
|
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
|
||||||
Array arr = *p_args[i];
|
Array arr = *p_args[i];
|
||||||
jobjectArray jarr = env->NewObjectArray(arr.size(), env->FindClass("org/godotengine/godot/variant/Callable"), nullptr);
|
jobjectArray jarr = env->NewObjectArray(arr.size(), jni_find_class(env, "org/godotengine/godot/variant/Callable"), nullptr);
|
||||||
for (int j = 0; j < arr.size(); j++) {
|
for (int j = 0; j < arr.size(); j++) {
|
||||||
Variant callable = arr[j];
|
Variant callable = arr[j];
|
||||||
jobject jcallable = callable_to_jcallable(env, callable);
|
jobject jcallable = callable_to_jcallable(env, callable);
|
||||||
@@ -611,7 +611,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
|
|||||||
if (cn.begins_with("[L") && cn.ends_with(";")) {
|
if (cn.begins_with("[L") && cn.ends_with(";")) {
|
||||||
cn = cn.substr(2, cn.length() - 3);
|
cn = cn.substr(2, cn.length() - 3);
|
||||||
}
|
}
|
||||||
jclass c = env->FindClass(cn.utf8().get_data());
|
jclass c = jni_find_class(env, cn.utf8().get_data());
|
||||||
if (c) {
|
if (c) {
|
||||||
Array arr = *p_args[i];
|
Array arr = *p_args[i];
|
||||||
jobjectArray jarr = env->NewObjectArray(arr.size(), c, nullptr);
|
jobjectArray jarr = env->NewObjectArray(arr.size(), c, nullptr);
|
||||||
@@ -1470,7 +1470,7 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_priva
|
|||||||
JNIEnv *env = get_jni_env();
|
JNIEnv *env = get_jni_env();
|
||||||
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
|
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
|
||||||
|
|
||||||
jclass bclass = env->FindClass(class_name_dots.replace_char('.', '/').utf8().get_data());
|
jclass bclass = jni_find_class(env, class_name_dots.replace_char('.', '/').utf8().get_data());
|
||||||
ERR_FAIL_NULL_V_MSG(bclass, Ref<JavaClass>(), vformat("Java class '%s' not found.", p_class));
|
ERR_FAIL_NULL_V_MSG(bclass, Ref<JavaClass>(), vformat("Java class '%s' not found.", p_class));
|
||||||
|
|
||||||
jobjectArray constructors = (jobjectArray)env->CallObjectMethod(bclass, Class_getDeclaredConstructors);
|
jobjectArray constructors = (jobjectArray)env->CallObjectMethod(bclass, Class_getDeclaredConstructors);
|
||||||
@@ -1699,7 +1699,7 @@ JavaClassWrapper::JavaClassWrapper() {
|
|||||||
JNIEnv *env = get_jni_env();
|
JNIEnv *env = get_jni_env();
|
||||||
ERR_FAIL_NULL(env);
|
ERR_FAIL_NULL(env);
|
||||||
|
|
||||||
jclass bclass = env->FindClass("java/lang/Class");
|
jclass bclass = jni_find_class(env, "java/lang/Class");
|
||||||
Class_getDeclaredConstructors = env->GetMethodID(bclass, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;");
|
Class_getDeclaredConstructors = env->GetMethodID(bclass, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;");
|
||||||
Class_getDeclaredMethods = env->GetMethodID(bclass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
|
Class_getDeclaredMethods = env->GetMethodID(bclass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
|
||||||
Class_getFields = env->GetMethodID(bclass, "getFields", "()[Ljava/lang/reflect/Field;");
|
Class_getFields = env->GetMethodID(bclass, "getFields", "()[Ljava/lang/reflect/Field;");
|
||||||
@@ -1707,53 +1707,53 @@ JavaClassWrapper::JavaClassWrapper() {
|
|||||||
Class_getSuperclass = env->GetMethodID(bclass, "getSuperclass", "()Ljava/lang/Class;");
|
Class_getSuperclass = env->GetMethodID(bclass, "getSuperclass", "()Ljava/lang/Class;");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/reflect/Constructor");
|
bclass = jni_find_class(env, "java/lang/reflect/Constructor");
|
||||||
Constructor_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
|
Constructor_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
|
||||||
Constructor_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
Constructor_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/reflect/Method");
|
bclass = jni_find_class(env, "java/lang/reflect/Method");
|
||||||
Method_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
|
Method_getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
|
||||||
Method_getReturnType = env->GetMethodID(bclass, "getReturnType", "()Ljava/lang/Class;");
|
Method_getReturnType = env->GetMethodID(bclass, "getReturnType", "()Ljava/lang/Class;");
|
||||||
Method_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
|
Method_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
|
||||||
Method_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
Method_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/reflect/Field");
|
bclass = jni_find_class(env, "java/lang/reflect/Field");
|
||||||
Field_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
|
Field_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
|
||||||
Field_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
Field_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
|
||||||
Field_get = env->GetMethodID(bclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
Field_get = env->GetMethodID(bclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Boolean");
|
bclass = jni_find_class(env, "java/lang/Boolean");
|
||||||
Boolean_booleanValue = env->GetMethodID(bclass, "booleanValue", "()Z");
|
Boolean_booleanValue = env->GetMethodID(bclass, "booleanValue", "()Z");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Byte");
|
bclass = jni_find_class(env, "java/lang/Byte");
|
||||||
Byte_byteValue = env->GetMethodID(bclass, "byteValue", "()B");
|
Byte_byteValue = env->GetMethodID(bclass, "byteValue", "()B");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Character");
|
bclass = jni_find_class(env, "java/lang/Character");
|
||||||
Character_characterValue = env->GetMethodID(bclass, "charValue", "()C");
|
Character_characterValue = env->GetMethodID(bclass, "charValue", "()C");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Short");
|
bclass = jni_find_class(env, "java/lang/Short");
|
||||||
Short_shortValue = env->GetMethodID(bclass, "shortValue", "()S");
|
Short_shortValue = env->GetMethodID(bclass, "shortValue", "()S");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Integer");
|
bclass = jni_find_class(env, "java/lang/Integer");
|
||||||
Integer_integerValue = env->GetMethodID(bclass, "intValue", "()I");
|
Integer_integerValue = env->GetMethodID(bclass, "intValue", "()I");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Long");
|
bclass = jni_find_class(env, "java/lang/Long");
|
||||||
Long_longValue = env->GetMethodID(bclass, "longValue", "()J");
|
Long_longValue = env->GetMethodID(bclass, "longValue", "()J");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Float");
|
bclass = jni_find_class(env, "java/lang/Float");
|
||||||
Float_floatValue = env->GetMethodID(bclass, "floatValue", "()F");
|
Float_floatValue = env->GetMethodID(bclass, "floatValue", "()F");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
|
|
||||||
bclass = env->FindClass("java/lang/Double");
|
bclass = jni_find_class(env, "java/lang/Double");
|
||||||
Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D");
|
Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D");
|
||||||
env->DeleteLocalRef(bclass);
|
env->DeleteLocalRef(bclass);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ static void _terminate(JNIEnv *env, bool p_restart = false) {
|
|||||||
FileAccessFilesystemJAndroid::terminate();
|
FileAccessFilesystemJAndroid::terminate();
|
||||||
NetSocketAndroid::terminate();
|
NetSocketAndroid::terminate();
|
||||||
|
|
||||||
|
cleanup_android_class_loader();
|
||||||
|
|
||||||
if (godot_java) {
|
if (godot_java) {
|
||||||
godot_java->on_godot_terminating(env);
|
godot_java->on_godot_terminating(env);
|
||||||
if (!restart_on_cleanup) {
|
if (!restart_on_cleanup) {
|
||||||
@@ -144,12 +146,13 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv
|
|||||||
JavaVM *jvm;
|
JavaVM *jvm;
|
||||||
env->GetJavaVM(&jvm);
|
env->GetJavaVM(&jvm);
|
||||||
|
|
||||||
|
init_thread_jandroid(jvm, env);
|
||||||
|
setup_android_class_loader();
|
||||||
|
|
||||||
// create our wrapper classes
|
// create our wrapper classes
|
||||||
godot_java = new GodotJavaWrapper(env, p_godot_instance);
|
godot_java = new GodotJavaWrapper(env, p_godot_instance);
|
||||||
godot_io_java = new GodotIOJavaWrapper(env, p_godot_io);
|
godot_io_java = new GodotIOJavaWrapper(env, p_godot_io);
|
||||||
|
|
||||||
init_thread_jandroid(jvm, env);
|
|
||||||
|
|
||||||
FileAccessAndroid::setup(p_asset_manager);
|
FileAccessAndroid::setup(p_asset_manager);
|
||||||
DirAccessJAndroid::setup(p_directory_access_handler);
|
DirAccessJAndroid::setup(p_directory_access_handler);
|
||||||
FileAccessFilesystemJAndroid::setup(p_file_access_handler);
|
FileAccessFilesystemJAndroid::setup(p_file_access_handler);
|
||||||
@@ -478,7 +481,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_godotengine_godot_GodotLib_getRendererIn
|
|||||||
String rendering_driver = RenderingServer::get_singleton()->get_current_rendering_driver_name();
|
String rendering_driver = RenderingServer::get_singleton()->get_current_rendering_driver_name();
|
||||||
String rendering_method = RenderingServer::get_singleton()->get_current_rendering_method();
|
String rendering_method = RenderingServer::get_singleton()->get_current_rendering_method();
|
||||||
|
|
||||||
jobjectArray result = env->NewObjectArray(2, env->FindClass("java/lang/String"), nullptr);
|
jobjectArray result = env->NewObjectArray(2, jni_find_class(env, "java/lang/String"), nullptr);
|
||||||
env->SetObjectArrayElement(result, 0, env->NewStringUTF(rendering_driver.utf8().get_data()));
|
env->SetObjectArrayElement(result, 0, env->NewStringUTF(rendering_driver.utf8().get_data()));
|
||||||
env->SetObjectArrayElement(result, 1, env->NewStringUTF(rendering_method.utf8().get_data()));
|
env->SetObjectArrayElement(result, 1, env->NewStringUTF(rendering_method.utf8().get_data()));
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
|
|||||||
godot_instance = p_env->NewGlobalRef(p_godot_instance);
|
godot_instance = p_env->NewGlobalRef(p_godot_instance);
|
||||||
|
|
||||||
// get info about our Godot class so we can get pointers and stuff...
|
// get info about our Godot class so we can get pointers and stuff...
|
||||||
godot_class = p_env->FindClass("org/godotengine/godot/Godot");
|
godot_class = jni_find_class(p_env, "org/godotengine/godot/Godot");
|
||||||
if (godot_class) {
|
if (godot_class) {
|
||||||
godot_class = (jclass)p_env->NewGlobalRef(godot_class);
|
godot_class = (jclass)p_env->NewGlobalRef(godot_class);
|
||||||
} else {
|
} else {
|
||||||
@@ -308,7 +308,7 @@ Error GodotJavaWrapper::show_dialog(const String &p_title, const String &p_descr
|
|||||||
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
||||||
jstring j_title = env->NewStringUTF(p_title.utf8().get_data());
|
jstring j_title = env->NewStringUTF(p_title.utf8().get_data());
|
||||||
jstring j_description = env->NewStringUTF(p_description.utf8().get_data());
|
jstring j_description = env->NewStringUTF(p_description.utf8().get_data());
|
||||||
jobjectArray j_buttons = env->NewObjectArray(p_buttons.size(), env->FindClass("java/lang/String"), nullptr);
|
jobjectArray j_buttons = env->NewObjectArray(p_buttons.size(), jni_find_class(env, "java/lang/String"), nullptr);
|
||||||
for (int i = 0; i < p_buttons.size(); ++i) {
|
for (int i = 0; i < p_buttons.size(); ++i) {
|
||||||
jstring j_button = env->NewStringUTF(p_buttons[i].utf8().get_data());
|
jstring j_button = env->NewStringUTF(p_buttons[i].utf8().get_data());
|
||||||
env->SetObjectArrayElement(j_buttons, i, j_button);
|
env->SetObjectArrayElement(j_buttons, i, j_button);
|
||||||
@@ -353,7 +353,7 @@ Error GodotJavaWrapper::show_file_picker(const String &p_current_directory, cons
|
|||||||
filters.append_array(E.get_slicec(';', 0).split(",")); // Add extensions.
|
filters.append_array(E.get_slicec(';', 0).split(",")); // Add extensions.
|
||||||
filters.append_array(E.get_slicec(';', 2).split(",")); // Add MIME types.
|
filters.append_array(E.get_slicec(';', 2).split(",")); // Add MIME types.
|
||||||
}
|
}
|
||||||
jobjectArray j_filters = env->NewObjectArray(filters.size(), env->FindClass("java/lang/String"), nullptr);
|
jobjectArray j_filters = env->NewObjectArray(filters.size(), jni_find_class(env, "java/lang/String"), nullptr);
|
||||||
for (int i = 0; i < filters.size(); ++i) {
|
for (int i = 0; i < filters.size(); ++i) {
|
||||||
jstring j_filter = env->NewStringUTF(filters[i].utf8().get_data());
|
jstring j_filter = env->NewStringUTF(filters[i].utf8().get_data());
|
||||||
env->SetObjectArrayElement(j_filters, i, j_filter);
|
env->SetObjectArrayElement(j_filters, i, j_filter);
|
||||||
@@ -469,7 +469,7 @@ int GodotJavaWrapper::create_new_godot_instance(const List<String> &args) {
|
|||||||
if (_create_new_godot_instance) {
|
if (_create_new_godot_instance) {
|
||||||
JNIEnv *env = get_jni_env();
|
JNIEnv *env = get_jni_env();
|
||||||
ERR_FAIL_NULL_V(env, 0);
|
ERR_FAIL_NULL_V(env, 0);
|
||||||
jobjectArray jargs = env->NewObjectArray(args.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
|
jobjectArray jargs = env->NewObjectArray(args.size(), jni_find_class(env, "java/lang/String"), env->NewStringUTF(""));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (List<String>::ConstIterator itr = args.begin(); itr != args.end(); ++itr, ++i) {
|
for (List<String>::ConstIterator itr = args.begin(); itr != args.end(); ++itr, ++i) {
|
||||||
jstring j_arg = env->NewStringUTF(itr->utf8().get_data());
|
jstring j_arg = env->NewStringUTF(itr->utf8().get_data());
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
|
|
||||||
#include "api/java_class_wrapper.h"
|
#include "api/java_class_wrapper.h"
|
||||||
|
|
||||||
|
static jobject android_class_loader = nullptr;
|
||||||
|
static jmethodID load_class_method = nullptr;
|
||||||
|
|
||||||
jobject callable_to_jcallable(JNIEnv *p_env, const Variant &p_callable) {
|
jobject callable_to_jcallable(JNIEnv *p_env, const Variant &p_callable) {
|
||||||
ERR_FAIL_NULL_V(p_env, nullptr);
|
ERR_FAIL_NULL_V(p_env, nullptr);
|
||||||
if (p_callable.get_type() != Variant::CALLABLE) {
|
if (p_callable.get_type() != Variant::CALLABLE) {
|
||||||
@@ -40,7 +43,7 @@ jobject callable_to_jcallable(JNIEnv *p_env, const Variant &p_callable) {
|
|||||||
|
|
||||||
Variant *callable_jcopy = memnew(Variant(p_callable));
|
Variant *callable_jcopy = memnew(Variant(p_callable));
|
||||||
|
|
||||||
jclass bclass = p_env->FindClass("org/godotengine/godot/variant/Callable");
|
jclass bclass = jni_find_class(p_env, "org/godotengine/godot/variant/Callable");
|
||||||
jmethodID ctor = p_env->GetMethodID(bclass, "<init>", "(J)V");
|
jmethodID ctor = p_env->GetMethodID(bclass, "<init>", "(J)V");
|
||||||
jobject jcallable = p_env->NewObject(bclass, ctor, reinterpret_cast<int64_t>(callable_jcopy));
|
jobject jcallable = p_env->NewObject(bclass, ctor, reinterpret_cast<int64_t>(callable_jcopy));
|
||||||
p_env->DeleteLocalRef(bclass);
|
p_env->DeleteLocalRef(bclass);
|
||||||
@@ -52,7 +55,7 @@ Callable jcallable_to_callable(JNIEnv *p_env, jobject p_jcallable_obj) {
|
|||||||
ERR_FAIL_NULL_V(p_env, Callable());
|
ERR_FAIL_NULL_V(p_env, Callable());
|
||||||
|
|
||||||
const Variant *callable_variant = nullptr;
|
const Variant *callable_variant = nullptr;
|
||||||
jclass callable_class = p_env->FindClass("org/godotengine/godot/variant/Callable");
|
jclass callable_class = jni_find_class(p_env, "org/godotengine/godot/variant/Callable");
|
||||||
if (callable_class && p_env->IsInstanceOf(p_jcallable_obj, callable_class)) {
|
if (callable_class && p_env->IsInstanceOf(p_jcallable_obj, callable_class)) {
|
||||||
jmethodID get_native_pointer = p_env->GetMethodID(callable_class, "getNativePointer", "()J");
|
jmethodID get_native_pointer = p_env->GetMethodID(callable_class, "getNativePointer", "()J");
|
||||||
jlong native_callable = p_env->CallLongMethod(p_jcallable_obj, get_native_pointer);
|
jlong native_callable = p_env->CallLongMethod(p_jcallable_obj, get_native_pointer);
|
||||||
@@ -70,7 +73,7 @@ String charsequence_to_string(JNIEnv *p_env, jobject p_charsequence) {
|
|||||||
ERR_FAIL_NULL_V(p_env, String());
|
ERR_FAIL_NULL_V(p_env, String());
|
||||||
|
|
||||||
String result;
|
String result;
|
||||||
jclass bclass = p_env->FindClass("java/lang/CharSequence");
|
jclass bclass = jni_find_class(p_env, "java/lang/CharSequence");
|
||||||
if (bclass && p_env->IsInstanceOf(p_charsequence, bclass)) {
|
if (bclass && p_env->IsInstanceOf(p_charsequence, bclass)) {
|
||||||
jmethodID to_string = p_env->GetMethodID(bclass, "toString", "()Ljava/lang/String;");
|
jmethodID to_string = p_env->GetMethodID(bclass, "toString", "()Ljava/lang/String;");
|
||||||
jstring obj_string = (jstring)p_env->CallObjectMethod(p_charsequence, to_string);
|
jstring obj_string = (jstring)p_env->CallObjectMethod(p_charsequence, to_string);
|
||||||
@@ -89,7 +92,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
switch (p_type) {
|
switch (p_type) {
|
||||||
case Variant::BOOL: {
|
case Variant::BOOL: {
|
||||||
if (force_jobject) {
|
if (force_jobject) {
|
||||||
jclass bclass = env->FindClass("java/lang/Boolean");
|
jclass bclass = jni_find_class(env, "java/lang/Boolean");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.z = (bool)(*p_arg);
|
val.z = (bool)(*p_arg);
|
||||||
@@ -103,7 +106,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
} break;
|
} break;
|
||||||
case Variant::INT: {
|
case Variant::INT: {
|
||||||
if (force_jobject) {
|
if (force_jobject) {
|
||||||
jclass bclass = env->FindClass("java/lang/Integer");
|
jclass bclass = jni_find_class(env, "java/lang/Integer");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.i = (int)(*p_arg);
|
val.i = (int)(*p_arg);
|
||||||
@@ -118,7 +121,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
} break;
|
} break;
|
||||||
case Variant::FLOAT: {
|
case Variant::FLOAT: {
|
||||||
if (force_jobject) {
|
if (force_jobject) {
|
||||||
jclass bclass = env->FindClass("java/lang/Double");
|
jclass bclass = jni_find_class(env, "java/lang/Double");
|
||||||
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
|
jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
|
||||||
jvalue val;
|
jvalue val;
|
||||||
val.d = (double)(*p_arg);
|
val.d = (double)(*p_arg);
|
||||||
@@ -139,7 +142,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
} break;
|
} break;
|
||||||
case Variant::PACKED_STRING_ARRAY: {
|
case Variant::PACKED_STRING_ARRAY: {
|
||||||
Vector<String> sarray = *p_arg;
|
Vector<String> sarray = *p_arg;
|
||||||
jobjectArray arr = env->NewObjectArray(sarray.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
|
jobjectArray arr = env->NewObjectArray(sarray.size(), jni_find_class(env, "java/lang/String"), env->NewStringUTF(""));
|
||||||
|
|
||||||
for (int j = 0; j < sarray.size(); j++) {
|
for (int j = 0; j < sarray.size(); j++) {
|
||||||
jstring str = env->NewStringUTF(sarray[j].utf8().get_data());
|
jstring str = env->NewStringUTF(sarray[j].utf8().get_data());
|
||||||
@@ -159,13 +162,13 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
|
|
||||||
case Variant::DICTIONARY: {
|
case Variant::DICTIONARY: {
|
||||||
Dictionary dict = *p_arg;
|
Dictionary dict = *p_arg;
|
||||||
jclass dclass = env->FindClass("org/godotengine/godot/Dictionary");
|
jclass dclass = jni_find_class(env, "org/godotengine/godot/Dictionary");
|
||||||
jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
|
jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
|
||||||
jobject jdict = env->NewObject(dclass, ctor);
|
jobject jdict = env->NewObject(dclass, ctor);
|
||||||
|
|
||||||
Array keys = dict.keys();
|
Array keys = dict.keys();
|
||||||
|
|
||||||
jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
|
jobjectArray jkeys = env->NewObjectArray(keys.size(), jni_find_class(env, "java/lang/String"), env->NewStringUTF(""));
|
||||||
for (int j = 0; j < keys.size(); j++) {
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
|
jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
|
||||||
env->SetObjectArrayElement(jkeys, j, str);
|
env->SetObjectArrayElement(jkeys, j, str);
|
||||||
@@ -178,7 +181,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
env->CallVoidMethodA(jdict, set_keys, &val);
|
env->CallVoidMethodA(jdict, set_keys, &val);
|
||||||
env->DeleteLocalRef(jkeys);
|
env->DeleteLocalRef(jkeys);
|
||||||
|
|
||||||
jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), nullptr);
|
jobjectArray jvalues = env->NewObjectArray(keys.size(), jni_find_class(env, "java/lang/Object"), nullptr);
|
||||||
|
|
||||||
for (int j = 0; j < keys.size(); j++) {
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
Variant var = dict[keys[j]];
|
Variant var = dict[keys[j]];
|
||||||
@@ -201,7 +204,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
|
|
||||||
case Variant::ARRAY: {
|
case Variant::ARRAY: {
|
||||||
Array array = *p_arg;
|
Array array = *p_arg;
|
||||||
jobjectArray arr = env->NewObjectArray(array.size(), env->FindClass("java/lang/Object"), nullptr);
|
jobjectArray arr = env->NewObjectArray(array.size(), jni_find_class(env, "java/lang/Object"), nullptr);
|
||||||
|
|
||||||
for (int j = 0; j < array.size(); j++) {
|
for (int j = 0; j < array.size(); j++) {
|
||||||
Variant var = array[j];
|
Variant var = array[j];
|
||||||
@@ -279,7 +282,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
|
String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
|
||||||
jclass cclass = env->FindClass("java/lang/Class");
|
jclass cclass = jni_find_class(env, "java/lang/Class");
|
||||||
jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
|
jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
|
||||||
jstring clsName = (jstring)env->CallObjectMethod(cls, getName);
|
jstring clsName = (jstring)env->CallObjectMethod(cls, getName);
|
||||||
|
|
||||||
@@ -346,7 +349,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name == "java.lang.Integer" || name == "java.lang.Long") {
|
if (name == "java.lang.Integer" || name == "java.lang.Long") {
|
||||||
jclass nclass = env->FindClass("java/lang/Number");
|
jclass nclass = jni_find_class(env, "java/lang/Number");
|
||||||
jmethodID longValue = env->GetMethodID(nclass, "longValue", "()J");
|
jmethodID longValue = env->GetMethodID(nclass, "longValue", "()J");
|
||||||
jlong ret = env->CallLongMethod(obj, longValue);
|
jlong ret = env->CallLongMethod(obj, longValue);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -386,7 +389,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name == "java.lang.Float" || name == "java.lang.Double") {
|
if (name == "java.lang.Float" || name == "java.lang.Double") {
|
||||||
jclass nclass = env->FindClass("java/lang/Number");
|
jclass nclass = jni_find_class(env, "java/lang/Number");
|
||||||
jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
|
jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
|
||||||
double ret = env->CallDoubleMethod(obj, doubleValue);
|
double ret = env->CallDoubleMethod(obj, doubleValue);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -509,3 +512,59 @@ Variant::Type get_jni_type(const String &p_type) {
|
|||||||
|
|
||||||
return Variant::OBJECT;
|
return Variant::OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setup_android_class_loader() {
|
||||||
|
// Find a known class defined in the Godot package and obtain its ClassLoader.
|
||||||
|
// This ClassLoader will be used by jni_find_class() to locate classes at runtime
|
||||||
|
// in a thread-safe manner, avoiding issues with FindClass in non-main threads.
|
||||||
|
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
ERR_FAIL_NULL(env);
|
||||||
|
|
||||||
|
jclass known_class = env->FindClass("org/godotengine/godot/Godot");
|
||||||
|
ERR_FAIL_NULL(known_class);
|
||||||
|
|
||||||
|
jclass class_class = env->FindClass("java/lang/Class");
|
||||||
|
ERR_FAIL_NULL(class_class);
|
||||||
|
|
||||||
|
jmethodID get_class_loader_method = env->GetMethodID(class_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
|
ERR_FAIL_NULL(get_class_loader_method);
|
||||||
|
|
||||||
|
jobject class_loader = env->CallObjectMethod(known_class, get_class_loader_method);
|
||||||
|
ERR_FAIL_NULL(class_loader);
|
||||||
|
|
||||||
|
// NOTE: Make global ref so it can be used later.
|
||||||
|
android_class_loader = env->NewGlobalRef(class_loader);
|
||||||
|
ERR_FAIL_NULL(android_class_loader);
|
||||||
|
|
||||||
|
jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
|
||||||
|
ERR_FAIL_NULL(class_loader_class);
|
||||||
|
|
||||||
|
load_class_method = env->GetMethodID(class_loader_class, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
|
if (!load_class_method) {
|
||||||
|
env->DeleteGlobalRef(android_class_loader);
|
||||||
|
android_class_loader = nullptr;
|
||||||
|
ERR_FAIL_MSG("Failed to find method ID for ClassLoader::loadClass.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_android_class_loader() {
|
||||||
|
if (android_class_loader != nullptr) {
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
if (env) {
|
||||||
|
env->DeleteGlobalRef(android_class_loader);
|
||||||
|
android_class_loader = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass jni_find_class(JNIEnv *p_env, const char *p_class_name) {
|
||||||
|
jstring java_class_name = p_env->NewStringUTF(p_class_name);
|
||||||
|
jobject class_object = p_env->CallObjectMethod(
|
||||||
|
android_class_loader,
|
||||||
|
load_class_method,
|
||||||
|
java_class_name);
|
||||||
|
p_env->DeleteLocalRef(java_class_name);
|
||||||
|
ERR_FAIL_NULL_V_MSG(class_object, nullptr, vformat("Failed to find Java class: \"%s\".", p_class_name));
|
||||||
|
return static_cast<jclass>(class_object);
|
||||||
|
}
|
||||||
|
|||||||
@@ -96,3 +96,18 @@ static inline String jstring_to_string(jstring source, JNIEnv *env = nullptr) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up thread-safe Android ClassLoader (used by jni_find_class() below).
|
||||||
|
*/
|
||||||
|
void setup_android_class_loader();
|
||||||
|
void cleanup_android_class_loader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-safe JNI class finder using Android ClassLoader.
|
||||||
|
* Works on any thread, unlike standard FindClass which may fail on non-main threads.
|
||||||
|
* @param p_env JNI environment instance.
|
||||||
|
* @param p_class_name Class name to find.
|
||||||
|
* @return jclass reference or null if not found.
|
||||||
|
*/
|
||||||
|
jclass jni_find_class(JNIEnv *p_env, const char *p_class_name);
|
||||||
|
|||||||
Reference in New Issue
Block a user