mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
fix(updater): clear tray icon on the direct-restart update path
restart_process re-execs via tauri::process::restart (spawn + exit(0)), which skips Tauri's internal cleanup_before_exit and all RunEvent::Exit plugin hooks. Window state, proxy/live restore and the single-instance lock were already compensated explicitly; the tray icon was not. On macOS/Linux the OS drops the status item when the process dies, so the gap there was cosmetic at most. The real residue risk is the Windows branch, which never reaches restart_process at all: update.install() exits the process inside the updater plugin (std::process::exit(0)), bypassing TrayIcon::drop — no NIM_DELETE is sent and a stale icon lingers in the shell until hovered, the same failure remove_tray_icon_before_exit was originally added for on the quit path. Call remove_tray_icon_before_exit (set_visible(false), proxied to the main thread via run_item_main_thread) in restart_process and before the Windows install. Deliberately not AppHandle::cleanup_before_exit(): it drops tray icons on the calling thread, which is not safe off the main thread on macOS (NSStatusItem).
This commit is contained in:
@@ -115,10 +115,13 @@ pub async fn install_update_and_restart(app: AppHandle) -> Result<bool, String>
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// Windows updater 会在 install() 内启动安装器并直接退出当前进程。
|
||||
// 因此清理只能放在 install 前执行。
|
||||
// Windows updater 会在 install() 内启动安装器并直接退出当前进程
|
||||
// (插件内部 std::process::exit(0),绕过 TrayIcon::drop、不发
|
||||
// NIM_DELETE,会残留死图标——与托盘"退出"路径相同的问题)。
|
||||
// 因此清理只能放在 install 前执行,且必须显式移除托盘图标。
|
||||
crate::save_window_state_before_exit(&app);
|
||||
crate::cleanup_before_exit(&app).await;
|
||||
crate::remove_tray_icon_before_exit(&app);
|
||||
crate::destroy_single_instance_lock(&app);
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
||||
update.install(bytes).map_err(|e| {
|
||||
|
||||
+12
-2
@@ -1646,7 +1646,7 @@ pub async fn cleanup_before_exit(app_handle: &tauri::AppHandle) {
|
||||
/// 触发 tray-icon 内部的 `remove_tray_icon` → `Shell_NotifyIconW(NIM_DELETE)`,
|
||||
/// 在进程结束前干净地把图标摘掉。其它平台 `set_visible(false)` 也是
|
||||
/// 正常的隐藏/移除语义,作为跨平台兜底也安全。
|
||||
fn remove_tray_icon_before_exit(app_handle: &tauri::AppHandle) {
|
||||
pub(crate) fn remove_tray_icon_before_exit(app_handle: &tauri::AppHandle) {
|
||||
if let Some(tray) = app_handle.tray_by_id(tray::TRAY_ID) {
|
||||
if let Err(e) = tray.set_visible(false) {
|
||||
log::warn!("退出时移除托盘图标失败: {e}");
|
||||
@@ -1973,8 +1973,18 @@ pub fn destroy_single_instance_lock(app_handle: &tauri::AppHandle) {
|
||||
tauri_plugin_single_instance::destroy(app_handle);
|
||||
}
|
||||
|
||||
/// 释放 single-instance 锁后重启当前应用。
|
||||
/// 清理托盘图标、释放 single-instance 锁后重启当前应用。
|
||||
///
|
||||
/// 直接走 `tauri::process::restart`(spawn 新进程 + `exit(0)`),不经过事件
|
||||
/// 循环退出,因此 Tauri 内部的 `cleanup_before_exit` 和各插件的
|
||||
/// `RunEvent::Exit` 钩子都不会执行。需要的清理由调用方与本函数显式补偿:
|
||||
/// 窗口状态、代理/Live 恢复(调用方);托盘图标、single-instance 锁(本函数)。
|
||||
///
|
||||
/// 有意不调 `AppHandle::cleanup_before_exit()`:它会在调用线程上 Drop 托盘
|
||||
/// 图标,而 macOS 的 NSStatusItem 操作要求主线程;`set_visible(false)` 走
|
||||
/// `run_item_main_thread` 代理,跨线程安全(见 `remove_tray_icon_before_exit`)。
|
||||
pub fn restart_process(app_handle: &tauri::AppHandle) -> ! {
|
||||
remove_tray_icon_before_exit(app_handle);
|
||||
destroy_single_instance_lock(app_handle);
|
||||
tauri::process::restart(&app_handle.env());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user