I am working on a new SwiftUI-only menu bar application and stumbled into the following problem; Whenever I define either a Window or WindowGroup in SwiftUI, at least one window is always opened on app launch. Conditional rendering (like if x { Window() }) isn’t supported either. The app should have an onboarding Window that is only shown depending on a user defaults setting. And there should be another window that can be manually opened via the menu bar item.
This is my SwiftUI App’s class:
import SwiftUI
@main
struct ExampleApp: App {
@Environment(.openWindow) var openWindow
@AppStorage("showIntroduction") private var showIntroduction = true
init() {
if showIntroduction {
print("Show introduction")
openWindow(id: "introduction")
}
}
var body: some Scene {
// How to hide this window by default?
Window("Intro", id: "introduction") {
WelcomeView()
}
.windowStyle(.hiddenTitleBar)
Settings {
SettingsView()
}
MenuBarExtra {
MenuBarView()
} label: {
Text("Test")
}
}
}
Views have the .hidden() modifier – but this doesn’t support Windows or WindowGroups. When my view is hidden but wrapped in a Window or WindowGroup an empty window is rendered instead.
Is there any way to achieve this with plain SwiftUI? Or is it necessary to programmatically create and open an NSWindow if it shouldn’t be open by default?
2
Answers
Option 1: Declare your app as menu bar utility
put this in your info.plist or info tab in project settings:
Option 2: Switch activation policy programmatically
Normal app, opens window at launch, has menu, dock item:
Agent, no window at launch, can be a menu bar app if a status item is set:
You could set up a
@NSApplicationDelegateAdaptor
and switch it inapplicationWillFinishLaunching(_:)
.Like this:
App.swift
AppDelegate.swift
Then you’d still need a status bar item and put e.g. a toggling menu item for that UserDefaults key.
I did not find a way to do this in pure SwiftUI.
However, here is a light weight approach with
NSWindow
:As you can see, there’s no dedicated
Window
Scene.If you don’t like the titled, closable design, you can close the window with this function in your
WelcomeView
, e.g. on aButton
: