How to properly exit Bevy app on Android

Normally, a Bevy application can be exit with AppExit, but on Android, that is not enough and can cause the app fails to reopen. To completely exit the Bevy application on Android, we need to do that from the Android side.

Start with the Android example: https://github.com/bevyengine/bevy/tree/main/examples/mobile/android_example

Java wrapper

In MainActivity.java, add a function for exit the app, so Bevy app can call it in the Rust side:

...
import android.os.Handler;


public class MainActivity extends GameActivity {
...

    // This function will exit the Android app
    public void exitAppActivity() {
        // `finishAffinity` needs to be run in main thread
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                MainActivity.this.finishAffinity();
            }
        });
    }
}

Bevy app

Add dependency to jni for android target in Cargo.toml.

[target.'cfg(target_os = "android")'.dependencies]
jni = "0.21"

In Bevy app, call the Android function above:

#[bevy_main]
fn main() {
    let mut app = App::new();
    ...
    app.run();

    // Exit the Android app after Bevy job is finished
    #[cfg(target_os = "android")]
    exit_android_app();
}

#[cfg(target_os = "android")]
fn exit_android_app() -> anyhow::Result<()> {
    let ctx = bevy::window::ANDROID_APP.get().expect("ANDROID_APP should be defined");
    let vm = unsafe { jni::JavaVM::from_raw(ctx.vm_as_ptr() as *mut *const jni::sys::JNIInvokeInterface_) }?;
    let activity = unsafe { jni::objects::JObject::from_raw(ctx.activity_as_ptr() as *mut jni::sys::_jobject) };
    let mut env = vm.attach_current_thread()?;

    // Call Android function
    env.call_method(activity, "exitAppActivity", "()V", &[])?;
    Ok(())
}

See also

comments powered by Disqus