A modern macOS application using a workspace + SPM package architecture for clean separation between app shell and feature code.
Flasher/
├── Flasher.xcworkspace/ # Open this file in Xcode
├── Flasher.xcodeproj/ # App shell project
├── Flasher/ # App target (minimal)
│ ├── Assets.xcassets/ # App-level assets (icons, colors)
│ ├── FlasherApp.swift # App entry point
│ ├── Flasher.entitlements # App sandbox settings
│ └── Flasher.xctestplan # Test configuration
├── FlasherPackage/ # 🚀 Primary development area
│ ├── Package.swift # Package configuration
│ ├── Sources/FlasherFeature/ # Your feature code
│ └── Tests/FlasherFeatureTests/ # Unit tests
└── FlasherUITests/ # UI automation tests
- App Shell:
Flasher/contains minimal app lifecycle code - Feature Code:
FlasherPackage/Sources/FlasherFeature/is where most development happens - Separation: Business logic lives in the SPM package, app target just imports and displays it
- Files added to the filesystem automatically appear in Xcode
- No need to manually add files to project targets
- Reduces project file conflicts in teams
The app is sandboxed by default with basic file access permissions. Modify Flasher.entitlements to add capabilities as needed.
Most development happens in FlasherPackage/Sources/FlasherFeature/ - organize your code as you prefer.
Types exposed to the app target need public access:
public struct SettingsView: View {
public init() {}
public var body: some View {
// Your view code
}
}Edit FlasherPackage/Package.swift to add SPM dependencies:
dependencies: [
.package(url: "https://github.com/example/SomePackage", from: "1.0.0")
],
targets: [
.target(
name: "FlasherFeature",
dependencies: ["SomePackage"]
),
]- Unit Tests:
FlasherPackage/Tests/FlasherFeatureTests/(Swift Testing framework) - UI Tests:
FlasherUITests/(XCUITest framework) - Test Plan:
Flasher.xctestplancoordinates all tests
Build settings are managed through XCConfig files in Config/:
Config/Shared.xcconfig- Common settings (bundle ID, versions, deployment target)Config/Debug.xcconfig- Debug-specific settingsConfig/Release.xcconfig- Release-specific settingsConfig/Tests.xcconfig- Test-specific settings
The app is sandboxed by default with basic file access. Edit Flasher/Flasher.entitlements to add capabilities:
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<!-- Add other entitlements as needed -->Add multiple windows and settings panels:
@main
struct FlasherApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
Settings {
SettingsView()
}
}
}- App-Level Assets:
Flasher/Assets.xcassets/(app icon with multiple sizes, accent color) - Feature Assets: Add
Resources/folder to SPM package if needed
To include assets in your feature package:
.target(
name: "FlasherFeature",
dependencies: [],
resources: [.process("Resources")]
)This project was scaffolded using XcodeBuildMCP, which provides tools for AI-assisted macOS development workflows.