iOS App Development
Build, configure, and deploy iOS applications using XcodeGen and Swift Package Manager.
Critical Warnings
Issue Cause Solution
"Library not loaded: @rpath/Framework" XcodeGen doesn't auto-embed SPM dynamic frameworks Build in Xcode GUI first (not xcodebuild). See Troubleshooting
xcodegen generate loses signing Overwrites project settings Configure in project.yml target settings, not global
Command-line signing fails Free Apple ID limitation Use Xcode GUI or paid developer account ($99/yr)
"Cannot be set when automaticallyAdjustsVideoMirroring is YES" Setting isVideoMirrored without disabling automatic Set automaticallyAdjustsVideoMirroring = false first. See Camera
App signed as adhoc despite certificate @electron/packager defaults continueOnError: true
Set continueOnError: false in osxSign. See Code Signing
"Cannot use password credentials, API key credentials..." Passing teamId to @electron/notarize with API key auth Remove teamId . notarytool infers team from API key. See Code Signing
EMFILE during signing (large embedded runtime) @electron/osx-sign traverses all files in .app bundle Add ignore filter + ulimit -n 65536 in CI. See Code Signing
Quick Reference
Task Command
Generate project xcodegen generate
Build simulator xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17' build
Build device (paid account) xcodebuild -destination 'platform=iOS,name=DEVICE' -allowProvisioningUpdates build
Clean DerivedData rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-*
Find device name xcrun xctrace list devices
XcodeGen Configuration
Minimal project.yml
name: AppName options: bundleIdPrefix: com.company deploymentTarget: iOS: "16.0"
settings: base: SWIFT_VERSION: "6.0"
packages: SomePackage: url: https://github.com/org/repo from: "1.0.0"
targets: AppName: type: application platform: iOS sources: - path: AppName settings: base: INFOPLIST_FILE: AppName/Info.plist PRODUCT_BUNDLE_IDENTIFIER: com.company.appname CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: TEAM_ID_HERE dependencies: - package: SomePackage
Code Signing Configuration
Personal (free) account: Works in Xcode GUI only. Command-line builds require paid account.
In target settings
settings: base: CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: TEAM_ID # Get from Xcode → Settings → Accounts
Get Team ID:
security find-identity -v -p codesigning | head -3
iOS Version Compatibility
API Changes by Version
iOS 17+ Only iOS 16 Compatible
.onChange { old, new in }
.onChange { new in }
ContentUnavailableView
Custom VStack
AVAudioApplication
AVAudioSession
@Observable macro @ObservableObject
SwiftData CoreData/Realm
Lowering Deployment Target
- Update project.yml :
deploymentTarget: iOS: "16.0"
- Fix incompatible APIs:
// iOS 17 .onChange(of: value) { oldValue, newValue in } // iOS 16 .onChange(of: value) { newValue in }
// iOS 17 ContentUnavailableView("Title", systemImage: "icon") // iOS 16 VStack { Image(systemName: "icon").font(.system(size: 48)) Text("Title").font(.title2.bold()) }
// iOS 17 AVAudioApplication.shared.recordPermission // iOS 16 AVAudioSession.sharedInstance().recordPermission
- Regenerate: xcodegen generate
Device Deployment
First-time Setup
-
Connect device via USB
-
Trust computer on device
-
In Xcode: Settings → Accounts → Add Apple ID
-
Select device in scheme dropdown
-
Run (Cmd + R )
-
On device: Settings → General → VPN & Device Management → Trust
Command-line Build (requires paid account)
xcodebuild
-project App.xcodeproj
-scheme App
-destination 'platform=iOS,name=DeviceName'
-allowProvisioningUpdates
build
Common Issues
Error Solution
"Library not loaded: @rpath/Framework" SPM dynamic framework not embedded. Build in Xcode GUI first, then CLI works
"No Account for Team" Add Apple ID in Xcode Settings → Accounts
"Provisioning profile not found" Free account limitation. Use Xcode GUI or get paid account
Device not listed Reconnect USB, trust computer on device, restart Xcode
DerivedData won't delete Close Xcode first: pkill -9 Xcode && rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-*
Free vs Paid Developer Account
Feature Free Apple ID Paid ($99/year)
Xcode GUI builds ✅ ✅
Command-line builds ❌ ✅
App validity 7 days 1 year
App Store ❌ ✅
CI/CD ❌ ✅
SPM Dependencies
SPM Dynamic Framework Not Embedded
Root Cause: XcodeGen doesn't generate the "Embed Frameworks" build phase for SPM dynamic frameworks (like RealmSwift, Realm). The app builds successfully but crashes on launch with:
dyld: Library not loaded: @rpath/RealmSwift.framework/RealmSwift Referenced from: /var/containers/Bundle/Application/.../App.app/App Reason: image not found
Why This Happens:
-
Static frameworks (most SPM packages) are linked into the binary - no embedding needed
-
Dynamic frameworks (RealmSwift, etc.) must be copied into the app bundle
-
XcodeGen generates link phase but NOT embed phase for SPM packages
-
embed: true in project.yml causes build errors (XcodeGen limitation)
The Fix (Manual, one-time per project):
-
Open project in Xcode GUI
-
Select target → General → Frameworks, Libraries
-
Find the dynamic framework (RealmSwift)
-
Change "Do Not Embed" → "Embed & Sign"
-
Build and run from Xcode GUI first
After Manual Fix: Command-line builds (xcodebuild ) will work because Xcode persists the embed setting in project.pbxproj.
Identifying Dynamic Frameworks:
Check if a framework is dynamic
file ~/Library/Developer/Xcode/DerivedData/PROJECT-*/Build/Products/Debug-iphoneos/FRAMEWORK.framework/FRAMEWORK
Dynamic: "Mach-O 64-bit dynamically linked shared library"
Static: "current ar archive"
Adding Packages
packages: AudioKit: url: https://github.com/AudioKit/AudioKit from: "5.6.5" RealmSwift: url: https://github.com/realm/realm-swift from: "10.54.6"
targets: App: dependencies: - package: AudioKit - package: RealmSwift product: RealmSwift # Explicit product name when package has multiple
Resolving Dependencies (China proxy)
git config --global http.proxy http://127.0.0.1:1082 git config --global https.proxy http://127.0.0.1:1082 xcodebuild -scmProvider system -resolvePackageDependencies
Never clear global SPM cache (~/Library/Caches/org.swift.swiftpm ). Re-downloading is slow.
Camera / AVFoundation
Camera preview requires real device (simulator has no camera).
Quick Debugging Checklist
-
Permission: Added NSCameraUsageDescription to Info.plist?
-
Device: Running on real device, not simulator?
-
Session running: session.startRunning() called on background thread?
-
View size: UIViewRepresentable has non-zero bounds?
-
Video mirroring: Disabled automaticallyAdjustsVideoMirroring before setting isVideoMirrored ?
Video Mirroring (Front Camera)
CRITICAL: Must disable automatic adjustment before setting manual mirroring:
// WRONG - crashes with "Cannot be set when automaticallyAdjustsVideoMirroring is YES" connection.isVideoMirrored = true
// CORRECT - disable automatic first connection.automaticallyAdjustsVideoMirroring = false connection.isVideoMirrored = true
UIViewRepresentable Sizing Issue
UIViewRepresentable in ZStack may have zero bounds. Fix with explicit frame:
// BAD: UIViewRepresentable may get zero size in ZStack ZStack { CameraPreviewView(session: session) // May be invisible! OtherContent() }
// GOOD: Explicit sizing ZStack { GeometryReader { geo in CameraPreviewView(session: session) .frame(width: geo.size.width, height: geo.size.height) } .ignoresSafeArea() OtherContent() }
Debug Logging Pattern
Add logging to trace camera flow:
import os private let logger = Logger(subsystem: "com.app", category: "Camera")
func start() async { logger.info("start() called, isRunning=(self.isRunning)") // ... setup code ... logger.info("session.startRunning() completed") }
// For CGRect (doesn't conform to CustomStringConvertible) logger.info("bounds=(NSCoder.string(for: self.bounds))")
Filter in Console.app by subsystem.
For detailed camera implementation: See references/camera-avfoundation.md
macOS Code Signing & Notarization
For distributing macOS apps (Electron or native) outside the App Store, signing + notarization is required. Without it users see "Apple cannot check this app for malicious software."
5-step checklist:
Step What Critical detail
1 Create CSR in Keychain Access Common Name doesn't matter; choose "Saved to disk"
2 Request Developer ID Application cert at developer.apple.com Choose G2 Sub-CA (not Previous Sub-CA)
3 Install .cer → must choose login keychain iCloud/System → Error -25294 (private key mismatch)
4 Export P12 from login keychain with password Base64: base64 -i cert.p12 | pbcopy
5 Create App Store Connect API Key (Developer role) Download .p8 once only; record Key ID + Issuer ID
GitHub Secrets required (5 secrets):
Secret Source
MACOS_CERT_P12
Step 4 base64
MACOS_CERT_PASSWORD
Step 4 password
APPLE_API_KEY
Step 5 .p8 base64
APPLE_API_KEY_ID
Step 5 Key ID
APPLE_API_ISSUER
Step 5 Issuer ID
APPLE_TEAM_ID is NOT needed. notarytool infers team from the API key. Passing teamId to @electron/notarize v2.5.0 causes a credential conflict error.
Electron Forge osxSign critical settings:
osxSign: { identity: 'Developer ID Application', hardenedRuntime: true, entitlements: 'entitlements.mac.plist', entitlementsInherit: 'entitlements.mac.plist', continueOnError: false, // CRITICAL: default is true, silently falls back to adhoc // Skip non-binary files in large embedded runtimes (prevents EMFILE) ignore: (filePath: string) => { if (!filePath.includes('python-runtime')) return false; if (/.(so|dylib|node)$/.test(filePath)) return false; return true; }, // CI: explicitly specify keychain (apple-actions/import-codesign-certs uses signing_temp.keychain) ...(process.env.MACOS_SIGNING_KEYCHAIN ? { keychain: process.env.MACOS_SIGNING_KEYCHAIN } : {}), },
Fail-fast three-layer defense:
-
@electron/osx-sign : continueOnError: false — signing error throws immediately
-
postPackage hook: codesign --verify --deep --strict
- adhoc detection
- Release trigger script: verify local HEAD matches remote before dispatch
Verify signing:
security find-identity -v -p codesigning | grep "Developer ID Application"
For complete step-by-step guide, entitlements, workflow examples, and full troubleshooting (7 real-world errors with root causes): references/apple-codesign-notarize.md
Resources
-
references/xcodegen-full.md - Complete project.yml options
-
references/swiftui-compatibility.md - iOS version API differences
-
references/camera-avfoundation.md - Camera preview debugging
-
references/testing-mainactor.md - Testing @MainActor classes (state machines, regression tests)
-
references/apple-codesign-notarize.md - Apple Developer signing + notarization for macOS/Electron CI/CD