Bevy(Wasm)环境下exit_on_all_closed不生效,如何处理浏览器标签页关闭?
Bevy Wasm环境下处理浏览器窗口/标签页关闭的解决方案
在原生环境中,Bevy的exit_on_all_closed参数可以在窗口关闭时触发应用退出,但这一逻辑不适用于WebAssembly(Wasm)环境——因为浏览器的窗口生命周期由JS引擎管理,Bevy原生的窗口关闭检测逻辑无法感知浏览器标签页/窗口的关闭事件。
解决方案:监听浏览器原生事件触发Bevy退出
我们可以通过web_sys crate监听浏览器的beforeunload或unload事件,在事件触发时向Bevy发送AppExit事件,实现应用的优雅退出。
步骤1:添加依赖
在Cargo.toml中添加web-sys依赖:
[dependencies] bevy = "0.12" # 请匹配你的Bevy版本 web-sys = { version = "0.3", features = ["Window", "EventTarget", "BeforeUnloadEvent"] }
步骤2:编写事件监听系统
创建一个启动系统,注册浏览器的关闭事件监听,并在事件触发时发送Bevy的AppExit事件:
use bevy::app::AppExit; use bevy::prelude::*; use std::rc::Rc; use web_sys::{window, BeforeUnloadEvent}; fn listen_for_browser_shutdown(mut exit_events: EventWriter<AppExit>) { let window = window().expect("浏览器环境不可用"); // 创建闭包处理beforeunload事件 let exit_events = Rc::new(exit_events); let closure = Closure::wrap(Box::new(move |_event: BeforeUnloadEvent| { // 发送AppExit事件触发Bevy退出 exit_events.send(AppExit); }) as Box<dyn FnMut(_)>); // 注册事件监听器 window.add_event_listener_with_callback( "beforeunload", closure.as_ref().unchecked_ref() ).expect("无法注册浏览器关闭事件监听器"); // 防止闭包被GC回收 closure.forget(); }
步骤3:将系统添加到Bevy应用
在main函数中注册上述启动系统:
fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { window: WindowDescriptor { title: "Extreme".to_string(), ..default() }, add_primary_window: true, exit_on_all_closed: true, close_when_requested: true, })) .add_startup_system(listen_for_browser_shutdown) .run() }
关键说明
beforeunload事件会在用户关闭标签页/窗口、刷新页面或导航离开时触发,适合用于执行资源清理、数据保存等退出前逻辑;- 如果不需要处理前置逻辑,仅需确保Bevy退出,也可以使用
unload事件,但它的触发时机更晚,可能无法完成所有清理操作; - 即使不手动触发
AppExit,浏览器关闭时也会直接终止Wasm实例,但手动监听事件可以实现优雅退出,避免资源泄漏或数据丢失。
内容的提问来源于stack exchange,提问作者tangoti84
相关产品推荐
相关产品推荐

