You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MacOS SwiftUI应用:实现仅菜单栏启动,阻止主窗口打开

SwiftUI macOS菜单栏应用消除启动空白主窗口方案

背景

开发基于SwiftUI的macOS应用,需求是仅通过菜单栏启动,不打开空白主窗口,同时保留通知功能。

问题

应用启动时,菜单栏图标显示正常,但会自动打开一个空白主窗口,不符合预期。

已尝试操作

移除var body部分或删除Settings{}代码块,但实现App协议时这两项为必填项,会触发编译错误。

核心代码上下文(Quote_DropletApp.swift)

以下是控制窗口启动的唯一核心文件代码:

class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate {
    static private(set) var instance: AppDelegate!
    lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    let menu = ApplicationMenu()
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        AppDelegate.instance = self
        statusBarItem.button?.image = NSImage(named: NSImage.Name("QuoteDropletSmall"))
        statusBarItem.button?.imagePosition = .imageLeading
        statusBarItem.menu = menu.createMenu()
        
        // 自动启动逻辑
        let mainAppIdentifier = "com.Daggerpov.Quote-Droplet"
        let runningApps = NSWorkspace.shared.runningApplications
        let isRunning = !runningApps.filter { $0.bundleIdentifier == mainAppIdentifier }.isEmpty
        
        if !isRunning {
            var pathComponents = (Bundle.main.bundlePath as NSString).pathComponents
            pathComponents.removeLast()
            pathComponents.removeLast()
            pathComponents.removeLast()
            pathComponents.removeLast()
            let newPath = NSString.path(withComponents: pathComponents)
            
            NSWorkspace.shared.launchApplication(newPath)
        }
        
        UNUserNotificationCenter.current().delegate = self
        
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
            if success {
                NotificationScheduler.shared.scheduleNotifications()
            } else if let error {
                print(error.localizedDescription)
            }
        }
    }
}

解决方案

方案一:通过Info.plist设置后台运行

在项目的Info.plist中添加LSUIElement键,设置值为YES。此配置会让应用以纯菜单栏后台应用运行,不会显示Dock图标和默认主窗口。

方案二:在SwiftUI App结构体中禁用默认窗口

若需保留Dock图标但启动时不显示主窗口,修改App结构体代码如下:

@main
struct Quote_DropletApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        // 用空视图的WindowGroup避免自动创建主窗口
        WindowGroup {
            EmptyView()
        }
        .windowStyle(.hiddenTitleBar) // 可选:彻底隐藏窗口样式
        
        // 保留Settings场景但用空视图避免显示设置窗口,或替换为自定义设置UI
        Settings {
            EmptyView()
        }
    }
}

注意点

  • 方案一设置后,应用不会出现在Cmd+Tab切换列表中,若需支持应用切换,优先选方案二。
  • 确保AppDelegate中的自动启动逻辑不会重复触发窗口创建。

内容的提问来源于stack exchange,提问作者Daggerpov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:05:11