Appleの技術ノート TN3181「無効なプライバシーマニフェストのデバッグ」 は、PrivacyInfo.xcprivacyの無効状態をApp Store Connectの提出エラーとして扱っています。したがって、App Store Connect プライバシーマニフェストが無効になったときは、主アプリへ通用する清書を追加したり、依存ファイルを盲目的に削除したりしないでください。通知のBundleパスを入口に、提出した最終xcarchiveの責任Targetを特定し、形式、値、Required Reason API、SDK、配置を個別に検証します。
これは、ITMS-91056または同種のプライバシーマニフェストエラーを受け、TestFlightやApp Store提出を復旧したい独立開発者向けです。Swift Package Manager、CocoaPods、XCFrameworkを使っていて、ソースは正常なのに公開用Archiveだけ拒否される小規模チームにも適しています。
01 最初に通知の経路と成果物を固定する
通知メールやApp Store Connectのエラー画面から、次の情報をそのまま作業記録へ移します。
- エラーコード
- PrivacyInfo.xcprivacyのファイル名
- 責任Bundleの名前
- Bundle内の相対パス
- 無効、欠落、Required Reason API、SDK署名のどれに分類されているか
Appleの第三者SDK要件では、対象SDKについてプライバシーマニフェストだけでなく、署名などの条件も確認対象になります。公式の第三者SDK要件と通知のパスが一致しているかを確認してください。
確認対象はプロジェクトフォルダーではありません。提出に使った.xcarchiveです。ソースにファイルが存在していても、Targetから外れていれば最終Bundleに入りません。
02 形式の検査とApp Store Connectの意味検査を分ける
Xcodeのプロパティリスト編集画面では、ルートが辞書であるか、配列と辞書の階層が崩れていないかを確認します。Booleanとして扱う値が文字列になっていないか、空の配列や想定外のキーが残っていないかも見ます。
原本Archiveを変更せず、複製した作業用Archiveまたは展開先を使ってください。パスはプロジェクト固有の値に置き換えます。
ARCHIVE_PATH="/path/to/YourApp.xcarchive"
MANIFEST_PATH="$ARCHIVE_PATH/Products/Applications/YourApp.app/PrivacyInfo.xcprivacy"
plutil -lint "$MANIFEST_PATH"
plutil -p "$MANIFEST_PATH"
plutil -lintが成功しても、App Store Connectで受理されるとは限りません。これは構文検査です。Appleが定めるPrivacy manifestの配置と記述方法は、Privacy manifestの追加方法で確認できます。
| 確認指標 | 証拠として見る場所 | 合格の判断 | 次の対応 |
|---|---|---|---|
| 通知経路 | App Store Connectのエラー | Bundleパスが記録されている | Archive内の同じ経路へ移動 |
| plist形式 | plutilの結果、Xcodeエディター |
構文と型に異常がない | 意味検査へ進む |
| API理由 | PrivacyInfo.xcprivacyと実コード、依存コード | 実際の使用とapproved reasonが一致 | 不一致ならコードまたは宣言を修正 |
| SDK責任 | 依存定義、Framework、XCFramework | 提供元のマニフェストと署名を確認できる | 更新、交換、または提供元へ確認 |
| Bundle配置 | Archive内の各Bundle | 対象Targetの成果物に収録されている | Target設定やリソース宣言を修正 |
| 提出結果 | XcodeのArchive、アップロード、処理結果 | App Store Connectの処理完了まで確認できる | 失敗箇所だけを再調査 |
03 Required Reason APIは実際の使用箇所から照合する
Required Reason APIの宣言は、通過しそうな理由を選ぶ作業ではありません。アプリのコード、依存ライブラリー、ビルド時に生成されるプライバシーレポートを突き合わせ、実際のAPI利用に対応するapproved reasonを選びます。
AppleのRequired Reason APIの記述方法とTN3183の設定手順を基準にしてください。機能と無関係な理由を追加して拒否を回避する方法は、正しい修正ではありません。
コード検索では、該当APIの呼び出し元を確認します。自分のコードに見つからない場合は、依存一覧とFramework内部の実装を調べます。主アプリのマニフェストで、第三者SDK自身のAPI使用を代替できるとは限りません。
04 依存方式ごとに更新か提供元確認かを決める
第三者SDKの問題では、最初に「誰がPrivacyInfo.xcprivacyを提供すべきか」を確定します。依存方式だけで責任を決めず、最終Bundleに入ったファイルと署名を確認してください。
| 依存方式 | 先に確認する証拠 | 基本方針 | 避ける対応 |
|---|---|---|---|
| Swift Package Manager | Package解決情報、Resources宣言、生成Bundle | 有効なマニフェストを含む版へ更新 | ソースだけ直して解決済み版を固定しない |
| CocoaPods | Podのバージョン、コピー処理、Framework | Pod更新後にArchiveへ収録されるか確認 | Pods配下だけを編集して再利用する |
| 動的Framework | Framework内部のマニフェストと署名 | 提供元の修正版へ置き換える | 署名済みFrameworkを無確認で改変する |
| XCFramework | 各slice、Bundle、署名状態 | 正しいsliceの修正版を取得する | 一つのsliceだけ直して配布する |
緊急時にArchive内部を編集する場合、コード署名が無効になる可能性があります。編集後は、対象Bundleだけでなくネストしたコードを含めた署名状態を確認し、必要な証明書とProvisioning Profileで再署名してください。これは恒久策ではなく、依存元を更新できるまでの限定対応です。
注意:署名済みArchive内のファイルを削除、追加、変更しても、元の署名が保たれるとは限りません。編集前のArchiveを保存し、変更版は別名で管理してください。
05 TargetとBundleの位置をArchiveで照合する
複数Targetがある場合、主アプリの清書だけを確認してはいけません。Extension、Framework、App Clip、Mac Catalyst、macOS Bundleは、それぞれ異なる成果物として扱います。
よくある原因は次のとおりです。
- PrivacyInfo.xcprivacyを作成したが、対象TargetのTarget Membershipが外れている
- Swift Packageでリソース宣言がなく、ビルド時にBundleへコピーされない
- ビルドスクリプトが誤ったディレクトリーへファイルを配置している
- ソース側のマニフェストは正しいが、古いSDKのファイルがArchiveへ残っている
- Extensionのエラーを主アプリのマニフェストで解決しようとしている
Xcodeのプライバシーレポートは、Appleのプライバシーレポート説明に沿って確認します。ただし、レポートだけでなくArchiveのディレクトリー構造も見てください。両者が一致しない場合は、ビルド入口、依存解決、リソースコピーのどこかに差があります。
06 条件分岐で修正方針を決める
次の条件で進めると、主アプリへの不要な追記を減らせます。
- 通知のBundleパスとArchive内のファイルが一致するなら、そのBundleの形式と値を先に修正します。一致しないなら、古いArchiveを提出していないか、Bundle名を取り違えていないかを確認します。
plutilが失敗するなら、構文、型、階層を修正します。成功するなら、Required Reason API、許可値、配置、SDK署名へ進みます。- API使用箇所が自分のコードにあるなら、機能に合うapproved reasonを選びます。依存コードにあるなら、SDKのマニフェストとバージョンを調べます。
- SDKが正式な修正版を提供しているなら更新します。提供されていないなら、別の実装へ交換するか、提供元へ問い合わせます。Archiveの直接編集は最後の一時策です。
- 複数Targetが独自コードまたは依存SDKを含むなら、各Bundleを個別に確認します。単一の主アプリ用ファイルだけで済ませないでください。
- 修正後のローカル検査だけが成功したなら、まだ提出完了とは扱いません。新規Archive、署名、アップロード受付、App Store Connectの処理完了まで進めます。
07 FAQ:提出前に詰まりやすい判断
ITMS-91056の調査開始点
ITMS-91056は、通知に示されたファイル名とBundleパスを最初の証拠にします。エラーの分類が「無効」なのか「欠落」なのかで、修正対象も異なります。ログを省略して主アプリへ同じファイルを追加する方法は、責任Bundleを外す危険があります。
Archive内の正しい場所
xcarchiveのProducts配下には、主アプリだけでなくExtensionやFrameworkなどのBundleが入ることがあります。通知のパスをArchive内で検索し、最終的に署名されるBundleの内部へPrivacyInfo.xcprivacyが収録されているかを確認します。
SDKファイルの直接修正
第三者SDKのファイルを直接書き換えると、次回の依存インストールで消えるだけでなく、署名にも影響します。まず修正版の公開バージョン、パッケージロック、提供元の対応状況を確認し、緊急修正を行う場合も再署名と交換計画を記録します。
構文検査と提出検査の違い
plistの構文が通ることは、必要なキーやapproved reasonが正しいことを意味しません。App Store Connectは、値の意味、Bundle内の位置、SDK要件、署名状態を別に確認します。したがって、plutilの結果だけで再提出しないでください。
複数Targetの扱い
主アプリ、Extension、Framework、App Clip、Mac Catalyst、macOS Bundleは、含まれるコードと依存関係が異なります。各Bundleに必要なマニフェストが収録されているかをArchiveで確認し、Xcodeのプライバシーレポートと突き合わせます。
08 新規Archiveからアップロード結果まで記録する
修正後は、古いArchiveを再利用せず、新しいコミットからArchiveを作成します。依存のロックファイル、Xcode 26のビルドログ、プライバシーレポート、Archiveの検査結果を同じ作業記録に残してください。
最後の確認は次の順番です。
- 新しいArchiveの作成が成功している
- 通知に示された責任Bundleへ修正版が入っている
- Required Reason APIの宣言が実際の使用と一致している
- SDKのマニフェストと署名に問題がない
- 変更後のBundleが正しく再署名されている
- Xcodeからアップロードが受け付けられている
- App Store Connect側の処理が完了している
Xcodeの配布手順は、Appのベータ配布とリリースに関する公式文書でも確認できます。ローカル検査、Archive完成、署名有効、アップロード受付、バックエンド処理完了は、別々の状態として記録してください。
自宅のMacだけで修正と再提出を繰り返す方法は、依存キャッシュ、古いArchive、Xcode設定の差を見落としやすい点が弱点です。さらに、常時稼働する端末を自分で保守し、ビルドログや署名環境を保存する負担も残ります。CALMVPSのMacレンタル料金と利用条件を確認し、Archive、依存ロックファイル、ログを保持できる環境でクリーンビルドを再現する方法は、短期の復旧やCIの再検証に向いています。
ただし、長期間にわたり高負荷のビルドを固定運用する場合や、物理デバイス、専用周辺機器への直接接続が必要な場合は、自前のMacのほうが適しています。必要な期間だけ別環境で再現性を確かめたいなら、CALMVPSのMac利用申し込みを検討し、提出証拠を残せる運用にしてください。