iOS 壁紙アプリ 6 本に Privacy Manifest を入れて回すという、地味で気の重い作業を 5 月の連休明けから 2 週間続けていました。1 本目で Apple から差し戻しを受け、その差し戻し文面と社内向けに書き残したメモが、残り 5 本のリリースを救った感覚があります。本稿は、その並行投入の運用ノートとして書きます。実装の手順そのものよりも「6 本を同時に動かす段取り」と「1 本目の失敗を残りに翻訳する工程」に焦点を当てます。
実装やコードレベルの詳細は、すでに Privacy Manifest の Required Reason API 対処法 と SDK 連鎖まで監査する手順 に書いたので、本稿はあえて運用面に振り切ります。
なぜ 6 本を並行で動かしたのか
最初は 1 本ずつ順番に出すつもりでした。Apple の審査時間が読めない時期だったため、リスクを 1 本ずつ確かめてから次に移る方が安全に見えたのです。考え直したきっかけは、Privacy Manifest の対応箇所がほぼ全アプリで共通だと気付いたことでした。AdMob、Firebase、RevenueCat、MMKV あたりは 6 本すべてで同じ世代を使っていて、PrivacyInfo.xcprivacy の中身も 8 割ほど同じになります。
ここで、宮大工だった両祖父が「同じ部材は一気に切り出してから組む」と話していた感覚を思い出しました。準備の手間は 1 本も 6 本もほぼ変わらないのなら、提出は分けても、棚卸しと修正は同時に進めた方が手戻りが少ないという判断です。結果として「監査・修正は 6 本まとめて/提出は 2 本ずつ 3 波に分割」という構成に落ち着きました。
1 本目の差し戻しから学べた 3 つのこと
最初の 1 本は、棚卸しを念入りに行ったつもりで提出したのですが、ITMS-91053 ではなく「Privacy Nutrition Label の宣言と Manifest の NSPrivacyTrackingDomains が一致していない」という旨の指摘で差し戻されました。文面そのものは穏やかですが、内容としては「申告漏れ」ではなく「申告の食い違い」が原因でした。
この差し戻しから持ち帰ったのは次の 3 点です。
第一に、Privacy Manifest 単体ではなく App Store Connect 側の Nutrition Label と必ずペアで見る こと。Manifest を綺麗に揃えても、Connect 側のチェックボックスが古い設計のままだと不一致として返ってきます。
第二に、NSPrivacyTrackingDomains の対象は 計測系ドメインだけでなく、広告配信ドメインや A/B 配信ドメインも含めて棚卸し する必要があったこと。AdMob の googleads.g.doubleclick.net を入れ忘れていたのが、今回の差し戻しの直接の原因でした。
第三に、差し戻しの文面は 次に提出する側へのチェックリストとして再利用できる こと。Apple の返答には踏み込んだ理由は書かれませんが、引用された行の番号や、対象 SDK 名のニュアンスから、残り 5 本でどこを見るべきかは推定できます。
残り 5 本にどう翻訳したか
1 本目を差し戻された日のうちに、社内向けの A4 1 枚のメモを書きました。書いた内容は次のような項目です。
- 今回の差し戻し理由(1 文)
- 該当した宣言行とその修正後(差分形式)
- 残り 5 本で同じ症状になりうる箇所のリスト(5 本 × 3 列のチェックボックス)
- Connect 側の Nutrition Label で再確認すべき項目(5 項目)
- 監査スクリプトに追加すべき検出条件(後日反映)
このメモを「翻訳テンプレート」と呼ぶことにしました。1 本ごとの修正履歴ではなく、1 本の失敗を残り N 本に適用するための短い手順書という意味です。結果として、残り 5 本については Manifest の修正自体は 30 分前後で終わり、Connect 側の Label 修正が 1 本あたり 15〜20 分。修正後の再提出はいずれも 1 回で通りました。
メモを書く時間は 40 分ほどでしたが、これを書かずに 5 本分を場当たり対応していたら、おそらく 3 本目あたりで似たような差し戻しを再度受けていたと思います。
段階公開リングをどう設計したか
6 本同時に「Phased Release」を全 7 日間で回す案も考えましたが、最終的には次のような 3 リング構成にしました。
リング 1(2 本)はユーザー数が比較的少なく、フィードバックが直接届きやすいアプリを置きます。ここは Phased Release を最短設定にし、初日からの障害検知を優先します。リング 2(2 本)は中規模で、最も収益貢献が大きいアプリを置きます。1 リング目の 24 時間が無事に過ぎたら順次提出。リング 3(2 本)は最大の DAU を抱えるアプリで、上 2 リングが 72 時間問題なく回ってから提出します。
このリング設計には「壁紙アプリは見た目の変更が無くても再ダウンロードを誘発しにくい」という特性を踏まえています。Privacy Manifest の更新は UI が変わらないため、ユーザーから能動的に再起動してもらえる契機が少なく、配信から実機反映まで時間がかかる前提で設計する必要があります。
Phased Release 自体の判断ルールは 段階公開とホットフィックス戦略の記事 で別途まとめているので、ここでは割愛します。
Claude in Chrome で 6 つの Connect ページを横断確認した工程
6 本分の App Store Connect ページを毎日見て回るのは現実的ではないため、Claude in Chrome に毎朝 6 つのタブを横断させ、次の 3 点を抽出してもらう形にしました。
- 直近 24 時間で審査ステータスに変化があったアプリ
- Crashlytics 由来の新規スタックトレース(クラッシュ率の急上昇)
- ユーザーレビューに「アップデート」「広告」「動かない」というキーワードが含まれる新着レビュー
抽出結果は短い箇条書きで返ってきて、見るべきタブだけ自分で開きにいきます。6 本を同時に動かしているとブラウザの切り替えだけで集中力が削られるので、AI に最初のフィルターを任せられるのは想像以上に効きました。アプリ事業を 2014 年から個人で続けてきて、累計 5,000 万ダウンロード規模になった今は、目視で全アプリを毎日見るより、AI に異常検知だけ任せる方が結果としてアプリの寿命を延ばせるという感触があります。
6 本同時投入で見えた現実的な落とし所
最後に、6 本並行ロールアウトを実際に終えてからの所感を 3 つだけ残しておきます。
ひとつ目は、同時並行の本質は「修正そのもの」ではなく「失敗の翻訳」にある ということです。1 本目の差し戻しから A4 1 枚のメモに翻訳できれば、残り N 本は事実上「修正済みリリースのコピー」になります。
ふたつ目は、Privacy Manifest 系の更新は UI が変わらないので段階公開の意味が薄い、と思い込まないこと。実機反映の遅さがあるため、リング設計はむしろ通常リリースより慎重に組む方が安全でした。
みっつ目は、個人開発で 6 本を同時に動かすのは「並行作業」ではなく「並列観測」だ という再認識です。実装は連続的に行い、観測だけ AI に並列で任せる、という形に落ち着くと、人間側の認知負荷が一気に下がります。
次にこれを読んでくださった方が同じ状況に立たれたら、まずは 1 本目を提出する前に「翻訳テンプレートを書くスペース」を 1 ページ分だけ用意してから提出してみてください。それだけで、2 本目以降の動き方が変わります。
お読みいただきありがとうございました。