Shipping
swift run and Cmd-R in Xcode are for building and testing. Shipping a real
.app means bundle identity, persistence, entitlements, and signing. Most of
it is small and one-time.
Bundle identity
Section titled “Bundle identity”Rename the product in three places:
Package.swift: the.executable(name:)and.library(name:)products.project.yml:name:,targets:, andPRODUCT_BUNDLE_IDENTIFIER.App/Info.plist:CFBundleIdentifierandCFBundleName.
Pick a reverse-DNS bundle id before you ship. NookModuleContext.makeDefault
uses it to name on-disk containers and per-module UserDefaults suites.
See Your first nook for the quick rename pointers at the end of the getting-started flow.
Persistence
Section titled “Persistence”NookKit stores framework preferences in UserDefaults.standard under the
opennook.* prefix:
opennook.appearance.v1opennook.display.v1opennook.hotkey.v1opennook.module.default
NookComponents file shelf data lives under nook.shelf.items.
If you use NookHostConfiguration, each module gets its own UserDefaults
suite through NookModuleContext. Keep your host product keys separate from
opennook.* and nook.shelf.* so nothing collides.
Entitlements
Section titled “Entitlements”A copy-paste template lives at App/Nook.entitlements.
It includes the minimum for App Sandbox plus the features OpenNook expects:
com.apple.security.app-sandboxcom.apple.security.files.user-selected.read-write(shelf drag-in and the file picker)com.apple.security.files.bookmarks.app-scope(scoped-bookmark persistence)
The demo does not wire this file in by default, so swift run stays
unsandboxed. To sandbox your app, set
CODE_SIGN_ENTITLEMENTS: App/Nook.entitlements on the NookHostApp target in
project.yml, regenerate the Xcode project, and rebuild.
The global hotkey is Carbon and needs no entitlement. CoreAudio output
listening for the volume glyph is read-only and needs no entitlement. The shelf
detects the sandbox at runtime (ShelfRuntime.isSandboxed) and switches to a
stricter acceptance mode when sandboxed.
File pickers
Section titled “File pickers”Modules open and save files through the host’s NookFilePicker, resolved from
\.appServices via NookFilePickerKey. It activates the app so the panel
works from the non-activating notch panel and keeps the surface open while the
panel is up.
Two things to know:
- Sandbox.
files.user-selected.read-writeis what makes a user-picked file readable inside the sandbox. Ship the entitlement above. - Dev loop. Under
swift runthe binary is unbundled and unsandboxed with no powerbox, so the panel cannot reach TCC-protected folders (Downloads, Desktop, Documents). Run the signed.appfrom theNookHostApptarget, or grant your terminal Full Disk Access. That limitation is dev-only, not a shipping constraint.
Menu bar only
Section titled “Menu bar only”Set LSUIElement = true in Info.plist if you want menu-bar accessory
behavior with no Dock icon, matching the demo.
Sign and notarize
Section titled “Sign and notarize”For distribution outside the Mac App Store, sign with a Developer ID, enable hardened runtime, and notarize. None of OpenNook’s APIs require runtime exceptions.
Regenerate the Xcode project after editing project.yml:
./Scripts/regenerate-xcodeproj.shopen Nook.xcodeprojSee also
Section titled “See also”- File shelf: sandbox behavior and relaunch pitfalls.
- Multiple modules: per-module persistence and host branding.
- Troubleshooting: symptom-first fixes when something looks wrong after you ship.