macos-app-structure
4
总安装量
4
周安装量
#52932
全站排名
安装命令
npx skills add https://github.com/makgunay/claude-swift-skills --skill macos-app-structure
Agent 安装分布
opencode
4
claude-code
4
codex
4
cursor
4
gemini-cli
3
github-copilot
3
Skill 文档
macOS App Structure
Critical Constraints
- â DO NOT use iOS-only scenes (
TabViewas root scene) â â UseWindowGroup,Window, orNavigationSplitView - â DO NOT use
UIApplicationDelegateâ â UseNSApplicationDelegateAdaptorfor AppKit hooks - â DO NOT forget
Settingsscene for Preferences â â macOS apps should have a Settings scene - â DO NOT assume single-window â â macOS apps can have multiple windows; design for it
- â DO NOT use iOS navigation patterns â â
Use
NavigationSplitView(sidebar + detail) for macOS
Standard macOS App
import SwiftUI
@main
struct MyApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
.defaultSize(width: 900, height: 600)
Settings {
SettingsView()
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
// AppKit lifecycle hooks
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true // Quit when last window closes
}
}
Menu Bar App
@main
struct MenuBarApp: App {
var body: some Scene {
MenuBarExtra("My App", systemImage: "command") {
MenuBarView()
}
.menuBarExtraStyle(.window) // Full window popover (not just menu items)
Settings {
SettingsView()
}
}
}
To hide dock icon, add to Info.plist:
<key>LSUIElement</key>
<true/>
Multiple Named Windows
@main
struct MultiWindowApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
Window("Inspector", id: "inspector") {
InspectorView()
}
.defaultSize(width: 300, height: 400)
.defaultPosition(.trailing)
Settings {
SettingsView()
}
}
}
// Open a named window from code
@Environment(\.openWindow) private var openWindow
Button("Open Inspector") { openWindow(id: "inspector") }
Content View with Sidebar
struct ContentView: View {
@State private var selection: SidebarItem? = .library
var body: some View {
NavigationSplitView {
List(selection: $selection) {
Section("Library") {
Label("All Items", systemImage: "square.grid.2x2")
.tag(SidebarItem.library)
Label("Favorites", systemImage: "heart")
.tag(SidebarItem.favorites)
}
}
.navigationSplitViewColumnWidth(min: 180, ideal: 220)
} detail: {
switch selection {
case .library: LibraryView()
case .favorites: FavoritesView()
case nil: ContentUnavailableView("Select an item", systemImage: "sidebar.left")
}
}
.navigationTitle("My App")
}
}
Project Structure Convention
MyApp/
âââ MyApp.swift # @main App struct
âââ AppDelegate.swift # NSApplicationDelegateAdaptor (if needed)
âââ Models/ # SwiftData @Model classes
âââ Views/
â âââ ContentView.swift # Main navigation structure
â âââ Components/ # Reusable view components
â âââ Settings/ # Settings/Preferences views
âââ ViewModels/ # @Observable view models
âââ Services/ # Business logic, networking, persistence
âââ Utilities/ # Extensions, helpers
âââ Resources/
â âââ Assets.xcassets
â âââ Localizable.xcstrings
âââ Info.plist
âââ MyApp.entitlements
Key Info.plist Entries (macOS)
<key>LSUIElement</key> <!-- true = menu bar only, no dock icon -->
<key>NSAccessibilityUsageDescription</key> <!-- Required for Accessibility API -->
<key>NSAppleEventsUsageDescription</key> <!-- Required for AppleScript -->
Key Entitlements
<!-- App Sandbox (required for App Store) -->
<key>com.apple.security.app-sandbox</key><true/>
<!-- Network access -->
<key>com.apple.security.network.client</key><true/>
<!-- File access -->
<key>com.apple.security.files.user-selected.read-write</key><true/>
<!-- iCloud -->
<key>com.apple.developer.icloud-container-identifiers</key>
Common Mistakes & Fixes
| Mistake | Fix |
|---|---|
No Settings scene |
Add Settings { SettingsView() } â expected on macOS |
| App doesn’t quit when last window closes | Implement applicationShouldTerminateAfterLastWindowClosed |
| Dock icon showing for menu bar app | Add LSUIElement = true to Info.plist |
| Window too small on macOS | Add .defaultSize(width:height:) to WindowGroup |
Using TabView as main navigation |
Use NavigationSplitView with sidebar on macOS |