From 21c32b42ff0b451ad5f81d3d6ceb3a1c1d45562d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E5=A4=A9?= Date: Tue, 17 Mar 2026 00:01:29 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20#91=20macOS=20Gateway=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=87=8D=E5=A4=8D=E8=A7=A6=E5=8F=91'?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E9=A1=B9=E5=B7=B2=E6=B7=BB=E5=8A=A0'?= =?UTF-8?q?=E9=80=9A=E7=9F=A5(=E6=A3=80=E6=9F=A5launchctl=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E7=8A=B6=E6=80=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/service.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src-tauri/src/commands/service.rs b/src-tauri/src/commands/service.rs index 0b9f98a..497e648 100644 --- a/src-tauri/src/commands/service.rs +++ b/src-tauri/src/commands/service.rs @@ -487,20 +487,27 @@ mod platform { // 先尝试 plist 文件是否存在 if !std::path::Path::new(&path).exists() { - // plist 不存在,直接用 CLI 启动 return start_gateway_direct(); } - let bootstrap_out = Command::new("launchctl") - .args(["bootstrap", &domain_target, &path]) + // Issue #91: 先检查服务是否已注册,避免重复 bootstrap 触发 macOS "后台项已添加" 通知 + let already_registered = Command::new("launchctl") + .args(["print", &service_target]) .output() - .map_err(|e| format!("bootstrap 失败: {e}"))?; + .map(|out| out.status.success()) + .unwrap_or(false); - if !bootstrap_out.status.success() { - let stderr = String::from_utf8_lossy(&bootstrap_out.stderr); - if !stderr.contains("already bootstrapped") && !stderr.trim().is_empty() { - // launchctl 失败(如 plist 二进制路径过期),回退到直接启动 - return start_gateway_direct(); + if !already_registered { + let bootstrap_out = Command::new("launchctl") + .args(["bootstrap", &domain_target, &path]) + .output() + .map_err(|e| format!("bootstrap 失败: {e}"))?; + + if !bootstrap_out.status.success() { + let stderr = String::from_utf8_lossy(&bootstrap_out.stderr); + if !stderr.contains("already bootstrapped") && !stderr.trim().is_empty() { + return start_gateway_direct(); + } } }