From 9eae0a0a878e7c27690073f586d2da45c69280fa Mon Sep 17 00:00:00 2001 From: kdletters Date: Tue, 1 Sep 2026 17:04:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9B=B4=E6=96=B0=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=8F=90=E6=9D=83=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过 Windows UAC 启动 NSIS 静默安装 释放临时安装包句柄后再提交并启动 同步更新客户端升级技术方案 --- .../src-tauri/src/main.rs | 45 +++++++++++++++++-- ...方案】AGC客户端更新检查与下载-2026-08-31.md | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/main.rs b/apps/ai-game-creator-shell/src-tauri/src/main.rs index 8610ef687..8cccbcefd 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/main.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/main.rs @@ -57,6 +57,45 @@ struct AgcUpdateDownloadProgress { total_bytes: Option, } +#[cfg(windows)] +fn launch_agc_installer(path: &Path) -> Result<(), String> { + use std::os::windows::process::CommandExt; + + let executable = path.to_string_lossy().replace('\'', "''"); + let script = format!( + "$ErrorActionPreference = 'Stop'; Start-Process -Verb RunAs -FilePath '{executable}' -ArgumentList @('/S')" + ); + let status = Command::new("powershell.exe") + .args([ + "-NoProfile", + "-NonInteractive", + "-WindowStyle", + "Hidden", + "-Command", + script.as_str(), + ]) + .creation_flags(0x0800_0000) + .status() + .map_err(|error| format!("无法启动更新安装程序:{error}"))?; + if status.success() { + Ok(()) + } else { + Err(format!( + "无法启动更新安装程序(exit code {:?})", + status.code() + )) + } +} + +#[cfg(not(windows))] +fn launch_agc_installer(path: &Path) -> Result<(), String> { + Command::new(path) + .arg("/S") + .spawn() + .map(|_| ()) + .map_err(|error| format!("无法启动更新安装程序:{error}")) +} + #[tauri::command] async fn download_agc_update( app: tauri::AppHandle, @@ -154,6 +193,7 @@ async fn download_agc_update( let _ = fs::remove_file(&temporary); return Err("保存更新文件失败".to_string()); } + drop(file); if let Some(expected_size) = expected_size { if downloaded_bytes != expected_size { let _ = fs::remove_file(&temporary); @@ -181,10 +221,7 @@ async fn download_agc_update( let _ = fs::remove_file(&temporary); return Err(format!("提交更新文件失败:{error}")); } - Command::new(&target) - .arg("/S") - .spawn() - .map_err(|_| "无法启动更新安装程序".to_string())?; + launch_agc_installer(&target)?; app.exit(0); Ok(target.to_string_lossy().into_owned()) } diff --git a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md index 7c3e3cebd..0221e9304 100644 --- a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md +++ b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md @@ -19,7 +19,7 @@ AGC 每次启动时由根窗口检查一次公开 OSS 更新清单。清单默 } ``` -`downloadUrl` 必须是 HTTPS;如提供 `sha256` / `size`,Tauri 下载时会校验摘要和字节数。点击“下载更新”后,客户端将安装包流式写入系统临时目录并显示进度,校验成功后自动启动 NSIS 静默安装并退出旧客户端。 +`downloadUrl` 必须是 HTTPS;如提供 `sha256` / `size`,Tauri 下载时会校验摘要和字节数。点击“下载更新”后,客户端将安装包流式写入系统临时目录并显示进度,校验成功后通过 Windows UAC 提权启动 NSIS 静默安装并退出旧客户端。 ## 启动与失败策略