MacなしでReact NativeのiOSアプリをビルドする
React Nativeの作業の大半は、WindowsやLinuxで問題なく動きます。iOSのビルドは例外です。CocoaPodsとxcodebuildにはmacOSが必要なので、その1ステップのためだけにMacを借ります。以下は、それを行うGitHub Actionsのワークフローです。2026年10月2日に実行し、React Native 0.87.1をXcode 26.6でビルドできました。
WindowsとLinuxでできること
JavaScriptとTypeScriptのコード、Metro、Jestは、どのデスクトップでも動きます。当社のテストでは、作成したばかりのアプリが、GitHubのubuntu-24.04 runnerとwindows-2025 runnerの両方でJestのテストに通りました。どちらもNode 22を使いました。Androidアプリのビルドと実行も、どちらのOSでもできます。React Nativeのドキュメントには、WindowsとLinuxそれぞれのAndroidのセットアップ手順があります。
iOSについては、同じドキュメントがはっきり書いています。WindowsとLinuxのセットアップページには、iOS向けにネイティブコードを含むプロジェクトをビルドするにはMacが必要だとあります。代わりに勧めているのはExpo Goです。開発中に、実機のiPhoneでJavaScriptを動かせます。画面とロジックの確認はこれでできます。ただし、リリースできるアプリは作れません。
macOSが必要なもの
- pod install。iOSのプロジェクトは、React Nativeとそのネイティブ依存関係をCocoaPodsで取得します。このステップではCodegenも動きます。
- xcodebuild。XcodeとiOS SDKはmacOS向けにしかありません。AppleはXcodeのシステム要件のページで、Xcode 26.6にはmacOS Tahoe 26.2以降が必要としています。
- シミュレータ。Xcodeに含まれているので、これもMac専用です。
- 署名とアップロード。この部分はMacなしでiOSアプリを公開する方法で説明しています。
実際に動かしたワークフロー
reactnative.devに載っているコマンドで、新しいアプリを作ります。LinuxとWindowsでテストを実行します。そのあと、macos-26 runnerでiOSのビルドを行います。initのフラグはReact Native CLIのドキュメントに従いました。npmを選び、podの確認を飛ばし、gitの初期化を飛ばします。.github/workflows/rn-ios.ymlに置き、Actionsタブから実行してください。
name: rn-ios
on: workflow_dispatch
jobs:
test-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npx @react-native-community/cli@latest init RNDemo --pm npm --install-pods false --skip-git-init true
- run: npm test
working-directory: RNDemo
test-windows:
runs-on: windows-latest
steps:
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npx @react-native-community/cli@latest init RNDemo --pm npm --install-pods false --skip-git-init true
- run: npm test
working-directory: RNDemo
build-ios:
runs-on: macos-26
steps:
- uses: actions/setup-node@v7
with:
node-version: 22
- run: sudo xcode-select -s /Applications/Xcode_26.6.app
- run: xcodebuild -version && node -v && ruby -v
- run: npx @react-native-community/cli@latest init RNDemo --pm npm --install-pods false --skip-git-init true
- run: node -p "require('react-native/package.json').version"
working-directory: RNDemo
- run: bundle install
working-directory: RNDemo/ios
- run: bundle exec pod install
working-directory: RNDemo/ios
- name: Build for the iOS Simulator (Debug)
run: |
xcodebuild -workspace RNDemo.xcworkspace -scheme RNDemo \
-configuration Debug -sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath build build
working-directory: RNDemo/ios
- name: Build for the iOS Simulator (Release, JS bundled)
run: |
xcodebuild -workspace RNDemo.xcworkspace -scheme RNDemo \
-configuration Release -sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath build build
working-directory: RNDemo/ios
- run: ls -la build/Build/Products/Release-iphonesimulator/RNDemo.app/main.jsbundle && du -sh build/Build/Products/*-iphonesimulator/RNDemo.app
working-directory: RNDemo/iosご自身のリポジトリでは、initのステップを、コードのチェックアウトとパッケージのインストールに置き換えます。残りはそのままです。RNDemoは、ご自身のワークスペース名とスキーム名に変えてください。
実行時の出力
以下はbuild-iosジョブのログからコピーした行です。macOSのジョブ全体で2分42秒かかりました。
Xcode 26.6 Build version 17F113 v22.23.2 0.87.1 Pod install took 43 [s] to run Pod installation complete! There are 87 dependencies from the Podfile and 86 total pods installed. ** BUILD SUCCEEDED ** Welcome to Metro v0.87.1 ** BUILD SUCCEEDED ** -rw-r--r-- 1 runner staff 1268567 Oct 2 04:02 build/Build/Products/Release-iphonesimulator/RNDemo.app/main.jsbundle 154M build/Build/Products/Debug-iphonesimulator/RNDemo.app 38M build/Build/Products/Release-iphonesimulator/RNDemo.app
Debugビルドは約39秒、Releaseビルドは約35秒でした。速いのは、React Native 0.87がビルド済みのコアをダウンロードするからです。pod installのログにもそうはっきり出ていました。古いバージョンでは、ずっと多くのネイティブコードをコンパイルします。ビルドにはもっと時間がかかると考えてください。
なぜ2回ビルドするのでしょうか。Debugのアプリは、実行中にMetroからJavaScriptを読み込みます。Releaseビルドでは、JavaScriptがmain.jsbundleとしてアプリに詰め込まれます。今回は1.27 MBでした。Releaseビルドが通れば、バンドルとネイティブコードの両方がコンパイルできたことになります。
プルリクエストごとに実行する
上のワークフローは手動で実行するものです。マージ前にiOSの不具合を見つけるには、トリガーの行を変えて、プルリクエストでも実行されるようにします。
on: pull_request: workflow_dispatch:
ビルドが失敗すると、ログは長くなります。当社の場合、小さなビルド2回で18,000行を超えました。ログで「error:」を検索し、最初に見つかったものを読んでください。後のエラーは、多くが最初のエラーの副作用です。pod installが失敗した場合は、まずPodfileとネイティブの依存関係を確認してください。
費用
GitHubは各ジョブを分単位に切り上げて課金します。当社のmacOSジョブは3分になりました。2026年10月時点のGitHubのrunner料金表の単価は1分$0.062です。これで計算すると、約19セントです。パブリックリポジトリなら、標準のrunnerは無料です。週に数回のビルドなら、これがiOSのビルドを得る最も安い方法です。
Expoを使っているなら、別の方法もあります。EAS Buildは、ExpoのクラウドでiOSをコンパイルします。Freeプランには、優先度の低いキューで月15回のiOSビルドが含まれます。それを超えると、2026年10月時点のexpo.dev/pricingによれば、mediumのiOSビルドは1回$2です。
CIだけでは足りなくなるとき
CIのジョブで分かるのは、アプリがコンパイルできることです。アプリの画面は見られません。シミュレータ向けのビルドはiOSシミュレータでしか動かず、それにはMacの画面が必要です。iOSでだけネイティブモジュールが壊れたときは、Xcodeを開きたくなります。ブレークポイントと、クリックできるシミュレータが欲しくなります。その場合はWindowsからリモートのMacでXcodeを使う方法をご覧ください。
また、ホスト型のrunnerは毎回空の状態から始まります。実行のたびに、Nodeのパッケージ、gem、podを再びダウンロードします。当社の実行では、macOSのジョブにGitHubからの通知も付いていました。容量の制約により、macOSのarm64ジョブは待ち時間が長くなる場合があるという内容です。
この用途でMacを借りるべきでない人
ビルドが週に数回なら、ホスト型のrunnerかEASを使い続けてください。GitHubの基本料金で計算すると、専用のMacが元を取れるのは、macOSの利用が月に約2,242分を超えたあたりです。画面が必要な場合にも元が取れます。どちらにも当てはまらないなら、Macのレンタルは使う必要のないお金です。
その境目を超えるなら、同じワークフローをセルフホストのmacOS runnerで動かせます。runs-onを変更し、xcode-selectでご自身のXcodeを指定します。podとDerivedDataは実行の間もウォーム状態のまま残ります。M6のプランは料金ページをご覧ください。
よくある質問
WindowsでReact NativeのiOSアプリをビルドできますか?
+
Windowsで書いてテストすることはできますが、iOSのビルドにはmacOSが必要です。React Nativeのドキュメントには、iOS向けにネイティブコードを含むプロジェクトをビルドするにはMacが必要だとあります。そのステップは、クラウドのMacかCIのrunnerでまかなえます。
WindowsでiOSシミュレータを動かせますか?
+
いいえ。シミュレータはXcodeに含まれていて、XcodeはmacOSでしか動きません。リモートデスクトップでリモートのMacのシミュレータを見るか、開発中は実機のiPhoneでExpo Goを使ってください。
GitHub ActionsでのReact NativeのiOSビルドにはどのくらいかかりますか?
+
2026年10月の当社の実行では、新規のReact Native 0.87.1アプリで、macOSのジョブ全体が2分42秒でした。これにはpod installと、DebugとReleaseのシミュレータ向けビルドが含まれます。大きなアプリでは、もっと時間がかかります。
シミュレータ向けのビルドにApple Developerアカウントは必要ですか?
+
いいえ。当社のワークフローは、署名なしでシミュレータ向けにビルドしました。実機、TestFlight、App Store向けにアプリへ署名するには、有料のApple Developer Programが必要です。