Skip to content

Commit 9049862

Browse files
m4gr3dWhalesState
authored andcommitted
Remove the restriction on supported types for Godot Android plugins
The Android plugin implementation is updated to use `JavaClassWrapper` which was fixed in godotengine#96182, thus removing the limitation on supported types. Note that `JavaClassWrapper` has also been updated in order to only provide access to public methods and constructor to GDScript.
1 parent fada9df commit 9049862

6 files changed

+51
-208
lines changed

platform/android/api/api.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,11 @@ static JavaClassWrapper *java_class_wrapper = nullptr;
4141

4242
void register_android_api() {
4343
#if !defined(ANDROID_ENABLED)
44-
// On Android platforms, the `java_class_wrapper` instantiation and the
45-
// `JNISingleton` registration occurs in
44+
// On Android platforms, the `java_class_wrapper` instantiation occurs in
4645
// `platform/android/java_godot_lib_jni.cpp#Java_app_blazium_godot_GodotLib_setup`
47-
java_class_wrapper = memnew(JavaClassWrapper); // Dummy
48-
GDREGISTER_CLASS(JNISingleton);
46+
java_class_wrapper = memnew(JavaClassWrapper);
4947
#endif
50-
48+
GDREGISTER_CLASS(JNISingleton);
5149
GDREGISTER_CLASS(JavaClass);
5250
GDREGISTER_CLASS(JavaObject);
5351
GDREGISTER_CLASS(JavaClassWrapper);
@@ -108,7 +106,7 @@ Ref<JavaClass> JavaObject::get_java_class() const {
108106

109107
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
110108

111-
Ref<JavaClass> JavaClassWrapper::wrap(const String &) {
109+
Ref<JavaClass> JavaClassWrapper::_wrap(const String &, bool) {
112110
return Ref<JavaClass>();
113111
}
114112

platform/android/api/java_class_wrapper.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ class JavaClassWrapper : public Object {
262262
bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
263263
#endif
264264

265+
Ref<JavaClass> _wrap(const String &p_class, bool p_allow_private_methods_access);
266+
265267
static JavaClassWrapper *singleton;
266268

267269
protected:
@@ -270,15 +272,14 @@ class JavaClassWrapper : public Object {
270272
public:
271273
static JavaClassWrapper *get_singleton() { return singleton; }
272274

273-
Ref<JavaClass> wrap(const String &p_class);
275+
Ref<JavaClass> wrap(const String &p_class) {
276+
return _wrap(p_class, false);
277+
}
274278

275279
#ifdef ANDROID_ENABLED
276-
Ref<JavaClass> wrap_jclass(jclass p_class);
277-
278-
JavaClassWrapper(jobject p_activity = nullptr);
279-
#else
280-
JavaClassWrapper();
280+
Ref<JavaClass> wrap_jclass(jclass p_class, bool p_allow_private_methods_access = false);
281281
#endif
282+
JavaClassWrapper();
282283
};
283284

284285
#endif // JAVA_CLASS_WRAPPER_H

platform/android/api/jni_singleton.h

+24-173
Original file line numberDiff line numberDiff line change
@@ -31,193 +31,53 @@
3131
#ifndef JNI_SINGLETON_H
3232
#define JNI_SINGLETON_H
3333

34+
#include "java_class_wrapper.h"
35+
3436
#include "core/config/engine.h"
3537
#include "core/variant/variant.h"
3638

37-
#ifdef ANDROID_ENABLED
38-
#include "jni_utils.h"
39-
#endif
40-
4139
class JNISingleton : public Object {
4240
GDCLASS(JNISingleton, Object);
4341

44-
#ifdef ANDROID_ENABLED
4542
struct MethodData {
46-
jmethodID method;
4743
Variant::Type ret_type;
4844
Vector<Variant::Type> argtypes;
4945
};
5046

51-
jobject instance;
5247
RBMap<StringName, MethodData> method_map;
53-
#endif
48+
Ref<JavaObject> wrapped_object;
5449

5550
public:
5651
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
57-
#ifdef ANDROID_ENABLED
58-
RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
59-
60-
// Check the method we're looking for is in the JNISingleton map and that
61-
// the arguments match.
62-
bool call_error = !E || E->get().argtypes.size() != p_argcount;
63-
if (!call_error) {
64-
for (int i = 0; i < p_argcount; i++) {
65-
if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
66-
call_error = true;
67-
break;
52+
if (wrapped_object.is_valid()) {
53+
RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
54+
55+
// Check the method we're looking for is in the JNISingleton map and that
56+
// the arguments match.
57+
bool call_error = !E || E->get().argtypes.size() != p_argcount;
58+
if (!call_error) {
59+
for (int i = 0; i < p_argcount; i++) {
60+
if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
61+
call_error = true;
62+
break;
63+
}
6864
}
6965
}
70-
}
71-
72-
if (call_error) {
73-
// The method is not in this map, defaulting to the regular instance calls.
74-
return Object::callp(p_method, p_args, p_argcount, r_error);
75-
}
76-
77-
ERR_FAIL_NULL_V(instance, Variant());
78-
79-
r_error.error = Callable::CallError::CALL_OK;
80-
81-
jvalue *v = nullptr;
8266

83-
if (p_argcount) {
84-
v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
85-
}
86-
87-
JNIEnv *env = get_jni_env();
88-
89-
int res = env->PushLocalFrame(16);
90-
91-
ERR_FAIL_COND_V(res != 0, Variant());
92-
93-
List<jobject> to_erase;
94-
for (int i = 0; i < p_argcount; i++) {
95-
jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
96-
v[i] = vr.val;
97-
if (vr.obj) {
98-
to_erase.push_back(vr.obj);
67+
if (!call_error) {
68+
return wrapped_object->callp(p_method, p_args, p_argcount, r_error);
9969
}
10070
}
10171

102-
Variant ret;
103-
104-
switch (E->get().ret_type) {
105-
case Variant::NIL: {
106-
env->CallVoidMethodA(instance, E->get().method, v);
107-
} break;
108-
case Variant::BOOL: {
109-
ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
110-
} break;
111-
case Variant::INT: {
112-
ret = env->CallIntMethodA(instance, E->get().method, v);
113-
} break;
114-
case Variant::FLOAT: {
115-
ret = env->CallFloatMethodA(instance, E->get().method, v);
116-
} break;
117-
case Variant::STRING: {
118-
jobject o = env->CallObjectMethodA(instance, E->get().method, v);
119-
ret = jstring_to_string((jstring)o, env);
120-
env->DeleteLocalRef(o);
121-
} break;
122-
case Variant::PACKED_STRING_ARRAY: {
123-
jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
124-
125-
ret = _jobject_to_variant(env, arr);
126-
127-
env->DeleteLocalRef(arr);
128-
} break;
129-
case Variant::PACKED_INT32_ARRAY: {
130-
jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
131-
132-
int fCount = env->GetArrayLength(arr);
133-
Vector<int> sarr;
134-
sarr.resize(fCount);
135-
136-
int *w = sarr.ptrw();
137-
env->GetIntArrayRegion(arr, 0, fCount, w);
138-
ret = sarr;
139-
env->DeleteLocalRef(arr);
140-
} break;
141-
case Variant::PACKED_INT64_ARRAY: {
142-
jlongArray arr = (jlongArray)env->CallObjectMethodA(instance, E->get().method, v);
143-
144-
int fCount = env->GetArrayLength(arr);
145-
Vector<int64_t> sarr;
146-
sarr.resize(fCount);
147-
148-
int64_t *w = sarr.ptrw();
149-
env->GetLongArrayRegion(arr, 0, fCount, w);
150-
ret = sarr;
151-
env->DeleteLocalRef(arr);
152-
} break;
153-
case Variant::PACKED_FLOAT32_ARRAY: {
154-
jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
155-
156-
int fCount = env->GetArrayLength(arr);
157-
Vector<float> sarr;
158-
sarr.resize(fCount);
159-
160-
float *w = sarr.ptrw();
161-
env->GetFloatArrayRegion(arr, 0, fCount, w);
162-
ret = sarr;
163-
env->DeleteLocalRef(arr);
164-
} break;
165-
case Variant::PACKED_FLOAT64_ARRAY: {
166-
jdoubleArray arr = (jdoubleArray)env->CallObjectMethodA(instance, E->get().method, v);
167-
168-
int fCount = env->GetArrayLength(arr);
169-
Vector<double> sarr;
170-
sarr.resize(fCount);
171-
172-
double *w = sarr.ptrw();
173-
env->GetDoubleArrayRegion(arr, 0, fCount, w);
174-
ret = sarr;
175-
env->DeleteLocalRef(arr);
176-
} break;
177-
case Variant::DICTIONARY: {
178-
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
179-
ret = _jobject_to_variant(env, obj);
180-
env->DeleteLocalRef(obj);
181-
182-
} break;
183-
case Variant::OBJECT: {
184-
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
185-
ret = _jobject_to_variant(env, obj);
186-
env->DeleteLocalRef(obj);
187-
} break;
188-
default: {
189-
env->PopLocalFrame(nullptr);
190-
ERR_FAIL_V(Variant());
191-
} break;
192-
}
193-
194-
while (to_erase.size()) {
195-
env->DeleteLocalRef(to_erase.front()->get());
196-
to_erase.pop_front();
197-
}
198-
199-
env->PopLocalFrame(nullptr);
200-
201-
return ret;
202-
#else // ANDROID_ENABLED
203-
204-
// Defaulting to the regular instance calls.
20572
return Object::callp(p_method, p_args, p_argcount, r_error);
206-
#endif
20773
}
20874

209-
#ifdef ANDROID_ENABLED
210-
jobject get_instance() const {
211-
return instance;
75+
Ref<JavaObject> get_wrapped_object() const {
76+
return wrapped_object;
21277
}
21378

214-
void set_instance(jobject p_instance) {
215-
instance = p_instance;
216-
}
217-
218-
void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
79+
void add_method(const StringName &p_name, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
21980
MethodData md;
220-
md.method = p_method;
22181
md.argtypes = p_args;
22282
md.ret_type = p_ret_type;
22383
method_map[p_name] = md;
@@ -232,24 +92,15 @@ class JNISingleton : public Object {
23292
ADD_SIGNAL(mi);
23393
}
23494

235-
#endif
95+
JNISingleton() {}
23696

237-
JNISingleton() {
238-
#ifdef ANDROID_ENABLED
239-
instance = nullptr;
240-
#endif
97+
JNISingleton(const Ref<JavaObject> &p_wrapped_object) {
98+
wrapped_object = p_wrapped_object;
24199
}
242100

243101
~JNISingleton() {
244-
#ifdef ANDROID_ENABLED
245102
method_map.clear();
246-
if (instance) {
247-
JNIEnv *env = get_jni_env();
248-
ERR_FAIL_NULL(env);
249-
250-
env->DeleteGlobalRef(instance);
251-
}
252-
#endif
103+
wrapped_object.unref();
253104
}
254105
};
255106

platform/android/java_class_wrapper.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
11201120
return false;
11211121
}
11221122

1123-
Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
1123+
Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_private_methods_access) {
11241124
String class_name_dots = p_class.replace("/", ".");
11251125
if (class_cache.has(class_name_dots)) {
11261126
return class_cache[class_name_dots];
@@ -1175,7 +1175,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
11751175

11761176
jint mods = env->CallIntMethod(obj, is_constructor ? Constructor_getModifiers : Method_getModifiers);
11771177

1178-
if (!(mods & 0x0001)) {
1178+
if (!(mods & 0x0001) && (is_constructor || !p_allow_private_methods_access)) {
11791179
env->DeleteLocalRef(obj);
11801180
continue; //not public bye
11811181
}
@@ -1336,20 +1336,20 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
13361336
return java_class;
13371337
}
13381338

1339-
Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class) {
1339+
Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_private_methods_access) {
13401340
JNIEnv *env = get_jni_env();
13411341
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
13421342

13431343
jstring class_name = (jstring)env->CallObjectMethod(p_class, Class_getName);
13441344
String class_name_string = jstring_to_string(class_name, env);
13451345
env->DeleteLocalRef(class_name);
13461346

1347-
return wrap(class_name_string);
1347+
return _wrap(class_name_string, p_allow_private_methods_access);
13481348
}
13491349

13501350
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
13511351

1352-
JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
1352+
JavaClassWrapper::JavaClassWrapper() {
13531353
singleton = this;
13541354

13551355
JNIEnv *env = get_jni_env();

platform/android/java_godot_lib_jni.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
#include "android_input_handler.h"
3434
#include "api/java_class_wrapper.h"
35-
#include "api/jni_singleton.h"
3635
#include "dir_access_jandroid.h"
3736
#include "display_server_android.h"
3837
#include "file_access_android.h"
@@ -209,8 +208,7 @@ JNIEXPORT jboolean JNICALL Java_app_blazium_godot_GodotLib_setup(JNIEnv *env, jc
209208

210209
TTS_Android::setup(p_godot_tts);
211210

212-
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
213-
GDREGISTER_CLASS(JNISingleton);
211+
java_class_wrapper = memnew(JavaClassWrapper);
214212
return true;
215213
}
216214

0 commit comments

Comments
 (0)