import Cocoa import FlutterMacOS import ServiceManagement class MainFlutterWindow: NSWindow { // launch_at_startup 插件在 macOS 没自带实现,需宿主接 MethodChannel。学 Tailscale 用 // SMAppService.loginItem 注册内置的 PangolinLoginHelper(登录时它带 --autostart 拉起主 app)。 private let loginHelperID = "com.pangolin.pangolin.LoginHelper" override func awakeFromNib() { let flutterViewController = FlutterViewController() self.contentViewController = flutterViewController // 桌面默认窗口 920×600(对齐设计稿 ui_kits/desktop),最小 720×560。 let defaultSize = NSSize(width: 920, height: 600) self.setContentSize(defaultSize) self.contentMinSize = NSSize(width: 720, height: 560) self.center() RegisterGeneratedPlugins(registry: flutterViewController) // P1 方案B:VPN 原生控制通道(NETunnelProviderManager 启停 PacketTunnel)。 // 需 VpnChannel.swift 已加入 Runner target 的 Compile Sources。 VpnChannel.register(with: flutterViewController.registrar(forPlugin: "VpnChannel")) // 开机自启 MethodChannel(launch_at_startup 插件的原生侧,macOS 需宿主实现)。 registerLaunchAtStartupChannel(messenger: flutterViewController.engine.binaryMessenger) super.awakeFromNib() // 开机自启(登录项带 --autostart):不弹主窗口,直接隐藏到托盘(与 Windows 一致)。 // Dart 侧 main() 也会 windowManager.hide();这里原生 orderOut 兜底,避免 storyboard // "Visible At Launch" 把窗口闪出来。常规启动(无参数)正常显示。 if CommandLine.arguments.contains("--autostart") { self.orderOut(nil) } } // launch_at_startup 的 macOS 原生实现:SMAppService.loginItem 注册/注销 LoginHelper。 private func registerLaunchAtStartupChannel(messenger: FlutterBinaryMessenger) { let channel = FlutterMethodChannel(name: "launch_at_startup", binaryMessenger: messenger) let helperID = loginHelperID channel.setMethodCallHandler { call, result in guard #available(macOS 13.0, *) else { result(FlutterError(code: "unsupported", message: "开机自启需 macOS 13+", details: nil)) return } let svc = SMAppService.loginItem(identifier: helperID) switch call.method { case "launchAtStartupIsEnabled": result(svc.status == .enabled) case "launchAtStartupSetEnabled": let on = ((call.arguments as? [String: Any])?["setEnabledValue"] as? Bool) ?? false do { if on { if svc.status != .enabled { try svc.register() } } else { if svc.status == .enabled { try svc.unregister() } } result(nil) } catch { NSLog("[pangolin/launch] SMAppService %@ failed: %@", on ? "register" : "unregister", error.localizedDescription) result(FlutterError(code: "smappservice", message: error.localizedDescription, details: nil)) } default: result(FlutterMethodNotImplemented) } } } }