なぜ今これが必要か

Apple は 2024 年以降、アプリに Privacy Manifest(PrivacyInfo.xcprivacyの同梱と、一部 API の使用理由の宣言を審査時の必須条件に組み込んだ。

個人開発者にとっては、「UIKit の一部メソッドを呼んだだけで警告が出る」「第三者 SDK のせいで審査が通らない」という、それまで気にしなくてよかったレイヤーの問題が増えた。

この記事は、60d Memo v1.0 を App Store に通した実例をもとに、個人開発者が最低限やっておくべき対応を具体的にチェックリスト化する。

対象読者: iOS 17+ を最低サポートとする個人開発者。SwiftUI + SwiftData + 数個の SPM 依存、くらいのシンプルな構成を想定。

Privacy Manifest とは何か

PrivacyInfo.xcprivacy は、アプリがどんなデータにアクセスし、何のために使うかを機械可読な形で宣言する plist ファイルだ。

主に次の 4 項目を宣言する:

キー内容60d Memo の例
NSPrivacyTrackingトラッキングを行うかfalse
NSPrivacyTrackingDomainsトラッキングに使うドメイン空配列
NSPrivacyCollectedDataTypes収集するデータの種類空配列(自前サーバーに何も送らない)
NSPrivacyAccessedAPITypesRequired Reason API の使用理由後述(UserDefaults など)

Required Reason API とは

「使った場合に理由宣言が必須になる」と Apple が指定した API 群。プライバシー上のリスクがある(フィンガープリンティングに使われうる)API が対象。

典型的な対象 API

公式リスト: Describing use of required reason API

注意: 宣言漏れがあると App Store 審査で警告が出る。自分のコードに加え、依存している SPM ライブラリ内での使用も対象になりうる。

60d Memo v1.0 の実例

最小構成の PrivacyInfo.xcprivacy

60d Memo は:

この構成で必要だった宣言は次のとおり:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSPrivacyTracking</key>
    <false/>
    <key>NSPrivacyTrackingDomains</key>
    <array/>
    <key>NSPrivacyCollectedDataTypes</key>
    <array/>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

これだけで v1.0 は審査を通過した。重要なのは自分のアプリ本当の挙動と宣言が一致していること。実際にやっていない行為(データ収集、トラッキング)を false で宣言するだけ。

配置場所

アプリのメインターゲット直下に PrivacyInfo.xcprivacy を置き、Xcode プロジェクトに追加する(Copy Bundle Resources に含まれるはず)。

第三者 SDK の確認

SDK 側も Privacy Manifest を同梱している必要がある。Apple が指定する**「commonly used SDK」リスト**に入っているものは特に注意。

60d Memo では

唯一の SPM 依存が GoogleSignIn-iOS。これは Google 公式が Privacy Manifest を同梱済みで、特に追加作業は不要だった。

確認方法

  1. 依存 SDK のリポジトリで PrivacyInfo.xcprivacy を検索
  2. 見つからなければ、SDK のリリースノート / CHANGELOG で対応バージョンを確認
  3. 古いバージョンを使っているなら、Privacy Manifest 同梱版にアップデート

注意: SDK を束ねた xcframework / バイナリ配布を使っている場合、その中に Privacy Manifest が入っているかは自分では変えられない。提供元の更新を待つしかない。

ログのプライバシー(OSLogprivacy: パラメータ)

Privacy Manifest と直接の関係はないが、実装上は一緒に対応すべき。print() ではなく Loggerimport os)を使い、機微情報には privacy: を明示する。

import os
private let logger = Logger(subsystem: "dev.60d.memo", category: "sync")

// 機微情報: .private で Release ビルドではマスクされる
logger.info("Signed in as \(email, privacy: .private)")

// メタデータ(ID、ステータスコード等)は .public で OK
logger.debug("Syncing memo \(memoId, privacy: .public)")

// Release で確実に出したくないならビルド時に除外
#if DEBUG
logger.debug("Response body: \(bodyString, privacy: .public)")
#endif

重要なのは、指定省略時のデフォルトは .public ということ。うっかりメールアドレスやトークンが本番ログに出続けないよう、機微情報には必ず privacy: を書く。

ログに絶対出さないもの

チェックリスト

初回リリース前に

新しい API を使ったとき

新しい SDK を追加するとき

トラブルシューティング

「Missing API declaration」の警告

App Store Connect のアップロード後、メールで「ITMS-91053」のような警告が来る。該当する API カテゴリを PrivacyInfo.xcprivacy に追加する。

自分は使っていないのに警告が出る

多くの場合、依存 SDK 内の使用が原因。SDK を新しいバージョンにアップデートするか、SDK のドキュメントで推奨される対応を確認する。

審査で差し戻された

実態と宣言が食い違っているケースが多い。特に:

レビューアからのコメントを文字通り読んで、自分の実装と照らし合わせる。

個人開発で「最小で通す」戦略

Privacy Manifest の網羅は大変なので、個人開発ではシンプルな設計自体が最強の審査対策になる。

  1. 第三者 SDK を最小限に — Apple 標準フレームワークだけなら宣言もシンプル
  2. トラッキング・広告 SDK は入れない — 宣言漏れのリスクが消える
  3. ユーザーデータを自前サーバーに送らないNSPrivacyCollectedDataTypes が空でよい

60d Memo は「データの所有権をユーザーに返す」というコンセプトで設計したため、結果的に Privacy Manifest の宣言が最小で済んだ。プライバシー重視の設計は、ユーザーのためだけでなく開発者自身の工数削減にもつながる。

まとめ

Privacy Manifest は面倒に見えて、次のステップで整理できる:

  1. 自分のアプリの実態(トラッキング・データ収集)を素直に宣言
  2. 使っている Required Reason API を洗い出して理由を記載
  3. 依存 SDK が対応バージョンか確認
  4. ログ出力の機微情報を privacy: パラメータで保護

複雑に見えるが、シンプルなアプリほど宣言は軽い。「複雑なデータ処理をしない」設計そのものが最も確実な対策だ。

最後に、発見した制約や API はプロジェクトのルールファイルに蓄積することを勧める。次のアプリ、次のリリースで同じ調査を繰り返さなくて済む。これについては別の記事で詳しく書いた。

参考リンク