プライバシーポリシーをビルドと同期させておく
プライバシーポリシーは SDK を追加するプルリクエストで古くなります。ビルドファイルだけを読む無料のチェックで、プルリクエスト上で気づく方法。
ページを書いた時点の SDK、データの種類、権限を記録し、すべてのプルリクエストのビルドファイルをその記録と比較します。記録にない依存関係や権限が現れると、リリースより前にプルリクエストがそれを示します。プライバシーポリシーとストアのフォームをまだ簡単に更新できるうちに、です。
数分で済ませる方法もあります
AppFoyer は、このガイドで扱っているページ(プライバシーポリシー、利用規約、サポート、アカウント削除、そして app-ads.txt)を、専用のサブドメインでホストします。自分のドメインもサーバーも要りません。アプリ 1 つまでは無料で、ストアが求めるものが有料プランの壁の向こうに置かれることは決してありません。
2026年9月30日 に確認。 ストアのポリシーは、予告なく変わることもあります。以下の内容はすべて公式ドキュメントにリンクしており、拠り所となるのはこのページではなくそちらです。両者が食い違う場合は、ストアが正しいものとしてください。 このガイドは英語からの翻訳です。ストアのドキュメントからの引用は原文の英語のまま掲載しています。
プライバシーポリシーを書くのは一度きりの作業です。しかし、それを正しく保つのはそうではありません。ポリシーは書いた時点のビルドを説明しており、ビルドは変わり続けます。プルリクエストがクラッシュレポート、サブスクリプションのライブラリ、位置情報の権限を追加し、アプリがリリースされても、ポリシー、Data safetyフォーム、App Privacy の詳細は古いアプリを説明したままです。
どちらのストアも、それをストアではなくあなたの問題として扱います。Google Play は、Data safety の回答は常に正確かつ完全でなければならず、アプリ内のサードパーティのライブラリや SDK が収集するデータもあなたが申告するものだとしています。Apple も App Privacy の詳細について同じことを述べ、さらに、アップデートを申請しなくても App Store Connect でいつでも回答を変更できるとしています。
ずれは実際にどこから来るのか
「もっとデータを収集しよう」という判断から来ることはほとんどありません。普段のエンジニアリングから来ます。
- 新しい依存関係。 クラッシュレポート、アナリティクス、ペイウォールの SDK、地図ライブラリ。
- 新しい権限。 ある機能のための位置情報、スキャナーのためのカメラ、広告のためのトラッキング。
- フレーバーやターゲット。 無料版のビルドに、有料版にはない広告 SDK が入る。
- 削除。 これもずれです。ポリシーが過剰に申告している状態になり、より安全な間違いではあっても間違いには変わりません。
これらはどれもビルドファイルに現れます。build.gradle、AndroidManifest.xml、Podfile、Package.swift、Info.plist、pubspec.yaml、package.json。だからこそチェックできるのです。
方法:記録と、プルリクエストごとのチェック
- ページを書いたときに、何をもとに書いたかを記録します。その時点のビルドにある SDK、データの種類、権限です。
- プルリクエストごとにビルドファイルを読み直して比較します。
- 違いがあれば、何が、どこで(ファイルと行)、どのページやフォームに影響しうるかを示します。
重要な性質が 2 つあります。チェックはビルドファイルだけを読む必要があります。ソースコードもシークレットも読まないので、どのリポジトリで実行しても安全です。そして「違反」ではなく「古くなっている可能性がある」と伝える必要があります。ビルドファイルにライブラリがあっても、アプリがそれを使っている証拠にはならず、アプリが収集するものが変わるかどうかを知っているのはあなただけだからです。
AppFoyer で設定する
チェックはすべてのプランで無料です。ビルドファイルだけを読み、キーもシークレットも不要で、どこにも何も送信せず、ページを変更することもありません。
Claude Code プラグインを使う場合
- “make this app store-ready” と伝えます。プラグインはページの下書きを作るだけでなく、リポジトリのルートに
appfoyer.jsonを書き込みます。ページが何をもとに書かれたかの記録です。 - “add the AppFoyer drift check” と伝えます。GitHub のワークフローが表示され、了承すると
.github/workflows/appfoyer.ymlが書き込まれます。 - 両方のファイルをコミットします。プラグインがあなたの代わりにコミットやプッシュをすることはありません。
プラグインを使わない場合
ワークフローを自分で追加します。
name: AppFoyer drift check
on: pull_request
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: appfoyer/check-action@v1
プルリクエストを開きます。リポジトリにまだ appfoyer.json がない場合、ジョブのサマリーに、ビルドから書き出されるファイルが表示されます。公開中のページと比べてからコミットしてください。
または、ローカルで作成します。同じスキャナーが npm で公開されています。
npx @appfoyer/check init
他の CI システムの場合
npm パッケージは Node 20 以降が動く環境ならどこでも動作します。たとえば GitLab の場合:
appfoyer-drift-check:
image: node:22
script:
- npx -y @appfoyer/check --fail-on-drift
--format markdown は GitHub のジョブのサマリーと同じレポートを出力します。--format json はスクリプト向けです。
検出結果の例
ページを書いたときには RevenueCat がなかったアプリに、それを追加するプルリクエストの場合:
"Trail Notes": 2 changes
+ In-app purchases / subscriptions (data collected) app/build.gradle.kts:28
→ Privacy policy may not declare "In-app purchases / subscriptions"
→ Google Play Data safety and Apple App Privacy answers may be outdated
→ Terms may not cover purchases and subscriptions
+ RevenueCat (SDK) app/build.gradle.kts:28
→ Store forms: RevenueCat is not in the app's SDK list
→ Privacy policy may not name this SDK
デフォルトでは、ジョブは報告するだけで成功します。with: の下に fail-on-drift: "true" を追加すると、記録が更新されるまで失敗するようになります。
変更が報告されたら
- 変更が影響するものを更新する。 同じブランチで “make this app store-ready” ともう一度伝えます。プラグインがビルドを読み直し、アプリの事実を更新し、変更が関係するページの下書きを作り直し、
appfoyer.jsonを書き直します。または、ダッシュボードでページと Store forms タブを自分で編集します。 - 記録を更新する。 プラグインはすでに行っています。ダッシュボードで編集した場合は
npx @appfoyer/check updateを実行するか、ジョブのサマリーの検出結果の下にある更新済みのファイルをコピーします。 - 同じプルリクエストでコミットする。 次の実行では変更が表示されず、履歴には依存関係と開示内容の変更が一緒に入ったことが残ります。
- コンソールのストアフォームを更新する。 チェックも AppFoyer も Play Console や App Store Connectにはアクセスできません。回答の下書きはダッシュボードの Store forms タブにあります。
- レビュー画面から、更新した下書きを公開する。
1 つのリポジトリに複数のアプリ
appfoyer.json はストアの掲載情報ごとに 1 つのエントリを持ちます。独自のアプリケーション ID を持つプロダクトフレーバーには独自のエントリがあるため、無料フレーバーだけが使う広告 SDK は、有料フレーバーのページではなく無料フレーバーのページと比較されます。プラグインは、ストア対応にしたフレーバーごとに1 つのエントリを書き込みます。手で書く場合、エントリには sourceSets のリスト(["free"]、または複数ディメンションのビルドでは組み合わせ内のすべてのフレーバーと組み合わせそのもの)を指定し、アプリがモノレポの中にある場合は root フォルダも指定します。
見えないもの
- 依存関係の依存関係。 ただし iOS は例外で、
Podfile.lockにそれらが記載されています。別のライブラリが取り込む SDK はビルドファイルに現れないので、ここにも現れません。 - コードだけで書かれた設定。 Expo の
app.config.js/app.config.tsは JavaScript なので読み取られません。app.jsonとpackage.jsonは読み取られます。 - 申告したものを実際に使っているかどうか。 存在するが使われていない依存関係も報告されます。
- バックエンド。 サーバーが何をどれだけの期間保存するかは、ビルドファイルのどこにも書かれていません。
これは、変更を開示するのが最も安く済む時点でのリマインダーであり、コンプライアンスの判定でも法的助言でもありません。
公式の情報源
- Provide information for Google Play’s Data safety section — Google Play Console ヘルプ:フォームを正確に保つこと、サードパーティ SDK のデータについて
- App privacy details on the App Store — Apple:回答を最新に保つこと、アプリのアップデートなしで回答を更新することについて
appfoyer/check-actionと@appfoyer/check— Action と npm パッケージ、それらが読み取るもの