リリース作業の「最後の1マイル」を自動化する
アプリ開発者として最もストレスの高い作業のひとつが、リリース前後の定型作業です。バージョン番号の更新、リリースノートの執筆(日英対応)、スクリーンショットの差し替え、TestFlightへのビルドアップロード、そして審査提出——これらの作業は、開発そのものとはまったく異なるスキルを要求し、ミスが起きやすく、時間もかかります。
2026年現在、Claude Code と App Store Connect API を組み合わせることで、これらのリリース作業のほぼ全体を自動化できるようになっています。実際に動作するコードを交えながら、iOS/Androidアプリのリリースパイプラインを設計・構築する方法を順を追って整理していきます。
対象読者は、Claude Code の基本操作に慣れており、Xcode やターミナルでの作業経験がある iOS/Android 開発者です。Fastlane の経験があると理解が深まりますが、必須ではありません。Claude Code を使った Xcode 開発の基礎については Claude Code × Xcode iOS開発ガイド を、GitHub Actions との連携については Claude Code × GitHub Actions 完全ガイド を先に参照してください。
全体アーキテクチャを理解する
自動化パイプライン全体の構成を把握してから、各コンポーネントの実装に入りましょう。
本ガイドが目指す最終形は次の通りです。
- トリガー:
git push origin release/v1.x.xまたは GitHub でのタグ作成 - Step 1: Claude Code がバージョン番号を自動更新(
Info.plist/build.gradle) - Step 2: Claude API がコミット履歴を解析してリリースノートを日英自動生成
- Step 3: Fastlane が Simulator 起動・スクリーンショット撮影・ローカライズを実行
- Step 4:
fastlane deliverでビルドを TestFlight にアップロード - Step 5: Slack 通知 → テスター確認 → Production 公開の承認フロー
- Step 6: App Store Connect API で審査提出・リリーススケジュール管理
この全体像を頭に置いたまま、以下を順に実装していきます。
App Store Connect API の認証セットアップ
API キーの発行
App Store Connect API を使うには、APIキー(p8形式) が必要です。Apple Developer サイトで発行します。
発行手順は次の通りです。
- App Store Connect にログイン
- 「ユーザーとアクセス」→「統合」→「App Store Connect API」を開く
- 「+」ボタンで新しいキーを追加(名前例:
Release Automation) - アクセスレベルは「App Manager」を選択
.p8ファイルをダウンロード(一度しかダウンロードできない)Issuer IDとKey IDをメモしておく
発行したキーの情報は環境変数として管理します。
# .env.local(Git管理外に設定)
APP_STORE_CONNECT_KEY_ID=XXXXXXXXXX
APP_STORE_CONNECT_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
APP_STORE_CONNECT_KEY_PATH=/path/to/AuthKey_XXXXXXXXXX.p8Fastlane のインストールと初期設定
Fastlane は Ruby ベースの iOS/Android ビルド自動化ツールです。App Store Connect API のラッパーとして機能します。
# Fastlane のインストール
gem install fastlane
# プロジェクトルートで初期化
cd /path/to/YourApp
fastlane init初期化後、fastlane/Appfile に App Store Connect の認証情報を設定します。
# fastlane/Appfile
app_identifier "com.example.yourapp"
apple_id "developer@example.com"
# App Store Connect API を使用する場合
api_key_path "./fastlane/app_store_connect_api_key.json"API キーは JSON ファイルとして管理するか、環境変数から読み込む方式が推奨です。
{
"key_id": "YOUR_KEY_ID",
"issuer_id": "YOUR_ISSUER_ID",
"key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}Claude Code によるバージョン管理の自動化
リリース作業で最初に行う「バージョン番号の更新」は単純ですが、複数ファイルにまたがるため抜け漏れが発生しやすい作業です。Claude Code はこの作業を一元管理できます。
CLAUDE.md(プロジェクトルートの設定ファイル)に以下のように記述しておきます。
## リリース前のバージョン管理
バージョン番号は以下の4箇所で統一して管理する:
1. `ios/YourApp/Info.plist` — CFBundleShortVersionString & CFBundleVersion
2. `android/app/build.gradle` — versionName & versionCode
3. `package.json` — version フィールド(React Native の場合)
4. `CHANGELOG.md` — 最新エントリ
バージョンアップ時は必ず全箇所を同時に更新し、コミットメッセージは
`chore: bump version to X.Y.Z (build NNN)` の形式を使う。この設定により、Claude Code に「バージョンを 2.3.0 に上げて」と指示するだけで、全ファイルを一括更新してくれます。実際の動作例を見てみましょう。
# Claude Code へのプロンプト例
claude "バージョンを 2.3.0 (build 231) に更新してください。
CLAUDE.md の指示に従い、全4箇所を一括更新してコミットしてください。"Claude Code はファイルを横断して更新し、差分確認後にコミットを作成します。人間がミスしやすい versionCode の連番管理も自動で行われます。
Claude API によるリリースノートの自動生成
リリースノートは「ユーザーへの手紙」です。技術的な変更をユーザー目線の言葉に翻訳し、日本語と英語の両方で用意しなければなりません。これが、開発者にとって最も時間のかかる作業のひとつです。
コミット履歴からリリースノートを生成するスクリプト
以下のスクリプトは、git log からコミット履歴を取得し、Claude API に渡してリリースノートを生成します。
#!/usr/bin/env python3
# scripts/generate_release_notes.py
import subprocess
import json
import os
import anthropic
def get_commits_since_last_tag():
"""前回リリースタグからのコミット一覧を取得"""
try:
# 前回のタグを取得
last_tag = subprocess.check_output(
["git", "describe", "--tags", "--abbrev=0", "HEAD^"],
text=True
).strip()
# タグ以降のコミット一覧
commits = subprocess.check_output(
["git", "log", f"{last_tag}..HEAD", "--oneline", "--no-merges"],
text=True
).strip()
return last_tag, commits
except subprocess.CalledProcessError:
# タグがない場合は全履歴を取得
commits = subprocess.check_output(
["git", "log", "--oneline", "--no-merges", "-20"],
text=True
).strip()
return "v0.0.0", commits
def generate_release_notes(commits, version, app_name):
"""Claude API を使ってリリースノートを生成"""
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
prompt = f"""
あなたはモバイルアプリ「{app_name}」のリリースノート担当者です。
以下のコミット履歴から、ユーザー向けのリリースノート(バージョン {version})を
日本語と英語の両方で作成してください。
# コミット履歴
{commits}
# 出力形式(JSON)
{{
"ja": {{
"title": "バージョン {version} リリース",
"whats_new": "何が新しくなったかの説明(200文字以内、ユーザー目線で)",
"improvements": ["改善点1", "改善点2"],
"bug_fixes": ["バグ修正1", "バグ修正2"]
}},
"en": {{
"title": "Version {version} Release",
"whats_new": "What's new description (under 200 chars, user-focused)",
"improvements": ["improvement1", "improvement2"],
"bug_fixes": ["bug fix1", "bug fix2"]
}}
}}
技術的なコミットメッセージ(chore:, refactor:, ci: など)は省略し、
ユーザーに見える変化のみを記載してください。
"""
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
# JSON部分を抽出してパース
content = message.content[0].text
json_start = content.find("{")
json_end = content.rfind("}") + 1
return json.loads(content[json_start:json_end])
def main():
app_name = os.environ.get("APP_NAME", "MyApp")
version = os.environ.get("APP_VERSION", "1.0.0")
last_tag, commits = get_commits_since_last_tag()
print(f"前回タグ: {last_tag}")
print(f"コミット数: {len(commits.splitlines())}")
release_notes = generate_release_notes(commits, version, app_name)
# fastlane metadata ディレクトリに書き出し
ja_path = "fastlane/metadata/ja/release_notes.txt"
en_path = "fastlane/metadata/en-US/release_notes.txt"
os.makedirs(os.path.dirname(ja_path), exist_ok=True)
os.makedirs(os.path.dirname(en_path), exist_ok=True)
with open(ja_path, "w") as f:
f.write(release_notes["ja"]["whats_new"])
with open(en_path, "w") as f:
f.write(release_notes["en"]["whats_new"])
print("✅ リリースノート生成完了")
print(f"JA: {release_notes['ja']['whats_new']}")
print(f"EN: {release_notes['en']['whats_new']}")
if __name__ == "__main__":
main()このスクリプトを実行すると、fastlane/metadata/ja/release_notes.txt と fastlane/metadata/en-US/release_notes.txt が自動生成されます。App Store Connect の文字数制限(4,000文字)も Claude に渡す指示に含めることで対応できます。
実行例:
前回タグ: v2.2.1
コミット数: 12
✅ リリースノート生成完了
JA: ホーム画面の動作をより快適にしました。検索の精度を向上させ、よく起きていた
クラッシュ問題を修正しています。ご不便をおかけしていた点が解消されています。
EN: We've improved the home screen experience and enhanced search accuracy.
Fixed a crash issue that some users were experiencing.
Fastlane スクリーンショット自動化との統合
App Store のスクリーンショットは、日本語・英語・中国語など複数言語分、かつ複数デバイスサイズ(iPhone 6.7"、6.5"、5.5"、iPad など)を用意する必要があります。手作業では数時間かかる作業です。
snapshot でのスクリーンショット自動撮影
Fastlane の snapshot ツールを使うと、Xcode UI テストと連携してスクリーンショットを自動撮影できます。
# fastlane/Snapfile
devices([
"iPhone 16 Pro Max",
"iPhone 16",
"iPhone SE (3rd generation)",
"iPad Pro 13-inch (M4)"
])
languages([
"ja",
"en-US"
])
scheme "YourAppUITests"
output_directory "./fastlane/screenshots"
clear_previous_screenshots trueUI テスト側では、各画面への遷移とスクリーンショット撮影のタイミングをコード化します。
// YourAppUITests/SnapshotTests.swift
import XCTest
class SnapshotTests: XCTestCase {
func testCaptureHomeScreen() throws {
let app = XCUIApplication()
setupSnapshot(app)
app.launch()
// ホーム画面のスクリーンショット
snapshot("01_HomeScreen")
// 検索画面に遷移してスクリーンショット
app.tabBars.buttons["検索"].tap()
snapshot("02_SearchScreen")
// 設定画面
app.tabBars.buttons["設定"].tap()
snapshot("03_SettingsScreen")
}
}Claude Code は、新しい画面を追加した際に「スナップショットテストの追加」を自動で提案し、既存のパターンに合わせたコードを生成してくれます。
TestFlight への自動配布
ビルドとスクリーンショットが揃ったら、TestFlight への配布を自動化します。
# fastlane/Fastfile
platform :ios do
desc "テスター向けビルドを TestFlight に配布"
lane :beta do
# バージョン情報を環境変数から取得
version = ENV["APP_VERSION"] || get_version_number
build_num = ENV["BUILD_NUMBER"] || get_build_number
# クリーンビルド
gym(
scheme: "YourApp",
configuration: "Release",
export_method: "app-store",
output_directory: "./build",
output_name: "YourApp.ipa"
)
# TestFlight にアップロード
pilot(
ipa: "./build/YourApp.ipa",
skip_waiting_for_build_processing: false,
distribute_external: true,
groups: ["Beta Testers"],
changelog: File.read("fastlane/metadata/ja/release_notes.txt"),
notify_external_testers: true
)
# Slack 通知
slack(
message: "✅ TestFlight ビルド #{version} (#{build_num}) をアップロードしました",
slack_url: ENV["SLACK_WEBHOOK_URL"],
success: true
)
end
desc "App Store に審査提出"
lane :release do |options|
version = options[:version]
# スクリーンショット撮影
snapshot
# App Store メタデータをアップロード
deliver(
submit_for_review: true,
automatic_release: false,
force: true,
skip_binary_upload: false,
metadata_path: "./fastlane/metadata",
screenshots_path: "./fastlane/screenshots"
)
puts "🚀 審査提出完了!通常 24〜48 時間でレビューが完了します。"
end
endこのFastlaneの設定により、ターミナルから fastlane beta または fastlane release を実行するだけで、ビルド〜TestFlight配布〜Slack通知が自動で完結します。
GitHub Actions との統合(完全な CI/CD パイプライン)
最後に、上記のすべてをGitHub Actions で自動実行するパイプラインを構築します。release/* ブランチへのプッシュで自動起動する設定です。
# .github/workflows/release.yml
name: Release Pipeline
on:
push:
branches:
- 'release/*'
workflow_dispatch:
inputs:
version:
description: 'リリースバージョン (例: 2.3.0)'
required: true
jobs:
release:
name: Build & Deploy to TestFlight
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # 全コミット履歴が必要(リリースノート生成のため)
- name: Set up Ruby & Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
- name: Install Python dependencies
run: pip install anthropic
- name: Extract version from branch name
id: version
run: |
BRANCH="${{ github.ref_name }}"
VERSION=$(echo "$BRANCH" | sed 's/release\///')
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Generate release notes with Claude AI
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
APP_VERSION: ${{ steps.version.outputs.version }}
APP_NAME: "YourApp"
run: python scripts/generate_release_notes.py
- name: Install certificates and provisioning profiles
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.IOS_P12_BASE64 }}
p12-password: ${{ secrets.IOS_P12_PASSWORD }}
- name: Run Fastlane beta lane
env:
APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}
APP_VERSION: ${{ steps.version.outputs.version }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
run: bundle exec fastlane betaこのワークフローを設定すると、release/v2.3.0 というブランチを push するだけで:
- Claude API がコミット履歴からリリースノートを日英で自動生成
- iOS アプリがビルドされ TestFlight にアップロード
- Slack にリリース通知が届く
というフローが全自動で実行されます。
よくあるエラーと対処法
実際の運用でよく遭遇するエラーと、その解決方法を紹介します。
No profiles for 'com.example.yourapp' were found
証明書またはプロビジョニングプロファイルの問題です。match コマンドでコード署名を一元管理することで解消できます。
fastlane match appstore --readonlyInvalid JWT token(App Store Connect API エラー)
APIキーの有効期限切れか、Issuer IDの誤りが原因です。ファイルパスと環境変数の内容を確認してください。p8 ファイルの改行コードが問題になることもあります。
# p8ファイルの読み込み時に改行を正規化
key_content = key_content.replace("\\n", "\n")Xcode simulator not found(snapshot エラー)
指定したシミュレータがインストールされていない場合です。xcrun simctl list で利用可能なシミュレータを確認し、Snapfile の devices に合わせて修正します。
Changelog is too long(TestFlight アップロードエラー)
TestFlight の what_to_test フィールドは 4,000 文字が上限です。Claude に渡すプロンプトで文字数制限を明示することで回避できます。
全体を振り返って
Claude Code と App Store Connect API、そして Fastlane を組み合わせることで、これまで数時間かかっていたリリース作業を大幅に短縮できます。特に効果が大きい点をまとめます。
リリースノートの AI 自動生成は、品質を保ちながら作業時間をほぼゼロにできる最も費用対効果の高い自動化です。コミット履歴を Claude API に渡すだけで、日英対応のユーザー向けリリースノートが数秒で生成されます。
スクリーンショットの自動撮影は、新機能追加のたびに発生する繰り返し作業を排除します。UI テストとして一度書いておけば、以後はコマンド一発で最新のスクリーンショットが全デバイス・全言語分自動生成されます。
GitHub Actions との統合により、ブランチ名の規則(release/v*)という単純なトリガーで全工程が自動実行されます。深夜のリリース作業や、タイムゾーンをまたいだ多言語対応も、自動化されていれば問題ありません。
自動化の恩恵を受けながら、アプリの本質的な価値——ユーザー体験の向上や新機能の開発——に集中できる時間を取り戻してください。
CI/CD と AI エージェントの統合という視点から、本記事の内容を補完する知見が得られるでしょう。