Rork Max でネイティブSwiftUIアプリを作り始めると、開発体験のよさに驚く一方で、あるタイミングで壁に当たります。
「毎回リリースのたびにXcodeを開いて、アーカイブして、App Store Connectにアップロードして……これって自動化できないんだろうか?」
実際、Rork Max のデフォルトの使い方では、リリース作業はほぼ手動です。プロンプトでコードを生成して、Xcodeでビルドして、TestFlightにアップロードして——慣れてくると逆にこのフローのもったいなさが見えてきます。
Xcode Cloud は、Apple がXcode/App Store Connectに組み込んだCI/CDサービスです。GitHub などのリポジトリと接続すれば、プルリクのオープン時に自動テストを走らせ、main へのマージで TestFlight に自動配布し、承認後に App Store へ自動提出する——そういったワークフローを、コードなしのUI設定だけで構築できます。
EAS Build(Expo/React Native向け)とは異なり、Xcode Cloud はネイティブSwiftプロジェクトに特化しているため、Rork Max の生成するSwiftUIコードと相性が抜群です。
Rork Max プロジェクトを Xcode Cloud に接続し、本番に耐えるCI/CDパイプラインを一から構築する手順を順を追って整理していきます。
Xcode Cloud とは(なぜ Rork Max と組み合わせるのか
Xcode Cloud は Apple が 2021年から提供するCI/CDプラットフォームです。App Store Connect の「Xcode Cloud」セクションから設定でき、月に25時間の無料枠(2026年時点)があります。個人開発規模のアプリなら、無料枠だけで十分に運用できます。
Rork Max との相性が特によい理由は、生成物の性質にあります。
Rork Max が出力するのは純粋な SwiftUI + Swift コードです。.xcodeproj ファイルと Swift ソースファイルで構成されており、Xcode Cloud はこの構造をそのままビルドできます。一方、React Native / Expo プロジェクト(通常の Rork の出力)に使う EAS Build は、SwiftUI ネイティブプロジェクトには対応していません。
また、Xcode Cloud は Apple のインフラ上で動くため、iOS シミュレーターや XCTest が素直に使える点も大きなメリットです。GitHub Actions + Fastlane という組み合わせでも同等のことは実現できますが、証明書の管理やシミュレーターの環境構築まで自分でやる必要があります。Xcode Cloud はそのあたりを Apple 側が面倒を見てくれます。
Xcode Cloud の基本概念を整理する
設定に入る前に、用語を把握しておきましょう。
Product(プロダクト): Xcode Cloud の管理単位。App Store Connect の 1 アプリに 1 プロダクトが対応します。
Workflow(ワークフロー): 「どのトリガーで、何を実行するか」を定義するCI/CD設定です。1プロダクトに複数のワークフローを作れます。たとえば「プルリク用テストワークフロー」と「main マージ後の TestFlight 配布ワークフロー」を別々に定義するといった使い方が一般的です。
Action(アクション): ワークフロー内で実行する処理の単位。Build(ビルドのみ)、Test(テスト実行)、Archive(配布用アーカイブ生成)、Analyze(静的解析)の 4 種類があります。
Start Condition(開始条件): ワークフローのトリガー。「特定のブランチへのプッシュ」「プルリクのオープン」「スケジュール」などを選べます。
[GitHub リポジトリ]
↓ プッシュ / プルリク
[Xcode Cloud: Start Condition 検知]
↓
[Xcode Cloud: Actions 実行]
Build → Test → Archive
↓
[TestFlight への自動配布]
↓(手動承認 or 自動)
[App Store 提出]
セットアップ ― Rork Max プロジェクトを Xcode Cloud に接続する
前提条件
- Rork Max から生成した
.xcodeprojプロジェクトが GitHub リポジトリにプッシュ済みであること - Apple Developer Program への加入(年間 12,800 円)
- App Store Connect へのアクセス権があること
Step 1: Xcode からプロダクトを作成する
Xcode で Rork Max 生成プロジェクトを開き、メニューから Product → Xcode Cloud → Create Workflow を選択します。
初回は App Store Connect への接続承認と、GitHub(または Bitbucket/GitLab)へのアクセス許可を求められます。OAuth フローで進むと、Xcode Cloud が自動的に対象リポジトリを検出します。
注意: Rork Max が生成するプロジェクトの場合、
.xcodeproj のバンドル ID が com.yourcompany.appname のように
プレースホルダーになっていることがあります。
App Store Connect に登録済みの Bundle ID と一致させてから
Xcode Cloud を設定してください。
Step 2: 初回ワークフローの設定
プロダクト作成後、ワークフロー設定画面が開きます。まず「プルリク用テストワークフロー」から作りましょう。
設定項目:
- Name:
Pull Request Tests - Start Condition: Branch Changes → Pull Request to
main - Environment: Xcode 15.x(最新安定版)、macOS Sonoma
- Actions:
Build― Debug 構成、iPhone シミュレーター向けTest― iPhone 15 シミュレーターで XCTest 実行
この設定で、main ブランチへのプルリクをオープンするたびに自動でビルドとテストが走るようになります。
自動テスト ― Rork Max 生成コードに XCTest を追加する
Rork Max は現状、XCTest ターゲットをデフォルトでは生成しません。テストターゲットは手動で追加する必要があります。
テストターゲットの追加
Xcode で File → New → Target → Unit Testing Bundle を選択し、ターゲット名を AppNameTests とします。
// AppNameTests.swift — まず最小限のテストから始める
import XCTest
@testable import AppName // Rork Max が生成したモジュール名に合わせる
final class AppNameTests: XCTestCase {
// ViewModel のロジックをテストする例
func testPriceCalculation() throws {
let cart = CartViewModel()
cart.addItem(price: 1000)
cart.addItem(price: 500)
XCTAssertEqual(cart.total, 1500)
XCTAssertEqual(cart.itemCount, 2)
}
// 日付フォーマットのユーティリティ関数をテストする例
func testDateFormatting() throws {
let formatter = AppDateFormatter()
let date = Date(timeIntervalSince1970: 1700000000) // 2023-11-15
let result = formatter.shortFormat(date)
XCTAssertFalse(result.isEmpty)
}
}Rork Max 生成コードのどこをテストするか
Rork Max が生成するコードの構造上、テストを書きやすい部分と書きにくい部分があります。
テストしやすい部分(優先的にカバーする):
- ViewModel のビジネスロジック
- ユーティリティ関数(日付変換・価格計算・バリデーション等)
- API レスポンスのパース処理
テストが難しい部分(UIテストで補う):
- SwiftUI の View 自体(宣言的UIは状態管理をテストするのが現実的)
- アニメーション・トランジション
UIテストの例:
// AppNameUITests.swift
import XCTest
final class AppNameUITests: XCTestCase {
let app = XCUIApplication()
override func setUpWithError() throws {
continueAfterFailure = false
app.launch()
}
// ログイン画面の基本操作テスト
func testLoginScreenExists() throws {
// Rork Max が生成するログイン画面のアクセシビリティ識別子で要素を探す
let emailField = app.textFields["emailTextField"]
let passwordField = app.secureTextFields["passwordTextField"]
let loginButton = app.buttons["loginButton"]
XCTAssertTrue(emailField.exists, "メールフィールドが見つかりません")
XCTAssertTrue(passwordField.exists, "パスワードフィールドが見つかりません")
XCTAssertTrue(loginButton.exists, "ログインボタンが見つかりません")
}
// ナビゲーションの基本フローテスト
func testNavigationToMainTab() throws {
// テスト用アカウントでログイン
let emailField = app.textFields["emailTextField"]
emailField.tap()
emailField.typeText("test@example.com")
let passwordField = app.secureTextFields["passwordTextField"]
passwordField.tap()
passwordField.typeText("testpassword123")
app.buttons["loginButton"].tap()
// メイン画面のタブバーが表示されることを確認
let tabBar = app.tabBars.firstMatch
XCTAssertTrue(tabBar.waitForExistence(timeout: 5))
}
}テストコードで accessibilityIdentifier を参照していますが、Rork Max 生成コードには最初から付いていないことが多いです。Xcode Cloud にテストを組み込む前に、主要なUI要素に .accessibilityIdentifier("xxx") モディファイアをプロンプトで追加してもらうか、手動で足しておくと UITest がはるかに書きやすくなります。
TestFlight への自動配布ワークフロー
テストワークフローが動いたら、次は TestFlight 自動配布ワークフロー を追加します。
App Store Connect の Xcode Cloud 画面で「+ New Workflow」をクリックし、以下を設定します。
設定項目:
- Name:
TestFlight Distribution - Start Condition: Branch Changes → Push to
main - Environment: Xcode 最新安定版、
CURRENT_PROJECT_VERSIONを自動インクリメント - Actions:
Test― 軽量なスモークテストのみ実行(時間短縮)Archive― Release 構成、Distribution 署名
ビルド番号の自動インクリメント設定:
Archive アクションの設定で「Increment Build Number」を有効にすると、Xcode Cloud がビルドするたびに CFBundleVersion(ビルド番号)を自動で増やします。CFBundleShortVersionString(バージョン番号、例: 1.2.0)は手動管理のままにするのが一般的です。
Post-Action(配布先の設定):
Archive アクションの後処理として、TestFlight の内部テスター or 外部テスターへの配布を指定できます。
内部テスター: Apple Developer Program のチームメンバー(最大 100 人)
→ App Store Connect のレビューなしで即配布
外部テスター: メール招待した最大 10,000 人
→ Apple の「ベータ版審査」(通常1〜2日)が必要
個人開発の場合は「内部テスター(自分のみ)」で十分です。main マージ後30〜40分で TestFlight に最新ビルドが届くようになります。
App Store 自動リリースの設定
最終段階として、TestFlight から App Store への提出も自動化できます。
Xcode Cloud の Archive アクションには「Distribute to App Store」オプションがあります。ただし、これは自動的に公開するのではなく、App Store Connect の審査キューに自動的に提出するものです。実際の公開は:
- 手動承認: App Store Connect で「このバージョンを公開」をタップ
- 自動公開: 審査通過後に自動公開(フェーズド・リリース設定可能)
どちらも選択できます。慎重にリリースしたい場合は手動承認、迅速さを優先するなら自動公開が適しています。
本番向けのフルワークフロー設定イメージ:
ブランチ戦略:
feature/* → プルリク → Pull Request Tests ワークフロー
main → マージ → TestFlight Distribution ワークフロー
release/* → プッシュ → App Store Submission ワークフロー
[App Store Submission ワークフロー設定]
Start Condition: Branch Changes → Push to release/*
Actions:
1. Test (Full Suite)
2. Archive (Release)
└─ Post-Action: Distribute to App Store
└─ Distribute to App Store Connect / TestFlight External Testers
release/* ブランチを作ってプッシュするだけで審査提出まで自動化できます。
シークレットと環境変数の管理
API キーや機密情報は絶対にリポジトリにコミットしないでください。Xcode Cloud では Environment Variables(環境変数) と Secrets で管理します。
App Store Connect の Xcode Cloud → Workflow → Environment Variables タブから設定できます。
// ci_scripts/ci_post_clone.sh
// Xcode Cloud がリポジトリをクローンした直後に実行するスクリプト
#!/bin/sh
# CI環境の確認
if [[ $CI_XCODE_CLOUD == "TRUE" ]]; then
echo "Xcode Cloud 環境を検出しました"
# Xcode Cloud の Environment Variables から値を取得
# CI_SUPABASE_URL は Xcode Cloud の管理画面で設定
echo "SUPABASE_URL=${CI_SUPABASE_URL}" >> .env
echo "SUPABASE_ANON_KEY=${CI_SUPABASE_ANON_KEY}" >> .env
fiXcode Cloud は ci_scripts/ ディレクトリに置いたシェルスクリプトを自動的に実行します:
ci_post_clone.sh― クローン直後(依存関係のインストール等)ci_pre_xcodebuild.sh― ビルド前(設定ファイルの生成等)ci_post_xcodebuild.sh― ビルド後(通知等)
よくある詰まりポイントと解決策
Rork Max プロジェクトを Xcode Cloud に接続して実際に動かすまでに、私が詰まったパターンをまとめます。
① プロビジョニングプロファイルが自動設定されない
症状: アーカイブ時に「No profiles for 'com.xxx.yyy' were found」エラーが出ます。
原因: App Store Connect にアプリの Bundle ID が登録されていない、または証明書が不正な状態になっています。
対処: Xcode Cloud が使う自動管理証明書を再生成します。Xcode → Preferences → Accounts → 対象チーム → Manage Certificates → Apple Distribution を「+」で追加します。Xcode Cloud は自動管理(Automatic Signing)をオンにしたプロジェクトに限り、証明書の管理を代行してくれます。
Rork Max 生成プロジェクトのデフォルト設定:
DEVELOPMENT_TEAM = "YOUR_TEAM_ID" ← ここにAppleのチームIDを設定
CODE_SIGN_STYLE = Automatic ← これが Xcode Cloud の自動管理に必要
② TestFlight にビルドは届くが内部テスターに通知が来ない
症状: Xcode Cloud のビルドは成功しているのに、TestFlight アプリにビルドが表示されません。
原因: App Store Connect で対象アプリの「TestFlight」→「内部テスト」グループにテスターが追加されていません。
対処: App Store Connect → TestFlight → 内部テスト → テスターとグループ → 自分のメールアドレスを追加するだけです。
③ ci_scripts が認識されない
症状: ci_post_clone.sh を置いても実行されません。
原因: ファイルのパーミッションが実行可能になっていない(chmod +x されていません)。
対処:
# リポジトリルートで実行
chmod +x ci_scripts/ci_post_clone.sh
git add ci_scripts/ci_post_clone.sh
git commit -m "Fix: ci_scripts executable permission"
git pushGit はファイルの実行権限を追跡するため、chmod +x した上でコミットし直す必要があります。
④ テストが途中でタイムアウトする
症状: UIテストが30分以上かかって Xcode Cloud 側でキャンセルされます。
原因: テストが特定の要素の表示を待ち続けて無限ループ状態になっています。
対処: waitForExistence(timeout:) に現実的な秒数を設定し、タイムアウト時に明示的に失敗させます。
// NG: デフォルトのタイムアウトは短すぎることがある
XCTAssertTrue(element.exists)
// OK: 明示的に待機時間を設定
XCTAssertTrue(element.waitForExistence(timeout: 10), "要素が10秒以内に表示されませんでした")全体を通じて感じたこと
Xcode Cloud を使い始めてまず感じたのは、「Apple のエコシステムで完結している安心感」でした。証明書の管理や iOS シミュレーターの準備を、ほぼ意識せずに済むのは確かにストレス軽減になります。
一方で、無料枠の25時間/月はUIテストを頻繁に走らせると意外とすぐ使い切ります。私のやり方では、プルリク用のテストワークフローは「ビルドが通るかどうか」だけを素早く確認するものに絞り、本格的なUIテストスイートは週次スケジュールで深夜に実行するようにしています。こうすることで、無料枠を超えずに運用できています。
Rork Max でネイティブアプリを本気で仕上げていくなら、Xcode Cloud は早いうちに導入する価値があります。リリース作業の自動化によって生まれた時間を、プロンプト設計やUI改善に使えるようになります。
Rork Max × Xcode 最適化ワークフローの詳細も合わせて読んでいただくと、生成後のコード改善と CI/CD の両輪が揃います。また、React Native / Expo ベースの Rork プロジェクトを CI/CD 化したい場合は、EAS Build × GitHub Actions によるCI/CDパイプラインが参考になります。