Skip to content

Commit 06a7cf7

Browse files
committed
Merge pull request godotengine#97500 from m4gr3d/update_godot_plugin_to_use_javaclasswrapper
Remove the restriction on supported types for Godot Android plugins
2 parents 97fa718 + 4587d14 commit 06a7cf7

File tree

11 files changed

+133
-209
lines changed

11 files changed

+133
-209
lines changed

platform/android/api/api.cpp

Lines changed: 4 additions & 6 deletions
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_org_godotengine_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

Lines changed: 7 additions & 6 deletions
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

Lines changed: 24 additions & 173 deletions
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/export/export_plugin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,8 +3263,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
32633263
cmdline.push_back(apk_build_command);
32643264
}
32653265

3266+
String addons_directory = ProjectSettings::get_singleton()->globalize_path("res://addons");
3267+
32663268
cmdline.push_back("-p"); // argument to specify the start directory.
32673269
cmdline.push_back(build_path); // start directory.
3270+
cmdline.push_back("-Paddons_directory=" + addons_directory); // path to the addon directory as it may contain jar or aar dependencies
32683271
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
32693272
cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
32703273
cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.

platform/android/java/app/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ dependencies {
6363
implementation files(pluginsBinaries)
6464
}
6565

66+
// Automatically pick up local dependencies in res://addons
67+
String addonsDirectory = getAddonsDirectory()
68+
if (addonsDirectory != null && !addonsDirectory.isBlank()) {
69+
implementation fileTree(dir: "$addonsDirectory", include: ['*.jar', '*.aar'])
70+
}
71+
6672
// .NET dependencies
6773
String jar = '../../../../modules/mono/thirdparty/libSystem.Security.Cryptography.Native.Android.jar'
6874
if (file(jar).exists()) {

platform/android/java/app/config.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,8 @@ ext.shouldUseLegacyPackaging = { ->
408408
// Default behavior for minSdk >= 23
409409
return false
410410
}
411+
412+
ext.getAddonsDirectory = { ->
413+
String addonsDirectory = project.hasProperty("addons_directory") ? project.property("addons_directory") : ""
414+
return addonsDirectory
415+
}

platform/android/java/lib/src/org/godotengine/godot/Godot.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ import org.godotengine.godot.input.GodotEditText
5858
import org.godotengine.godot.input.GodotInputHandler
5959
import org.godotengine.godot.io.directory.DirectoryAccessHandler
6060
import org.godotengine.godot.io.file.FileAccessHandler
61+
import org.godotengine.godot.plugin.AndroidRuntimePlugin
62+
import org.godotengine.godot.plugin.GodotPlugin
6163
import org.godotengine.godot.plugin.GodotPluginRegistry
6264
import org.godotengine.godot.tts.GodotTTS
6365
import org.godotengine.godot.utils.CommandLineFileParser
@@ -228,7 +230,9 @@ class Godot(private val context: Context) {
228230
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
229231

230232
Log.v(TAG, "Initializing Godot plugin registry")
231-
GodotPluginRegistry.initializePluginRegistry(this, primaryHost.getHostPlugins(this))
233+
val runtimePlugins = mutableSetOf<GodotPlugin>(AndroidRuntimePlugin(this))
234+
runtimePlugins.addAll(primaryHost.getHostPlugins(this))
235+
GodotPluginRegistry.initializePluginRegistry(this, runtimePlugins)
232236
if (io == null) {
233237
io = GodotIO(activity)
234238
}

0 commit comments

Comments
 (0)