developing-ios-apps について
developing-ios-appsは、XcodeGenとSwift Package Managerを使ったiOSアプリの開発、設定、デプロイを案内するスキルです。プロジェクト設定、バージョン互換性、実機ビルド、カメラ実装、Apple署名の問題に関するトラブルシューティングを扱います。
主な機能
- 01XcodeGenによるプロジェクト生成
- 02Swift Package Manager依存関係の管理
- 03iOS API互換性への対応
- 04実機へのビルドとデプロイ
- 05カメラと署名の問題の調査
活用シーン
- 01iOSプロジェクトと依存関係の設定
- 02フレームワーク埋め込みや署名の失敗解決
- 03実機でのカメラプレビュー確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ daymade/ claude-code-skills --skill developing-ios-appsインストール後、Claude Code で/developing-ios-appsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/apple-codesign-notarize.mdcamera-avfoundation.mdswiftui-compatibility.mdtesting-mainactor.mdxcodegen-full.md詳細
iOS アプリ開発
XcodeGen と Swift Package Manager を使用して、iOS アプリケーションをビルド、設定、デプロイします。
重要な警告
| 問題 | 原因 | 解決策 |
|---|---|---|
| 「Library not loaded: @rpath/Framework」 | XcodeGen は SPM の動的フレームワークを自動で埋め込みません | まず Xcode GUI でビルドしてください(xcodebuild ではありません)。トラブルシューティングを参照してください |
xcodegen generate を実行すると署名設定が失われる | プロジェクト設定が上書きされる | グローバル設定ではなく、project.yml のターゲット設定で構成してください |
| コマンドラインでの署名に失敗する | 無料の Apple ID の制限 | Xcode GUI または有料の開発者アカウント(年額 99 ドル)を使用してください |
| 「Cannot be set when automaticallyAdjustsVideoMirroring is YES」 | 自動調整を無効にせず isVideoMirrored を設定している | 先に automaticallyAdjustsVideoMirroring = false を設定してください。カメラを参照してください |
| 証明書があるのにアプリが adhoc 署名される | @electron/packager の continueOnError: true がデフォルト | osxSign で continueOnError: false を設定してください。コード署名を参照してください |
| 「Cannot use password credentials, API key credentials...」 | API キー認証で @electron/notarize に teamId を渡している | teamId を削除してください。notarytool が API キーからチームを推測します。コード署名を参照してください |
| 署名中に EMFILE が発生する(埋め込みランタイムが大きい場合) | @electron/osx-sign が .app バンドル内のすべてのファイルを走査する | CI で ignore フィルターと ulimit -n 65536 を追加してください。コード署名を参照してください |
クイックリファレンス
| タスク | コマンド |
|---|---|
| プロジェクトを生成 | xcodegen generate |
| シミュレーター向けにビルド | xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17' build |
| デバイス向けにビルド(有料アカウント) | xcodebuild -destination 'platform=iOS,name=DEVICE' -allowProvisioningUpdates build |
| DerivedData をクリーンアップ | rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-* |
| デバイス名を確認 | xcrun xctrace list devices |
XcodeGen の設定
最小限の 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
コード署名の設定
個人(無料)アカウント:Xcode GUI でのみ動作します。コマンドラインでのビルドには有料アカウントが必要です。
# In target settings
settings:
base:
CODE_SIGN_STYLE: Automatic
DEVELOPMENT_TEAM: TEAM_ID # Get from Xcode → Settings → Accounts
Team ID の確認:
security find-identity -v -p codesigning | head -3
iOS バージョンの互換性
バージョンごとの API の変更
| iOS 17 以降のみ | iOS 16 互換 |
|---|---|
.onChange { old, new in } | .onChange { new in } |
ContentUnavailableView | カスタム VStack |
AVAudioApplication | AVAudioSession |
@Observable マクロ | @ObservableObject |
| SwiftData | CoreData/Realm |
デプロイメントターゲットを下げる
project.ymlを更新します:
deploymentTarget:
iOS: "16.0"
- 互換性のない API を修正します:
// 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
- 再生成します:
xcodegen generate
デバイスへのデプロイ
初回セットアップ
- USB でデバイスを接続します
- デバイスでコンピューターを信頼します
- Xcode で「Settings → Accounts → Add Apple ID」を選択します
- スキームのドロップダウンでデバイスを選択します
- 実行します(
Cmd + R) - デバイスで「Settings → General → VPN & Device Management → Trust」を選択します
コマンドラインでのビルド(有料アカウントが必要)
xcodebuild \
-project App.xcodeproj \
-scheme App \
-destination 'platform=iOS,name=DeviceName' \
-allowProvisioningUpdates \
build
よくある問題
| エラー | 解決策 |
|---|---|
| 「Library not loaded: @rpath/Framework」 | SPM の動的フレームワークが埋め込まれていません。まず Xcode GUI でビルドすると、その後は CLI でも動作します |
| 「No Account for Team」 | Xcode の「Settings → Accounts」で Apple ID を追加します |
| 「Provisioning profile not found」 | 無料アカウントの制限です。Xcode GUI を使用するか、有料アカウントを取得してください |
| デバイスが一覧に表示されない | USB を再接続し、デバイスでコンピューターを信頼してから、Xcode を再起動します |
| DerivedData を削除できない | 先に Xcode を終了します:pkill -9 Xcode && rm -rf ~/Library/Developer/Xcode/DerivedData/PROJECT-* |
無料と有料の開発者アカウント
| 機能 | 無料の Apple ID | 有料(年額 99 ドル) |
|---|---|---|
| Xcode GUI でのビルド | ✅ | ✅ |
| コマンドラインでのビルド | ❌ | ✅ |
| アプリの有効期間 | 7 日間 | 1 年間 |
| App Store | ❌ | ✅ |
| CI/CD | ❌ | ✅ |
SPM の依存関係
SPM Dynamic Framework Not Embedded
根本原因:XcodeGen は、SPM の動的フレームワーク(RealmSwift、Realm など)の「Embed Frameworks」ビルドフェーズを生成しません。アプリは正常にビルドされますが、起動時に次のエラーでクラッシュします:
dyld: Library not loaded: @rpath/RealmSwift.framework/RealmSwift
Referenced from: /var/containers/Bundle/Application/.../App.app/App
Reason: image not found
発生する理由:
- 静的フレームワーク(ほとんどの SPM パッケージ)はバイナリにリンクされるため、埋め込みは不要です
- 動的フレームワーク(RealmSwift など)はアプリバンドルにコピーする必要があります
- XcodeGen は、SPM パッケージのリンクフェーズは生成しますが、埋め込みフェーズは生成しません
embed: trueを project.yml に指定すると、ビルドエラーになります(XcodeGen の制限)
修正方法(プロジェクトごとに手動で一度だけ実施):
- Xcode GUI でプロジェクトを開きます
- ターゲットを選択 → General → Frameworks, Libraries
- 動的フレームワーク(RealmSwift)を探します
- 「Do Not Embed」から「Embed & Sign」に変更します
- まず Xcode GUI からビルドして実行します
手動修正後:Xcode が project.pbxproj に埋め込み設定を保存するため、コマンドラインからのビルド(xcodebuild)も動作します。
動的フレームワークの識別方法:
# 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"
パッケージの追加
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
依存関係の解決(中国向けプロキシ)
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
グローバル SPM キャッシュ(~/Library/Caches/org.swift.swiftpm)は絶対に削除しないでください。再ダウンロードには時間がかかります。
カメラ / AVFoundation
カメラプレビューには実機が必要です(シミュレーターにはカメラがありません)。
すぐに確認できるデバッグ項目
- 権限:Info.plist に
NSCameraUsageDescriptionを追加しましたか? - デバイス:シミュレーターではなく、実機で実行していますか?
- セッションの実行:
session.startRunning()はバックグラウンドスレッドで呼び出されていますか? - ビューサイズ:UIViewRepresentable の境界にゼロ以外の値がありますか?
- ビデオのミラーリング:
isVideoMirroredを設定する前にautomaticallyAdjustsVideoMirroringを無効にしましたか?
ビデオのミラーリング(フロントカメラ)
重要:手動でミラーリングを設定する前に、自動調整を無効にする必要があります:
// WRONG - crashes with "Cannot be set when automaticallyAdjustsVideoMirroring is YES"
connection.isVideoMirrored = true
// CORRECT - disable automatic first
connection.automaticallyAdjustsVideoMirroring = false
connection.isVideoMirrored = true
UIViewRepresentable のサイズに関する問題
ZStack 内の UIViewRepresentable の境界がゼロになる場合があります。明示的なフレームを指定して修正します:
// 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()
}
デバッグログのパターン
カメラの処理を追跡するためにログを追加します:
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))")
Console.app でサブシステムを指定して絞り込みます。
カメラの実装について詳しくは:references/camera-avfoundation.md を参照してください。
macOS のコード署名と公証
App Store 以外で macOS アプリ(Electron またはネイティブ)を配布するには、署名と公証が必要です。これらを行わないと、ユーザーには「Apple はこのアプリに悪意のあるソフトウェアが含まれていないことを確認できません」と表示されます。
5 ステップのチェックリスト:
| 手順 | 内容 | 重要な詳細 |
|---|---|---|
| 1 | Keychain Access で CSR を作成する | 通称は何でも構いません。「Saved to disk」を選択します |
| 2 | developer.apple.com で Developer ID Application 証明書を申請する | G2 Sub-CA を選択します(Previous Sub-CA ではありません) |
| 3 | .cer をインストールする → login キーチェーンを選択する必要があります | iCloud/System を選ぶとエラー -25294(秘密鍵の不一致)が発生します |
| 4 | login キーチェーンからパスワード付きの P12 を書き出す | Base64:base64 -i cert.p12 | pbcopy |
| 5 | App Store Connect API キーを作成する(Developer ロール) | .p8 は一度しかダウンロードできません。Key ID と Issuer ID を記録してください |
必要な GitHub Secrets(5 つ):
| Secret | 入手元 |
|---|---|
MACOS_CERT_P12 | 手順 4 の Base64 |
MACOS_CERT_PASSWORD | 手順 4 のパスワード |
APPLE_API_KEY | 手順 5 の .p8 の Base64 |
APPLE_API_KEY_ID | 手順 5 の Key ID |
APPLE_API_ISSUER | 手順 5 の Issuer ID |
APPLE_TEAM_IDは不要です。notarytoolは API キーからチームを推定します。@electron/notarizev2.5.0 にteamIdを渡すと、認証情報の競合エラーが発生します。
Electron Forge の osxSign に関する重要な設定:
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 }
: {}),
},
失敗を即座に検出する 3 層の防御:
@electron/osx-sign:continueOnError: false— 署名エラーが直ちにスローされますpostPackageフック:codesign --verify --deep --strictとアドホック署名の検出- リリーストリガースクリプト:ディスパッチ前にローカル HEAD がリモートと一致することを確認します
署名を確認する:
security find-identity -v -p codesigning | grep "Developer ID Application"
手順の詳細、エンタイトルメント、ワークフローの例、およびトラブルシューティング全体(実際に発生した 7 件のエラーと根本原因)については、references/apple-codesign-notarize.md を参照してください。
リソース
- references/xcodegen-full.md -
project.ymlのオプションの詳細 - references/swiftui-compatibility.md - iOS バージョン間の API の違い
- references/camera-avfoundation.md - カメラプレビューのデバッグ
- references/testing-mainactor.md -
@MainActorクラスのテスト(状態機械、回帰テスト) - references/apple-codesign-notarize.md - macOS/Electron の CI/CD における Apple Developer 署名と公証