三层排查实锤(lldb 运行时取证): 1. 红点按钮真实 action 是 AppKit 私有 selector `_close:`(并非文档所称 performClose:),内部直接关窗,绕过 performClose/close 重写与 delegate 拦截 2. flutter create 模板的 AppDelegate 自带 applicationShouldTerminateAfterLastWindowClosed 返回 true——最后一个窗口 关闭即 NSApp.terminate,这是"点红点进程退出、托盘随进程消失"的根因 3. 修复:改为返回 false。窗口即便被真关闭,进程/HTTP 服务/托盘也保持运行, 托盘点击 makeKeyAndOrderFront 恢复窗口(releasedWhenClosed=NO,窗口对象在) 验证(红点 action 原样重放 `_close:`):窗口关闭后进程存活、服务在线、 托盘状态栏窗口存在、makeKeyAndOrderFront 可恢复窗口。 保留 MainFlutterWindow 的 performClose/close 重写(Cmd+W 等正常路径只隐藏 不关闭,体验更好)。
22 lines
994 B
Swift
22 lines
994 B
Swift
import Cocoa
|
||
import FlutterMacOS
|
||
|
||
@main
|
||
class AppDelegate: FlutterAppDelegate {
|
||
/// 关窗不退出(托盘常驻的核心开关)。
|
||
///
|
||
/// 红点按钮的真实 action 是 AppKit 私有 `_close:`(实测 macOS 15,并非文档所说
|
||
/// 的 performClose:),会绕过 performClose/close 的重写把窗口真正关闭;窗口关闭后
|
||
/// AppKit 询问本方法——Flutter 模板默认返回 true(关窗即退出),这正是"点红点
|
||
/// 直接退出、托盘消失"的根因。返回 false 后:窗口关闭时进程/HTTP 服务/托盘保持
|
||
/// 运行,托盘点击 makeKeyAndOrderFront 恢复窗口(xib releasedWhenClosed=NO,
|
||
/// 窗口对象未释放)。真正退出只走托盘菜单 → NSApp.terminate / Cmd+Q。
|
||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||
return false
|
||
}
|
||
|
||
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
|
||
return true
|
||
}
|
||
}
|