跳到主要内容
知仓学习社ZHICANG

developing-ios-apps

Develops iOS/macOS apps with XcodeGen, SwiftUI, and SPM, including Apple Developer signing, notarization, and CI/CD pipelines. Use when building iOS…

写文件严重 0 · 高危 2daymade/claude-code-skills

它会碰到什么

扫了多少6 个文本文件,45 KB
它会碰到什么写文件
命中总数6 处
命中统计严重 0 · 高 2 · 中 0 · 低 0
逐条看命中(2 条严重或高危)
  • SKILL.md:29fs-destructive
    | Clean DerivedData | `rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-*` |
  • SKILL.md:158fs-destructive
    | DerivedData won't delete | Close Xcode first: `pkill -9 Xcode && rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-*` |

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

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](#spm-dynamic-framework-not-embedded) |

| 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](#camera--avfoundation) |

| App signed as adhoc despite certificate | @electron/packager defaults continueOnError: true | Set continueOnError: false in osxSign. See [Code Signing](#macos-code-signing--notarization) |

| "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](#macos-code-signing--notarization) |

| 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](#macos-code-signing--notarization) |

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

  1. Update project.yml:
deploymentTarget:
  iOS: "16.0"
  1. 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
  1. Regenerate: xcodegen generate

Device Deployment

First-time Setup

  1. Connect device via USB
  2. Trust computer on device
  3. In Xcode: Settings → Accounts → Add Apple ID
  4. Select device in scheme dropdown
  5. Run (Cmd + R)
  6. 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):

  1. Open project in Xcode GUI
  2. Select target → General → Frameworks, Libraries
  3. Find the dynamic framework (RealmSwift)
  4. Change "Do Not Embed" → "Embed & Sign"
  5. 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

  1. Permission: Added NSCameraUsageDescription to Info.plist?
  2. Device: Running on real device, not simulator?
  3. Session running: session.startRunning() called on background thread?
  4. View size: UIViewRepresentable has non-zero bounds?
  5. 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](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:

  1. @electron/osx-sign: continueOnError: false — signing error throws immediately
  2. postPackage hook: codesign --verify --deep --strict + adhoc detection
  3. 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](references/apple-codesign-notarize.md)


Resources

  • [references/xcodegen-full.md](references/xcodegen-full.md) - Complete project.yml options
  • [references/swiftui-compatibility.md](references/swiftui-compatibility.md) - iOS version API differences
  • [references/camera-avfoundation.md](references/camera-avfoundation.md) - Camera preview debugging
  • [references/testing-mainactor.md](references/testing-mainactor.md) - Testing @MainActor classes (state machines, regression tests)
  • [references/apple-codesign-notarize.md](references/apple-codesign-notarize.md) - Apple Developer signing + notarization for macOS/Electron CI/CD

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。