05. ストア掲載情報の更新をAPIで自動化する
応用事項編(PhaseEx)の最終章へようこそ。
アプリを一度リリースすると、そこから先は「直す → ビルドする → ストアの掲載情報を更新する」の繰り返しになります。このうち最後の「掲載情報の更新」だけが、いつまでも手作業として残りがちです。
アプリ名、サブタイトル、キーワード、説明文、リリースノート、そしてスクリーンショット。これを2つのストア × 対応言語の数だけ、ブラウザで管理画面を開いて貼り直す。バージョンを上げるたびにこれをやるのは、地味ですが確実に消耗します。しかも手で貼る作業は、貼り忘れと貼り間違いが必ず起きます。
幸い、AppleもGoogleも公式のAPIを用意しています。この記事では、App Store Connect API と Google Play Developer API の鍵を取得し、fastlane を経由して掲載情報の反映をコマンド一発にするまでを、実際に詰まった箇所も含めて手順として解説します。
この記事のサブコンテンツ
Section titled “この記事のサブコンテンツ”- 手作業のストア更新を卒業する
- Apple側でApp Store Connect APIキーを発行する
- Google側でサービスアカウントを作り権限を渡す
- fastlaneを導入して掲載情報をファイルで管理する
- 審査に出さないことを二重に担保して実行する
- 実際に踏んだ落とし穴と応用事項編の総まとめ
1. 手作業のストア更新を卒業する
Section titled “1. 手作業のストア更新を卒業する”何が自動化できて、何ができないのか
Section titled “何が自動化できて、何ができないのか”最初に、APIの機能と、この記事で自動化する範囲を分けます。
| APIから更新できる | |
|---|---|
| できる | アプリ名、サブタイトル、キーワード、説明文、簡単な説明、宣伝用テキスト、リリースノート、審査メモ、スクリーンショット、フィーチャーグラフィック |
| この記事では管理画面で確認する | 価格、販売地域、年齢レーティング、データセーフティ/Appのプライバシー、輸出コンプライアンス。一部にはAPIもあるが、この手順では扱わない |
| この記事では自動化しない | 審査への提出 |
App Store Connect APIには価格・配信地域などを更新する機能もあります。「このレーンで扱わない」ことと「APIが存在しない」ことは別です。
3つ目が重要です。fastlaneは審査提出まで実行できてしまいますが、この記事では最後まで「提出しない」設定で組みます。提出は人間が管理画面から判断して押す作業として残します。自動化の目的は、ボタンを押す人を消すことではなく、貼り間違いを消すことだからです。
flowchart LR
Text["手元のテキストファイル<br/>fastlane/metadata/"] --> FL["fastlane"]
Shot["手元のスクリーンショット<br/>fastlane/screenshots/"] --> FL
FL -->|"App Store Connect API"| ASC["App Store Connect<br/>提出準備中の版"]
FL -->|"Google Play Developer API"| Play["Google Play Console<br/>保留中の変更"]
掲載文をリポジトリの中のテキストファイルとして持ち、それをfastlaneがAPIに流し込む形です。こうすると掲載文がGitの履歴に残り、「前回なんて書いたっけ」を管理画面で探す必要がなくなります。
なぜ生のAPIではなくfastlaneなのか
Section titled “なぜ生のAPIではなくfastlaneなのか”テキストを送るだけなら、APIを直接叩くコードをAIに書かせても大した手間ではありません。問題はスクリーンショットです。
App Store Connect APIの画像アップロードは、「枠の予約 → チャンク分割送信 → チェックサム照合 → コミット」という多段プロトコルになっています。1枚ごとにこれを正しく踏む必要があり、自前で書くと最も消耗する部分です。iPhoneとAndroid、複数言語分を揃えると数十枚になるので、ここを自分で実装する価値はほぼありません。
fastlaneの deliver(iOS)と supply(Android)は、まさにこの部分を解決するために存在します。
そして、CIには載せません
Section titled “そして、CIには載せません”CI/CDの流れからすると意外に思われるかもしれませんが、この経路はGitHub Actionsではなく、自分のマシンから実行することを勧めます。理由は3つあります。
- スクリーンショットの元データがCIに存在しない。 画像は容量が大きいのでリポジトリに入れないのが普通で、
.gitignoreに入っていればCIのチェックアウト先には1枚もありません。そもそもスクショの撮影はアプリを実際に動かす作業なので、パイプラインの起点が最初から手元にあります。 - 鍵の置き場所が1つ減る。 秘密鍵はストアへの書き込み権限そのものです。手元の
~/.config/にパーミッション600で置いて使うなら、GitHub Secretsに複製する必要がありません。鍵が存在する場所が少ないほど、漏れる経路も少なくなります。 - 見慣れない環境からの自動アクセスは、余計な検知を招きやすい。 特にfastlaneをApple IDとパスワードでログインさせる古い方式では、CIのIPアドレスから叩くたびに2要素認証のチャレンジが飛び、セッションが切れてジョブが止まります。これから作るAPIキー方式ならその多くは回避できますが、普段使っているマシンから叩いている限り、そもそもこの問題は起きません。
本ガイドでは最初にローカルで動作を確認します。CIでも、スクリーンショットの生成や成果物の取得、権限を絞った資格情報、差分確認の手順を用意すれば実行できます。ローカル実行そのものが公開事故を防ぐわけではありません。
2. Apple側でApp Store Connect APIキーを発行する
Section titled “2. Apple側でApp Store Connect APIキーを発行する”Apple側でやることは1つだけです。APIキーの発行です。
App Store Connect → ユーザーとアクセス → 統合 → App Store Connect API
初回は「許可のリクエスト」画面が出ます
Section titled “初回は「許可のリクエスト」画面が出ます”はじめてこのページを開くと、「App Store Connect APIへのアクセスには許可が必要です」という画面が表示されます。これは異常ではなく、正常な初回ゲートです。そのままリクエストしてください。
- 個人アカウントの場合: 有効化はアカウント責任者(=あなた自身)の操作なので、その場で通ります。
- 組織アカウントで責任者が別の人の場合: その人の承認待ちになります。
有効化されると、「チームキー」タブが現れます。ここでキーを生成します。
アクセス権の範囲を確認する
Section titled “アクセス権の範囲を確認する”この例では App Manager を使いますが、審査提出なども可能なロールです。チームキーは特定アプリだけにアクセスを限定できないため、最小権限の要件を満たすか確認してください。用途によってはアプリへのアクセスを絞ったユーザーの個人キーも検討します。以下のIssuer IDを使う手順はチームキー向けです。AppleのAPIキーの説明を参照してください。
控えるものは3つ
Section titled “控えるものは3つ”| 何か | どこに出るか | |
|---|---|---|
| Issuer ID | チーム全体で共通のUUID | ページ上部 |
| Key ID | 発行したキーごとの10文字前後の英数字 | キーの行 |
.p8 ファイル | 秘密鍵の本体 | 発行直後にダウンロード |
先に知っておくべき前提が1つ
Section titled “先に知っておくべき前提が1つ”deliver が更新するのは、App Store Connectの「編集可能な状態にあるバージョン」の掲載文です。具体的には「提出準備中(Prepare for Submission)」の版を指します。
この版が存在しないと、deliver はそこで止まります。まだ次のバージョンを作っていない場合は、先にApp Store Connectで新しいバージョンを追加しておいてください。
3. Google側でサービスアカウントを作り権限を渡す
Section titled “3. Google側でサービスアカウントを作り権限を渡す”ここが一番手数が多く、一番詰まりやすい手順です。Google Cloud ConsoleとGoogle Play Consoleという別々の管理画面をまたぐうえ、片方を忘れると次で解説するとおり紛らわしいエラーが出ます。
やることは3つです。
flowchart TD
A["① Google Cloud Console<br/>サービスアカウントを作り<br/>JSON鍵を取得"] --> B["② Google Cloud Console<br/>Google Play Android Developer API を有効化"]
B --> C["③ Google Play Console<br/>そのアカウントを招待して権限を渡す"]
C --> D["最大24時間の反映待ち"]
① サービスアカウントを作り、JSON鍵を取得する
Section titled “① サービスアカウントを作り、JSON鍵を取得する”Google Cloud Console → IAMと管理 → サービスアカウント → サービスアカウントを作成
- 名前を付けます(例:
play-store-publisher)。 - Cloud側のロールは付けなくて構いません。権限はこの後Play Console側で渡します。
- 作成後、そのアカウントの「キー」タブから 鍵を追加 → 新しい鍵を作成 → JSON を選び、ダウンロードします。
- 表示されるメールアドレス(
…@….iam.gserviceaccount.comの形)を控えます。次の手順で使います。
JSONも .p8 と同じ扱いです。リポジトリの外に置いてください。
mv ~/Downloads/xxxxx-xxxxxxxxxxxx.json ~/.config/myapp/play-publisher.jsonchmod 600 ~/.config/myapp/play-publisher.json② Google Play Android Developer API を有効化する
Section titled “② Google Play Android Developer API を有効化する”ここが最大の落とし穴です。
Google Cloud Console → APIとサービス → ライブラリ → 「Google Play Android Developer API」を検索 → 有効にする
サービスアカウントに権限を渡すことと、そのアカウントが属するCloudプロジェクトでAPI自体を使えるようにすることは、まったく別の設定です。有効化を忘れると、権限が正しく付いていても次のようなエラーが返ります。
Google Play Android Developer API has not been used inproject 000000000000 before or it is disabled.厄介なのは、これが権限の反映待ちとまったく同じ 403 として返ることです。「権限を付けたのに動かない、まだ反映されていないんだろう」と待ち続けても、永久に直りません。Play連携で 403 を見たら、まずここを疑ってください。
③ Play Consoleで招待し、権限を最小限だけ渡す
Section titled “③ Play Consoleで招待し、権限を最小限だけ渡す”Google Play Console → ユーザーとアクセス → ユーザーを招待
先ほど控えたサービスアカウントのメールアドレスを入力します。そして権限の設定で、「アプリの権限」タブから対象アプリだけを追加し、「アカウントの権限」は空のままにしてください。こうすると、この鍵が届く範囲がそのアプリ1つに閉じます。
アプリに対して渡す権限は、次のとおりです。
| 権限 | 付与 | 理由 |
|---|---|---|
| 製品版としてのリリース | ✗ 渡さない | ユーザーに公開できてしまう |
| テスト版トラックとしてのアプリのリリース | ✓ 渡す | Edits APIに必要。製品版には公開できない |
| ストアの掲載情報の編集(別グループ) | ✓ 渡す | 掲載文と素材の更新に必要 |
| アプリ情報の閲覧 | ✓ ONのまま | supply は書き込む前に現在の状態を読んで差分を組み立てるため、読み取りが無いと書き込みも失敗します |
| テスト版トラックの管理、テスターリストの編集 | ✗ 渡さない | テスターリストは扱わない |
④ 反映を待つ
Section titled “④ 反映を待つ”権限がAPIから見えるようになるまで、最大24時間かかります。付与直後に叩くと権限エラーになりますが、待てば直ります。
この手順は他の作業より先に着手しておくのが得です。待ち時間が他の作業と重なるので、最後に回すとそこだけで丸1日止まります。
4. fastlaneを導入して掲載情報をファイルで管理する
Section titled “4. fastlaneを導入して掲載情報をファイルで管理する”鍵が揃ったので、fastlaneを入れます。
インストール
Section titled “インストール”fastlaneはRuby製なので、Gemfile でバージョンを固定して入れるのが確実です。プロジェクトのルートに置きます。
# Gemfilesource "https://rubygems.org"gem "fastlane"bundle install識別子を書く
Section titled “識別子を書く”fastlane/Appfile に、両ストアの識別子を書きます。Expoなら app.json の expo.ios.bundleIdentifier と expo.android.package と同じ値です。
# fastlane/Appfileapp_identifier("com.example.myapp") # iOSpackage_name("com.example.myapp") # Android掲載文をファイルとして置く
Section titled “掲載文をファイルとして置く”fastlaneは決まった場所のテキストファイルを読んでストアに送ります。ディレクトリ構造そのものが設定ファイルです。
fastlane/├── Appfile├── Fastfile├── metadata/ # ← iOS│ ├── ja/│ │ ├── name.txt # アプリ名│ │ ├── subtitle.txt # サブタイトル│ │ ├── keywords.txt # キーワード│ │ ├── description.txt # 説明│ │ ├── promotional_text.txt # 宣伝用テキスト│ │ └── release_notes.txt # このバージョンの新機能│ ├── en-US/│ │ └── (同じ構成)│ ├── review_information/│ │ └── notes.txt # 審査メモ│ └── android/ # ← Android│ ├── ja-JP/│ │ ├── title.txt # アプリ名│ │ ├── short_description.txt # 簡単な説明│ │ ├── full_description.txt # 詳しい説明│ │ ├── changelogs/│ │ │ └── 63.txt # versionCode ごとのリリースノート│ │ └── images/│ │ └── phoneScreenshots/│ └── en-US/│ └── (同じ構成)└── screenshots/ # ← iOS ├── ja/ └── en-US/ここで2つ、間違えやすい点があります。
ロケール名が両ストアで違います。 iOSは ja / en-US、Playは ja-JP / en-US です。日本語のディレクトリ名が食い違うので、コピーするときに事故が起きます。
スクリーンショットの掲載順は、ファイル名の辞書順で決まります。 deliver も supply も名前順に並べるだけなので、意図した順序にしたければ先頭に番号を振ってください。
ja__iphone-6.5__1-home.pngja__iphone-6.5__2-record.pngja__iphone-6.5__3-result.png掲載文の生成をAIに任せる
Section titled “掲載文の生成をAIに任せる”Phase06:04. ストア掲載情報とスクリーンショットをAIで作成する で固めたアプリの仕様をもとに、AIエージェントに掲載文をこの構造のまま書き出させることができます。
【タスク: ストア掲載テキストをfastlaneの構造で生成】
ルートの `SPEC.md` を読み込んでください。App Store と Google Play の掲載テキストを作成し、以下のパスにファイルとして書き出してください。
- fastlane/metadata/ja/name.txt (30文字以内)- fastlane/metadata/ja/subtitle.txt (30文字以内)- fastlane/metadata/ja/keywords.txt (UTF-8で100バイト以内、半角コンマ区切り)- fastlane/metadata/ja/description.txt (4,000文字以内)- fastlane/metadata/ja/release_notes.txt- fastlane/metadata/android/ja-JP/title.txt (30文字以内)- fastlane/metadata/android/ja-JP/short_description.txt (80文字以内)- fastlane/metadata/android/ja-JP/full_description.txt (4,000文字以内)
同じ内容の英語版を en-US / en-US にも作成してください。各ファイルは本文のみで、見出しやコードフェンスを含めないこと。書き出したあと、各ファイルの文字数と上限を表にして報告してください。Apple用キーワードはUTF-8のバイト数も検証してください。最後の1行が効きます。文字数の上限超過はアップロード時にエラーになるので、送る前に手元で分かる方が早いです。特に英語は同じ内容でも日本語の倍以上の文字数になるため、先に詰まるのはたいてい英語側です。
5. 審査に出さないことを二重に担保して実行する
Section titled “5. 審査に出さないことを二重に担保して実行する”Fastfile を書く
Section titled “Fastfile を書く”fastlane/Fastfile に、iOSとAndroidそれぞれのレーンを定義します。コメントの部分が実際に効いている理由なので、消さずに残しておくことをおすすめします。
# fastlane/Fastfile
opt_out_usagedefault_platform(:ios)
# スクリーンショットは直列に上げる。既定の並列アップロードは削除と競合し、# 同じ画像が2枚ずつ入った状態を作る。掲載順はファイル名順で決まるので、# 重複はそのまま並び順の崩れになる。# レーンの中で設定しても遅い ―― deliver の設定はその前に組まれる。ENV["DELIVER_NUMBER_OF_THREADS"] ||= "1"
platform :ios do desc "App Store Connect の掲載情報を更新する(審査には出さない)" lane :metadata do |options| with_screenshots = options[:screenshots].to_s == "true"
validate_store_files!(:ios, with_screenshots)
key = app_store_connect_api_key( key_id: ENV.fetch("ASC_KEY_ID"), issuer_id: ENV.fetch("ASC_ISSUER_ID"), key_content: ENV.fetch("ASC_KEY_P8"), is_key_content_base64: true )
deliver( api_key: key, # 文言と素材だけ。ビルドはここでは扱わない。 skip_binary_upload: true, skip_app_version_update: true, # 提出しない。「提出準備中」の版に置かれるだけで、公開はされない。 submit_for_review: false, automatic_release: false, # 確認プロンプトと HTML プレビューを出さない。 force: true, run_precheck_before_submit: false, # 素材を持たずに overwrite すると、ストア側の既存素材が消える。 # 持っているときだけ上書きし、持っていないときは触らない。 skip_screenshots: !with_screenshots, overwrite_screenshots: with_screenshots ) endend
platform :android do desc "Google Play の掲載情報を更新する(審査には送らない)" lane :metadata do |options| with_screenshots = options[:screenshots].to_s == "true"
validate_store_files!(:android, with_screenshots)
supply( json_key_data: ENV.fetch("PLAY_SERVICE_ACCOUNT_JSON"), # リリースノートはトラック別。既定の production を使うと、そこに存在しない # versionCode のノートを書こうとして落ちるうえ、サービスアカウントに # 製品版の権限も渡していない。 track: "internal", # ビルドは上げない。掲載文と素材だけ。 skip_upload_apk: true, skip_upload_aab: true, # ビルドを伴わないので、changelog がどの版のものか supply 自身では # 判断できない。changelogs/<code>.txt のファイル名と一致させる。 version_code: android_version_code, # 保存はするが審査に送らない。これがないと掲載変更がそのまま審査に行く。 changes_not_sent_for_review: true, # APIエラー時に設定を変えて再送せず、その場で停止する。 rescue_changes_not_sent_for_review: false, skip_upload_images: !with_screenshots, skip_upload_screenshots: !with_screenshots ) endend
# 最低限の存在・空欄チェック。翻訳や画像の内容は実行前に目視確認する。def validate_store_files!(platform, with_screenshots) base = File.expand_path(__dir__) locales = platform == :ios ? ["ja", "en-US"] : ["ja-JP", "en-US"] fields = platform == :ios ? %w[name subtitle keywords description] : %w[title short_description full_description] locales.each do |locale| root = platform == :ios ? "metadata/#{locale}" : "metadata/android/#{locale}" fields.each do |field| path = File.join(base, root, "#{field}.txt") UI.user_error!("掲載文がありません: #{path}") unless File.file?(path) body = File.read(path, encoding: "UTF-8").strip UI.user_error!("掲載文が空です: #{path}") if body.empty? if field == "keywords" && body.bytesize > 100 UI.user_error!("キーワードが100バイトを超えています: #{path}") end end next unless with_screenshots screenshots = platform == :ios ? "screenshots/#{locale}" : "#{root}/images/phoneScreenshots" files = Dir.glob(File.join(base, screenshots, "*.{png,jpg,jpeg}")) UI.user_error!("スクリーンショットがありません: #{screenshots}") if files.empty? endend
# app.json の expo.android.versionCode を読む。# changelogs/<code>.txt のファイル名と揃えるために必要。def android_version_code require "json" config = JSON.parse(File.read(File.expand_path("../app.json", __dir__), encoding: "UTF-8")) code = config.dig("expo", "android", "versionCode") UI.user_error!("app.json から versionCode を読めませんでした。") if code.nil? code.to_send鍵を読み込んで実行するスクリプト
Section titled “鍵を読み込んで実行するスクリプト”環境変数を毎回手で用意するのは事故のもとなので、薄いシェルスクリプトにまとめます。
#!/usr/bin/env bash# tools/store_upload.sh {ios|android}## 資格情報は ~/.config/myapp/ に置く。リポジトリには入れない。# AuthKey_XXXXXXXXXX.p8 … App Store Connect の秘密鍵# play-publisher.json … Play のサービスアカウント# asc.env … ASC_KEY_ID と ASC_ISSUER_ID
set -euo pipefail
# fastlane はロケールが UTF-8 でないと警告を出す。掲載文が日本語なので# 文字化けの実害がありうる。ここで明示する。export LANG="${LANG:-en_US.UTF-8}"export LC_ALL="${LC_ALL:-en_US.UTF-8}"
# 並列アップロードは削除と競合して画像が重複する。export DELIVER_NUMBER_OF_THREADS="${DELIVER_NUMBER_OF_THREADS:-1}"
PLATFORM="${1:-}"if [[ "$PLATFORM" != "ios" && "$PLATFORM" != "android" ]]; then echo "使い方: tools/store_upload.sh {ios|android}" >&2 exit 2fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"CONF="$HOME/.config/myapp"
if [[ "$PLATFORM" == "ios" ]]; then source "$CONF/asc.env" : "${ASC_KEY_ID:?asc.env に ASC_KEY_ID がありません}" : "${ASC_ISSUER_ID:?asc.env に ASC_ISSUER_ID がありません}"
KEY_FILE="$CONF/AuthKey_${ASC_KEY_ID}.p8" [[ -f "$KEY_FILE" ]] || { echo "$KEY_FILE がありません。" >&2; exit 1; }
# .p8 は改行を含むので base64 にして渡す。 ASC_KEY_P8="$(base64 < "$KEY_FILE" | tr -d '\n')" export ASC_KEY_ID ASC_ISSUER_ID ASC_KEY_P8else KEY_JSON="$CONF/play-publisher.json" [[ -f "$KEY_JSON" ]] || { echo "$KEY_JSON がありません。" >&2; exit 1; } PLAY_SERVICE_ACCOUNT_JSON="$(cat "$KEY_JSON")" export PLAY_SERVICE_ACCOUNT_JSONfi
cd "$ROOT"# 手元には素材が揃っているので、スクリーンショットも一緒に送る。bundle exec fastlane "$PLATFORM" metadata screenshots:true~/.config/myapp/asc.env は次の2行だけのファイルです。
ASC_KEY_ID=XXXXXXXXXXASC_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxchmod +x tools/store_upload.shtools/store_upload.sh ios必ずiOSから始めてください。理由は影響範囲の違いです。
| 操作 | ストアへの影響 |
|---|---|
bundle install | なし。ツールを手元に入れるだけ |
store_upload.sh ios | 「提出準備中」の版の文言と素材が置き換わる。提出はされない。何度でも上書きできる |
store_upload.sh android | 本番の掲載情報に保留中の変更が溜まる。審査には送られない |
審査提出をしない設定でも、ストアへの書き込みは発生します。特にiOSの宣伝用テキストなど、バージョンの審査と更新条件が異なる項目があります。送信先のアプリ・編集対象の版・項目を確認し、必要な掲載情報と画像を手元へ保存してから実行してください。
提出に関わる設定と権限を確認する
Section titled “提出に関わる設定と権限を確認する”| 何が止めているか | |
|---|---|
| 設定 | submit_for_review: false / changes_not_sent_for_review: true とエラー時の自動再試行の無効化 |
| 権限 | サービスアカウントに「製品版としてのリリース」を渡していない |
この権限による制限はGoogle Playのサービスアカウントに対するものです。AppleのApp Managerキーには同じ制限はありません。設定と権限を確認しても「絶対に公開されない」とは断言せず、実行前の差分確認と実行後の管理画面での確認を行ってください。
6. 実際に踏んだ落とし穴と応用事項編の総まとめ
Section titled “6. 実際に踏んだ落とし穴と応用事項編の総まとめ”この仕組みを実際に組んだときに詰まった箇所を、そのまま並べておきます。どれも設定を書いた時点では分からず、走らせて初めて出るものです。
| 症状 | 原因と対処 |
|---|---|
Playで 403 が返り続ける | Cloudプロジェクトで androidpublisher.googleapis.com が未有効。権限の反映待ちと同じ 403 に見えるので、まずAPIの有効化を確認する |
| 同じスクリーンショットが2枚ずつ入る | deliver の並列アップロードが削除処理と競合する。DELIVER_NUMBER_OF_THREADS=1 をFastfileの冒頭かシェル側で設定する(レーンの中では遅い) |
Cannot find changelog because no version code given | ビルドを伴わないメタデータ単独更新では、supply はどのversionCode宛てか判断できない。version_code: を明示する |
| 通ったはずのファイルが見つからない | supply と自前の存在確認とで相対パスの基準が違う。パスは絶対パスに統一する |
日本語の掲載文が化ける、invalid byte sequence | ロケールがUTF-8でない。LANG / LC_ALL を明示する |
| ストア側の既存スクショが消えた | 素材を持たない状態で overwrite_screenshots を有効にした。素材があるときだけ上書きする設定にする |
deliver が「バージョンがない」で止まる | App Store Connect側に編集可能な版がない。先に新しいバージョンを作る |
| 空の掲載文がストアに送られた | 生成前に走らせた。掲載文が空だと事故が一番高くつくので、ファイルが無ければ止めるガードを入れておく |
最後の1つは特に重要です。fastlaneは、「掲載文が空」を有効な指示として受け取ります。説明文が空欄になったままストアに反映される事故を防ぐため、レーンの先頭でファイルの存在を確認して止めるようにしておいてください。
掲載文と実装の食い違いに気をつける
Section titled “掲載文と実装の食い違いに気をつける”もう1つ、仕組みの外側の話をしておきます。
掲載文は実装より先に古くなります。たとえば課金を実装したのに説明文が「アプリ内課金はありません」のままだと、それは単なる古い文章ではなく、メタデータ不一致としてリジェクトの理由になります。特に審査メモに書いた内容とビルドの実態がずれていると、審査で必ず止まります。
自動化するとアップロード自体は一瞬で終わるので、送る前に差分を確認する習慣が、手作業の頃より重要になります。
応用事項編の総まとめ
Section titled “応用事項編の総まとめ”これで応用事項編(PhaseEx)の全ステップが完了しました。
- クラウド連携: 01. Firebaseでユーザー認証とクラウド保存を実装する で、端末を超えたデータ同期を実現しました。
- リテンション: 02. Push通知を実装してアクティブ率を向上させる で、ユーザーが戻ってくる仕掛けを作りました。
- AI機能: 03. AI機能(Gemini API)をアプリに組み込む で、アプリ自身にインテリジェンスを持たせました。
- 計測: 04. GA4でアプリの使われ方を計測する で、次に直すべきものを数字で決められるようにしました。
- 運用基盤: 05. ストア掲載情報の更新をAPIで自動化する(この記事)で、リリースのたびに発生する手作業を仕組みに置き換えました。
次のフェーズ:セキュリティ編へ
Section titled “次のフェーズ:セキュリティ編へ”ここまでで、あなたのアプリは認証を持ち、クラウドにユーザーのデータを預かり、課金まで扱うようになりました。そしてこの記事で、ストアへの書き込み権限を持つ鍵まで手元に増えました。
つまり、守るべきものが増えたということです。
この記事では鍵の置き場所と権限の絞り方に触れましたが、それはアプリ全体から見ればごく一部です。最後の「PhaseSec:セキュリティ編」では、AIが書いたコードをそのまま公開することのリスク、秘密情報の扱い、そしてデータベースの権限設計を点検します。
さっそく「01. AI生成コードをそのまま公開して大丈夫?」へ進みましょう!