Open lockieluke opened 8 months ago
For those who are looking for a way to reliably run async functions on exit in a Tauri app, this is how I managed to do it:
First make an exit lock, this is responsible for blocking your Tauri app from exiting, I made a Lazy
global variable for this, just to make it nice and simple. You'll need once_cell.
use once_cell::sync::Lazy;
pub static EXIT_LOCKED: Lazy<std::sync::Mutex<bool>> = Lazy::new(|| {
std::sync::Mutex::new(true)
});
Then, make an on_exit
function that takes in an AppHandle
. This function runs your cleanup actions and blocks the main thread using a loop
until they have been run, no matter sync or async. You'll need the futures crate for this one.
fn on_exit(app: &AppHandle, need_exiting: bool) {
futures::executor::block_on(async move {
tauri::async_runtime::spawn(async move {
// Execute your cleanup actions here
stop_all_downloads().await;
*EXIT_LOCKED.lock().unwrap() = false;
})
});
let win = app.get_window("main").unwrap();
win.hide().unwrap();
loop {
if !*EXIT_LOCKED.lock().unwrap() {
break;
}
};
win.close().unwrap();
if need_exiting {
app.exit(0);
}
}
Intercept window events to run cleanup actions when a window is closed, this implementation is for single-window apps. Make sure your storing your tauri::Builder
to a variable or this won't work.
let app = tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
// Your handlers
])
.on_window_event(|event| match event {
WindowEvent::CloseRequested { api, .. } => {
api.prevent_close();
on_exit(&event.window().app_handle(), true);
},
_ => {}
})
.build(tauri::generate_context!())
.expect("error while running tauri application");
Intercept events from the app lifecycle events(RunEvent
) and run your cleanup actions also when Exit
is triggered.
app.run(move |app, event| match event {
RunEvent::Exit => {
// Since RunEvent:Exit already executes exit, we'll pass false to on_exit so it won't exit twice
on_exit(app, false);
},
_ => {}
});
This is a janky workaround but it works reliably enough, if there's a better way, please share. Hopefully, Tauri will handle pre-exit events reliably in v2 🤞
How exactly are you exiting the app? Closing Windows via the red button for example should trigger ExitRequested once all windows are closed (even though that's not really how macos apps should behave). right click -> Quit on the dock item may be the same as https://github.com/tauri-apps/tauri/issues/3084 if it's not working.
Using Command+Q or Quit from menu bar
For those who are looking for a way to reliably run async functions on exit in a Tauri app, this is how I managed to do it:
First make an exit lock, this is responsible for blocking your Tauri app from exiting, I made a
Lazy
global variable for this, just to make it nice and simple. You'll need once_cell.use once_cell::sync::Lazy; pub static EXIT_LOCKED: Lazy<std::sync::Mutex<bool>> = Lazy::new(|| { std::sync::Mutex::new(true) });
Then, make an
on_exit
function that takes in anAppHandle
. This function runs your cleanup actions and blocks the main thread using aloop
until they have been run, no matter sync or async. You'll need the futures crate for this one.fn on_exit(app: &AppHandle, need_exiting: bool) { futures::executor::block_on(async move { tauri::async_runtime::spawn(async move { // Execute your cleanup actions here stop_all_downloads().await; *EXIT_LOCKED.lock().unwrap() = false; }) }); let win = app.get_window("main").unwrap(); win.hide().unwrap(); loop { if !*EXIT_LOCKED.lock().unwrap() { break; } }; win.close().unwrap(); if need_exiting { app.exit(0); } }
Intercept window events to run cleanup actions when a window is closed, this implementation is for single-window apps. Make sure your storing your
tauri::Builder
to a variable or this won't work.let app = tauri::Builder::default() .invoke_handler(tauri::generate_handler![ // Your handlers ]) .on_window_event(|event| match event { WindowEvent::CloseRequested { api, .. } => { api.prevent_close(); on_exit(&event.window().app_handle(), true); }, _ => {} }) .build(tauri::generate_context!()) .expect("error while running tauri application");
Intercept events from the app lifecycle events(
RunEvent
) and run your cleanup actions also whenExit
is triggered.app.run(move |app, event| match event { RunEvent::Exit => { // Since RunEvent:Exit already executes exit, we'll pass false to on_exit so it won't exit twice on_exit(app, false); }, _ => {} });
This is a janky workaround but it works reliably enough, if there's a better way, please share. Hopefully, Tauri will handle pre-exit events reliably in v2 🤞
Is this still currently the best way to do this?
Describe the bug
nothing gets run when exit is requested
Reproduction
No response
Expected behavior
No response
Full
tauri info
output