macos-distribution
macOS Distribution & StoreKit
Critical Constraints
- ❌ DO NOT distribute without code signing → ✅ Always sign with Developer ID (direct) or Apple Distribution (App Store)
- ❌ DO NOT skip notarization for direct distribution → ✅ Required since macOS 10.15 for Gatekeeper
- ❌ DO NOT use
Transaction.currentEntitlement(for:)→ ✅ UseTransaction.currentEntitlements(for:)(plural, returns sequence) - ❌ DO NOT forget PrivacyInfo.xcprivacy → ✅ Required for App Store submission
Distribution Decision Tree
App Store distribution?
├── YES → Apple Distribution certificate + sandbox + review
│ ├── Basic version (sandbox-safe features)
│ └── Pro features via IAP/subscription
└── Direct distribution?
├── Developer ID certificate + notarization
├── DMG or pkg installer
└── Full system access (no sandbox required)
Dual strategy?
├── App Store: Basic/free version, sandbox-safe
└── Direct: Pro version, full Accessibility/CGEvent access
Code Signing & Notarization (Direct)
# Sign with Developer ID
codesign --deep --force --verify --verbose \
--sign "Developer ID Application: Your Name (TEAMID)" \
--options runtime \
MyApp.app
# Create DMG
hdiutil create -volname "MyApp" -srcfolder MyApp.app \
-ov -format UDZO MyApp.dmg
# Notarize
xcrun notarytool submit MyApp.dmg \
--apple-id "you@email.com" \
--team-id "TEAMID" \
--password "app-specific-password" \
--wait
# Staple (attach notarization ticket)
xcrun stapler staple MyApp.dmg
Sandboxing Entitlements (App Store)
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.network.client</key><true/>
<key>com.apple.security.files.user-selected.read-write</key><true/>
<key>com.apple.developer.icloud-container-identifiers</key>
<array><string>iCloud.com.company.app</string></array>
<key>com.apple.security.application-groups</key>
<array><string>group.com.company.app</string></array>
</dict>
</plist>
StoreKit — SubscriptionOfferView
import StoreKit
// Basic subscription offer
SubscriptionOfferView(productID: "com.app.pro.monthly")
.prefersPromotionalIcon(true)
// With custom icon
SubscriptionOfferView(productID: "com.app.pro.monthly") {
Image("pro_icon").resizable().frame(width: 40, height: 40)
}
// Show upgrade/downgrade based on customer status
SubscriptionOfferView(groupID: "com.app.subscriptions", visibleRelationship: .upgrade)
// Detail action
SubscriptionOfferView(productID: "com.app.pro.monthly")
.subscriptionOfferViewDetailAction { isShowingStore = true }
StoreKit — Transaction Handling
// Check entitlements (new plural API)
for await result in Transaction.currentEntitlements(for: "com.app.pro") {
if case .verified(let transaction) = result {
let appTxID = transaction.appTransactionID
if let offerPeriod = transaction.offerPeriod {
// Handle offer period
}
}
}
// Track subscription status
.subscriptionStatusTask(for: "com.app.subscriptions") { statuses in
if statuses.contains(where: { $0.state == .subscribed }) {
customerStatus = .subscribed
} else {
customerStatus = .notSubscribed
}
}
// AppTransaction — unique download identifier
let appTransaction = try await AppTransaction.shared
let transactionID = appTransaction.appTransactionID
let platform = appTransaction.originalPlatform // .iOS, .macOS, .tvOS, .visionOS
StoreKit Testing in Xcode
- File → New → File From Template → search "StoreKit Configuration File"
- Define products in the
.storekitfile - Edit scheme → Options → StoreKit Configuration → select your file
- Use Transaction Manager window to test purchase scenarios
Launch at Login
import ServiceManagement
func setLaunchAtLogin(_ enabled: Bool) {
do {
if enabled { try SMAppService.mainApp.register() }
else { try SMAppService.mainApp.unregister() }
} catch { print("Launch at login error: \(error)") }
}
func isLaunchAtLoginEnabled() -> Bool {
SMAppService.mainApp.status == .enabled
}
Common Mistakes & Fixes
| Mistake | Fix |
|---|---|
| "App is damaged" error | Notarize and staple before distribution |
| App Store rejection for entitlements | Justify each entitlement in review notes |
currentEntitlement(for:) deprecated |
Use currentEntitlements(for:) (plural) |
| Missing privacy manifest | Add PrivacyInfo.xcprivacy to app target |
| StoreKit products not loading in dev | Set StoreKit Configuration in scheme options |
References
More from makgunay/claude-swift-skills
macos-app-structure
macOS application architecture patterns covering App protocol (@main), Scene types (WindowGroup, Window, Settings, MenuBarExtra), multi-window management, NSApplicationDelegateAdaptor for AppKit lifecycle hooks, Info.plist configuration (LSUIElement for menu bar apps, NSAccessibilityUsageDescription), entitlements for sandbox/hardened runtime, and project structure conventions. Use when scaffolding a new macOS app, configuring scenes and windows, setting up menu bar apps, or resolving macOS-specific lifecycle issues. Corrects the common LLM mistake of generating iOS-only app structures.
31appkit-bridge
Bridging AppKit components into SwiftUI macOS apps. Covers NSViewRepresentable and NSViewControllerRepresentable protocols for hosting AppKit views in SwiftUI, NSHostingView/NSHostingController for hosting SwiftUI in AppKit, NSPanel for floating windows, NSWindow configuration (styleMask, level, collectionBehavior), responder chain integration, NSEvent monitoring (global and local), NSAnimationContext for AppKit animations, NSPopover, NSStatusItem for menu bar, and NSGlassEffectView for AppKit Liquid Glass. Use when SwiftUI lacks a native equivalent, building floating panels, custom window chrome, or integrating legacy AppKit components.
15swiftui-core
Core SwiftUI patterns for macOS and iOS development including navigation (NavigationSplitView, NavigationStack), state management (@State, @Binding, @Environment, @Bindable with @Observable), the new customizable toolbar system (toolbar IDs, ToolbarSpacer, DefaultToolbarItem, searchToolbarBehavior, matchedTransitionSource, sharedBackgroundVisibility), styled text editing (TextEditor with AttributedString, AttributedTextSelection, transformAttributes, textFormattingDefinition), and layout patterns. Use when building any SwiftUI view, implementing navigation, managing state, creating toolbars, or building rich text editors. Corrects common LLM errors like using deprecated NavigationView, wrong state wrappers, and outdated toolbar APIs.
14global-hotkeys
System-wide keyboard shortcut registration on macOS using NSEvent monitoring (simple, app-level) and Carbon EventHotKey API (reliable, system-wide). Covers NSEvent.addGlobalMonitorForEvents and addLocalMonitorForEvents, CGEvent tap for keystroke simulation, Carbon RegisterEventHotKey for system-wide hotkeys, modifier flag handling (.deviceIndependentFlagsMask), common key code mappings, debouncing, Accessibility permission requirements (AXIsProcessTrusted), and SwiftUI .onKeyPress for in-app shortcuts. Use when implementing global keyboard shortcuts, hotkey-triggered panels, or system-wide key event monitoring.
11swiftui-webkit
Native SwiftUI WebKit integration with the new WebView struct and WebPage observable class. Covers WebView creation from URLs, WebPage for navigation control and state management, JavaScript execution (callJavaScript with arguments and content worlds), custom URL scheme handlers, navigation management (load, reload, back/forward), navigation decisions, text search (findNavigator), content capture (snapshots, PDF generation, web archives), and configuration (data stores, user agents, JS permissions). Use when embedding web content in SwiftUI apps instead of the old WKWebView + UIViewRepresentable/NSViewRepresentable bridge pattern. This is a brand new API — do NOT use the old WKWebView wrapping approach.
10tech-stack-validator
Validates and recommends technology stacks for native macOS/iOS app projects against PRD and architecture requirements. Reads the PRD and architecture documents (or gathers requirements interactively), then systematically checks every technology choice for: OS version availability, framework capability gaps, performance feasibility, distribution compatibility (sandbox vs direct), API deprecation risks, dependency conflicts, and timeline realism for the team size. Produces a structured validation report with go/no-go verdicts, risk flags, and alternative recommendations. Use when user says things like 'validate my tech stack', 'check if this architecture works', 'what should I build this with', 'is SwiftData the right choice', 'can I ship this on the App Store', 'review my architecture', or before starting implementation of any PRD. Also use when migrating between tech stacks or evaluating whether to adopt a new framework.
9