wjs-publishing-appstore について
既存の TestFlight ビルドを App Store 審査に提出するためのスキルです。ストアのメタデータとスクリーンショットを用意し、既存の TestFlight ワークフローに手動実行の fastlane release レーンを追加します。
主な機能
- 01App Store メタデータのひな形作成
- 02ローカライズ済みスクリーンショットの撮影
- 03手動実行の fastlane release レーン追加
- 04提出前のストアページ確認
- 05処理済み TestFlight ビルドの再利用
活用シーン
- 01App Store 審査用のローカライズ資料作成
- 02ストア掲載用のシミュレーター画像撮影
- 03既存の TestFlight ビルドを審査に提出
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jianshuo/ claude-skills --skill wjs-publishing-appstoreインストール後、Claude Code で/wjs-publishing-appstoreを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
scripts/release_lane.rbscaffold-metadata.shshoot.sh詳細
wjs-publishing-appstore
TestFlight にビルド済みの iOS アプリを App Store で公開します。スクリーンショットと説明文/メタデータを準備し、既存の fastlane を使って審査に提出します。
これは wjs-publishing-testflight に対応する App Store 向けのスキルで、同スキルは前提条件です。ビルド/署名(match)/CI/beta レーンはそちらで管理します。このスキルではそれらが完了していることを前提とし、リスティングと明示的に実行する release レーンだけを追加します。参考実装:VoiceDrop、Cathier。
基本的な考え方
git push → main → beta lane → TestFlight (unchanged, automatic)
fastlane release → release lane → metadata + screenshots → submit for review
審査への提出は重大な操作なので、プッシュによって実行されることはありません。自分の意図で実行する fastlane release コマンドによってのみ実行されます。
前提条件
wjs-publishing-testflightがすでに設定済みであること:matchの App Store 証明書、ASC_API_*シークレット、正常に動作するbetaレーン、および 少なくとも 1 つのビルドがすでに TestFlight にアップロード済みであること(これによって App Store Connect のアプリレコードも作成されます)。- Apple の認証情報/ASC API キー:[[apple-developer-credentials]] と
wjs-publishing-testflightの前提条件の表を参照してください。ここではシークレットを再掲しないでください(このスキルは公開リポジトリに自動公開します)。 - App Store Connect のアプリレコードがまだ存在しない場合は、一度だけ作成します:
bundle exec fastlane produce -u [email protected] -a <BUNDLE_ID> --app_name "<Name>"。
手順
1. メタデータのディレクトリを作成する
scripts/scaffold-metadata.sh # from this skill; run at the repo root
編集可能な VoiceDrop の文面を初期データとして、fastlane/metadata/{zh-Hans,en-US}/*.txt、review_information/、最上位のカテゴリ/著作権情報を作成します。再実行しても既存ファイルは上書きされません。
2. 実際の文面を書く
すべての .txt を編集します。文字数制限に注意してください:名前 30・サブタイトル 30・キーワード 100(カンマ区切り、スペースなし)・プロモーション用テキスト 170・説明文 4000。review_information/ に電話番号を入力し、ログインが必要な場合に限りデモアカウントを入力してください。プライバシー URL も設定します。
App Store の name は全世界で一意である必要があります。「VoiceDrop」のような短く一般的な名前は、ほぼ確実に別のアカウントですでに使われています。その場合、提出時に upload_to_app_store で 「入力したアプリ名はすでに使用されています。」 と表示され、処理が失敗します。これは表示名のみです。ホーム画面の名前(CFBundleDisplayName)とは別なので、そちらは好きな名前のままでかまいません。区別しやすい名前を選んでください(例:単語を追加する、または中国語の接尾辞を付ける ―「VoiceDrop 口述」など)。長い名前ほど安全です。ロケールごとに設定でき、後のバージョンで変更できるため、固定されるものではありません。
3. スクリーンショットを撮影する
scripts/shoot.sh # default: iPhone 16 Pro Max (6.9"), zh-Hans
LOCALE=en-US scripts/shoot.sh # second locale
shoot.sh の drive_screens() を編集し、各マーケティング画面(3~6 枚、01_*、02_*…の名前)を表示します。シミュレーターを起動してビルドとインストールを行い、fastlane/screenshots/<locale>/ にキャプチャを保存します。FRAME=1 を指定すると frameit のフレームが追加されます。
必須サイズ: 必須なのは 6.9" ディスプレイ(1320×2868)のみで、iPhone 専用アプリにも適用されます。13" iPad 用の撮影は、TARGETED_DEVICE_FAMILY に iPad が含まれる場合のみ追加してください(VoiceDrop は iPhone 専用のため 1 サイズのみ)。
マイク許可に関する注意点: アプリがマイク/録音の許可を求める場合、iOS では xcrun simctl privacy grant microphone で抑止できないダイアログが表示されます(iOS 26 シミュレーター固有の制限です)。Simulator.app を開き、「允许/Allow」を一度だけタップしてください。許可はインストール中保持されるため、その後 shoot.sh を再実行すると、ダイアログのない画面を撮影できます。(simctl に tap はありません。スクリプトからクリックしようとしないでください。osascript による擬似クリックには macOS のアクセシビリティ権限が必要ですが、実行環境にはありません。)
その他の iOS 26 シミュレーターでのスクリーンショットに関する注意点:
- タップしないと表示できない画面を撮影する場合は、一時的にアプリの起動時にその画面を表示するようにしてください(環境変数で切り替える
DebugRoot)。また、アプリ独自のトークンを使ってデータを投入してください(シミュレーターは再インストールのたびに同期可能なキーチェーンの ID を再生成します。iCloud アカウントもないため、古い ID で注入したデータは表示されません。実機では ID が保持されます)。 - シミュレーターでは、何もない 2 タブの
TabViewでも、Dynamic Island 付近にTabViewのラベルの薄い残像が描画されます。これは Liquid Glass によるシミュレーター限定の現象で、アプリ内にはありません。原因を追わず、実機で確認してください。
4. release レーンを追加する
scripts/release_lane.rb の内容を、既存の fastlane/Fastfile の
platform :ios do … end 内に貼り付けます。メタデータとスクリーンショットをアップロードします(TestFlight レーンでは skip_metadata/skip_screenshots: true を設定しますが、このレーンでは false を設定します)。続いて、暗号化/IDFA のコンプライアンス回答を設定して submit_for_review: true を実行します。guard_not_in_review で保護されています。
5. プレビューしてから申請する
# dry-run the listing without submitting (writes an HTML preview, no upload):
bundle exec fastlane deliver --skip_binary_upload true --submit_for_review false --force false
# real submit (uses the build already on TestFlight for this version):
bundle exec fastlane release skip_build:true # reuse the TestFlight build
bundle exec fastlane release # or build a fresh one first
ローカルで実行するか、build.yml で appstore の選択肢が fastlane release に振り分けられる場合は、CI の workflow_dispatch 経由で実行します(wjs-publishing-testflight のステップ 3 を参照)。
確実な2段階リリース(実際にうまくいった方法): git push → beta レーンがビルドを作成して TestFlight にアップロードし、Apple による処理が完了するまで待機 → その後 appstore をディスパッチ → fastlane release skip_build:true で、すでに処理済みのビルドを再利用します。リリースレーン内で新しいバイナリをビルドすると、ビルドの処理が完了する前に申請してしまうおそれがあります。CI は main をチェックアウトするため、ディスパッチする前にメタデータとスクリーンショットを main にコミットしておく必要があります。
スクリーンショットの除外設定を解除する。 TestFlight 専用のセットアップでは、.gitignore に fastlane/screenshots/ が含まれていることがよくあります(このフローでは skip_screenshots を使用します)。このレーンではスクリーンショットをアップロードするため、コミットしておく必要があります。その除外行を削除するか(frameit の追加ファイルのみ除外したままにします)、CI は何もアップロードしません。
App Store Connect で初回申請前に一度だけ対応する項目
これらの設定は fastlane のメタデータではなく ASC の Web コンソールにあり、設定が完了するまで fastlane は申請を拒否します。初回の fastlane release の前に、一度だけすべて対応してください。設定は保持されるため、以降のバージョンで再設定する必要はありません。申請がこれらの項目で失敗するのは、最後の最後です。メタデータとスクリーンショットはすでにアップロードされているので、コンソールで項目を修正して再ディスパッチすればよく、再アップロードは不要です。実際のエラーブロックには、不足している属性がすべて一度に表示されます(violenceCartoonOrFantasy、ageAssurance、contentRightsDeclaration、「価格が設定されるまで、アプリは申請できません」 など)。
- 年齢制限指定の質問項目 — ユーティリティアプリの場合は、すべて「なし」/「いいえ」と回答します。Apple は2025年にこれを拡張しました(新しい項目:
ageAssurance、parentalControls、messagingAndChat、healthOrWellnessTopicsなど)。fastlane の年齢制限設定では完全には対応していないため、fastlane ではなくWeb コンソールで設定してください。 - 価格と配信状況 — 価格を無料に設定し、配信対象の国または地域を選択します。設定するまで、「価格が設定されるまで、アプリは申請できません」 と表示されます。
- コンテンツ権利の申告(App 情報) — ほとんどのアプリでは「サードパーティコンテンツを使用していない」を選択します。
- App プライバシーの「栄養表示」— データ収集について申告します。VoiceDrop の場合、音声はユーザー自身のストアに保存されるユーザーコンテンツです。位置情報は任意の概略情報(ファイル名のみ)です。Apple でサインインは匿名の識別子であり、トラッキングは行いません。
- 輸出コンプライアンス — レーン(
export_compliance_uses_encryption: false)で処理されるため、コンソールでの操作は不要です。 - 審査前にビルドを関連付ける必要があります(レーンが行います)。
すでに審査中のバージョンを更新する
guard_not_in_review(および Apple)は、バージョンが審査待ちの間、再申請をブロックします。新しいビルドに差し替えたり、文言を修正したり、スクリーンショットを追加したりするには、ASC でバージョンを開き、「このバージョンを審査から削除」(編集可能な状態に戻します)を選択してから、fastlane release skip_build:true を再ディスパッチします。新しいビルドが選択され、メタデータとスクリーンショットが再アップロードされて、再申請されます。
スクリーンショットはバイナリと一致している必要があります(ガイドライン 2.3.3)。 審査中のビルドにない機能のスクリーンショットは使用しないでください。申請するビルドにその機能を含めるか、その機能が含まれるバージョンまでスクリーンショットの使用を保留してください。
確認チェックリスト
-
fastlane/metadata/**に...FILL_ME...や空の必須フィールドがない -
fastlane/screenshots/<locale>/に、各ロケールにつき 6.9" の PNG が 1 枚以上あり、ファイル名がNN_*になっている -
fastlane deliverのプレビュー(ステップ 5 のドライラン)で、リスティングが正しく表示される - App Privacy、年齢制限、価格が ASC コンソールで設定されている
-
fastlane release→ 「Submitted X for App Store review」;release/Xタグが存在する - App Store Connect で、バージョンが Waiting for Review と表示されている
よくある間違い
| 症状 | 対処法 |
|---|---|
Could not find app … on App Store Connect | アプリレコードがありません → fastlane produce(ステップ/前提条件)。 |
| 「入力したアプリ名はすでに使用されています」 | name は全体で使用されています → 固有の表示名を選択します(ステップ 2)。 |
| 「スクリーンショットがありません」と送信に失敗する/CI から何もアップロードされない | 6.9" のスクリーンショットがない、サイズが間違っている、または fastlane/screenshots/ がまだ Git の追跡対象外になっている(追跡対象から除外しないようにします)。 |
violence…/ageAssurance/contentRightsDeclaration がない/「価格が設定されている」 | 初回提出時に必要なコンソール項目が未設定です → ASC の Web コンソールで、年齢制限、価格=Free、コンテンツ権利、App Privacy を一度設定します。 |
Another version is in review/guard_not_in_review が発生する | 審査中のバージョンを更新するには、ASC で「Remove this version from review」を選択してから、再度ディスパッチします。 |
| キーワードフィールドでエラーになる | キーワードはカンマ区切りで、スペースを含めず、合計 100 文字以内にする必要があります。 |
| 間違ったビルドが提出される | release skip_build:true を使い、この MARKETING_VERSION に対応する同一の TestFlight ビルドを再利用します。 |
このスキルのファイル
scripts/scaffold-metadata.sh—deliverメタデータツリーを作成します(VoiceDrop の文面を初期設定)scripts/shoot.sh—simctlによるスクリーンショット撮影をスクリプト化しますscripts/release_lane.rb— Fastfile に貼り付けるreleasefastlane レーン