问题描述
在 App 内「更多 → 按需求连接」中开启「始终开启 (Always On)」后,回到首页点「启动」连一次,当前连接正常,终端执行 scutil --nc show "Clash by Hako" 也显示 OnDemandEnabled: TRUE。但系统重启(关机再开机)后,即使系统 VPN 显示已开启,「始终开启」也不会再自动连接代理,必须手动打开 App 点「启动」才能恢复。
复现步骤
- App 内「更多 → 按需求连接」→ 打开「始终开启 (Always On)」
- 首页「启动」连接一次
- 终端执行
scutil --nc show "Clash by Hako",确认 OnDemandEnabled: TRUE
- 重启系统
- 重启后代理不会自动连接,且 OnDemand 被写回 FALSE(「按需求连接」界面开关看似还开着,但实际已失效)
根因分析
问题出在 App 退出时的处理逻辑。在 apple/HakoClient/Sources/Mac/HakoMacQuit.swift 中,当 App 终止且隧道正在运行时,会调用 stop();而 VPNController.swift 的 stop() 会将 isOnDemandEnabled 置为 false 并执行 saveToPreferences() 写回系统配置(即 disarm OnDemand)。
由于系统「关机 / 重启 / 注销」也会触发 App 的退出路径,于是每次重启都会执行一次 disarm,把用户在 App 里设置的“始终开启”撤销掉。这正是「设置后重启即失效」的根因。
值得注意:代码中已经存在 .readerQuitLeavingTunnelRunning 场合走 return .terminateNow(不调用 stop、保留隧道),说明作者本意是要区分「用户主动退出」与「系统终止」——只是目前系统终止仍走了对隧道 disarm 的路径。
建议修复
- 监听系统关机 / 电源关闭通知(如
NSWorkspace.willPowerOffNotification / NSWorkspaceWillPowerOffNotification)。
- 在该通知触发时直接
return .terminateNow,跳过 stop() / disarmOnDemandForUserStop,从而保留系统级 On Demand 配置。
- 仅当用户在 App 内主动「停止 / 断开」或 Cmd+Q 退出时,才走原有的 disarm 逻辑。
这样「始终开启」才能在开机 / 重启后持续生效,无需用户每次手动启动。
环境信息
- App: Clash by Hako(
com.hako.network)v1.0.10
- macOS(Apple Silicon)
- 系统 VPN(Packet Tunnel / Network Extension)模式,无本地代理端口
问题描述
在 App 内「更多 → 按需求连接」中开启「始终开启 (Always On)」后,回到首页点「启动」连一次,当前连接正常,终端执行
scutil --nc show "Clash by Hako"也显示OnDemandEnabled: TRUE。但系统重启(关机再开机)后,即使系统 VPN 显示已开启,「始终开启」也不会再自动连接代理,必须手动打开 App 点「启动」才能恢复。复现步骤
scutil --nc show "Clash by Hako",确认OnDemandEnabled: TRUE根因分析
问题出在 App 退出时的处理逻辑。在
apple/HakoClient/Sources/Mac/HakoMacQuit.swift中,当 App 终止且隧道正在运行时,会调用stop();而VPNController.swift的stop()会将isOnDemandEnabled置为false并执行saveToPreferences()写回系统配置(即 disarm OnDemand)。由于系统「关机 / 重启 / 注销」也会触发 App 的退出路径,于是每次重启都会执行一次 disarm,把用户在 App 里设置的“始终开启”撤销掉。这正是「设置后重启即失效」的根因。
值得注意:代码中已经存在
.readerQuitLeavingTunnelRunning场合走return .terminateNow(不调用 stop、保留隧道),说明作者本意是要区分「用户主动退出」与「系统终止」——只是目前系统终止仍走了对隧道 disarm 的路径。建议修复
NSWorkspace.willPowerOffNotification/NSWorkspaceWillPowerOffNotification)。return .terminateNow,跳过stop()/disarmOnDemandForUserStop,从而保留系统级 On Demand 配置。这样「始终开启」才能在开机 / 重启后持续生效,无需用户每次手动启动。
环境信息
com.hako.network)v1.0.10