tauri-apps / wry

Cross-platform WebView library in Rust for Tauri.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wry on android with winit

lucasmerlin opened this issue · comments

Is your feature request related to a problem? Please describe.
I have a egui project that uses winit and the GameActivity based android-activity backend. I tried to get the android version of wry working in my winit project but unfortunately I didn't succeed.

From the readme it sounds like in theory it should be possible to use wry on android without tao, but it's not really explained how it would work.

I guess the big question is how I would call wry::android_setup()?
I guess the JNIEnv maybe could be constructed from vm_as_ptr?
Same for the activity, activity_as_ptr?
But how would I create the foreign looper?

I also tried creating a tao and a winit instance in parallel, by making the WryActivity extend GameActivity, but then I got a error from ndk-context:
ndk-context-0.1.1/src/lib.rs:87:5:
assertion failed: previous.is_none()

I guess because both winit and tao try to initialize ndk-context.

Describe the solution you'd like
Support to use wry with winit on android, and better documentation how it would be done.

Describe alternatives you've considered

I guess an alternative for me would be to just use tao on android and use it together with https://crates.io/crates/eframe_tao, but I'd prefer to stay with winit since I'm using it with every other platform.

I did a bit of experimenting with android-activity's GameActivity last week and I got it to work but only If invoke the setup function for WRY in Java code after initialization, AndroidApp::vm_as_ptr and AndroidApp::activity_as_ptr also seem promising, but didn't have luck with it, just yet, not sure if I can work on it again soon.

Here is a simple PoC that I got working so far if anyone wants to continue research, first add this function in your Rust (notice that function name must contain your android domain and package name)

#[no_mangle]
pub extern "system" fn Java_co_realfit_agdkmainloop_MainActivity_create<'local>(
    env: JNIEnv<'local>,
    class: JClass<'local>,
    activity: JObject<'local>,
) {
    fn try_call_java_main_activity_create<'local>(
        mut env: JNIEnv<'local>,
        _class: JClass<'local>,
        activity: JObject<'local>,
    ) -> jni::errors::Result<()> {
        let webview = env.new_object(
            "android/webkit/WebView",
            "(Landroid/content/Context;)V",
            &[(&activity).into()],
        )?;
        let url = env.new_string("https://tauri.app")?;
        env.call_method(
            &webview,
            "loadUrl",
            "(Ljava/lang/String;)V",
            &[(&url).into()],
        )?;
        env.call_method(
            activity,
            "setContentView",
            "(Landroid/view/View;)V",
            &[(&webview).into()],
        )?;
        Ok(())
    }

    if let Err(err) = try_call_java_main_activity_create(env, class, activity) {
        error!("{}", err);
    }
}

then in MainActivity.java, declare this external function:

    private native void create(MainActivity activity);

then call it in the onCreate method:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        create(this);
    }