cf19ca2d34
根因:launch_at_startup 0.5.1 在 macOS 无自带实现,需宿主接 MethodChannel,而我们 Runner 从没实现 → enable() 抛 MissingPluginException 被 try/catch 吞掉 → 登录项从未注册,自启失败。 学 Tailscale(LoginItemHelper-macsys + SMAppService): - 新增无界面 LoginItem helper(macos/login_helper,LSBackgroundOnly),登录时带 --autostart 拉起主 app(→隐藏到托盘); - build_login_helper.sh 构建期编译+签名+嵌入 Contents/Library/LoginItems/(新 Run Script 阶段); - MainFlutterWindow 接 launch_at_startup MethodChannel → SMAppService.loginItem 注册/注销。 构建通过:helper 嵌入+签名,主 app --deep --strict 校验过。Windows 自启(schtasks)不变。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
3.0 KiB
Swift
71 lines
3.0 KiB
Swift
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)
|
||
}
|
||
}
|
||
}
|
||
}
|