godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Bring back a way to access JNI on GDExtension #6734

Closed j20001970 closed 1 year ago

j20001970 commented 1 year ago

Describe the project you are working on

A Godot GDExtension/GDNative plugin that access device camera on Android via JNI.

Describe the problem or limitation you are having in your project

On Godot 3.x, JNIEnv can be accessed on GDNative with no problem, but on Godot 4 such option is no longer available on GDExtension.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The goal is to use java classes and JNI-related functionalities on GDExtension C++. Bring back a way to get Godot JNIEnv, similar to android_api->godot_android_get_env() on GDNative, should be enough to overcome the problem.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Same as above.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Since this involves JVM belonging to Godot itself, I don't think it can be workaround with a few lines script or in a form of add-on.

Is there a reason why this should be core and not an add-on in the asset library?

Same as above.

EDIT: rephrasing

j20001970 commented 1 year ago

I think I've figured out how to access JNI on GDExtension...

For those who don't know yet, you can do the following to obtain JVM from Godot:

  1. Create a Android plugin and load the GDExtension library using System.loadLibrary in static initializer block.
    public class MyPlugin extends GodotPlugin {
    static {
        // load libmylib.so
        System.loadLibrary("mylib");
    }
    }
  2. Define a JavaVM pointer and JNI_OnLoad where you need them, on C++ it will look like this:
    
    // define static JavaVM
    static JavaVM *jvm = NULL;

// this will be called when Android plugin initialize extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM vm, void reserved) { JNIEnv *env; if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) return JNI_ERR; jvm = vm; return JNI_VERSION_1_6; }


3. After caching jvm, you can use jvm->GetEnv whenever you need it, just remember to check if attaching current thread is needed.

While the solution is not that trivial (when compared to GDNative where you can directly using `android_api->godot_android_get_env()` without worry about attach/detach current thread), this problem can be completely worked around. I will close the issue since it will likely be considered solvable by a few lines of script.