Compilare un’app React Native per iOS senza Mac
Quasi tutto il lavoro con React Native gira bene su Windows o Linux. La build iOS no. CocoaPods e xcodebuild richiedono macOS, quindi per quel solo passaggio ti serve un Mac in prestito. Qui sotto c’è un workflow GitHub Actions che lo fa. L’abbiamo eseguito il 2 ottobre 2026, e ha compilato React Native 0.87.1 con Xcode 26.6.
Cosa funziona su Windows e Linux
Il tuo codice JavaScript e TypeScript, Metro e Jest girano su qualsiasi desktop. Nel nostro test, un’app appena creata ha passato il suo test Jest sul runner ubuntu-24.04 di GitHub e sul suo runner windows-2025. Entrambi usavano Node 22. Puoi anche compilare e avviare l’app Android su tutti e due i sistemi. La documentazione di React Native spiega il setup Android per Windows e per Linux.
Per iOS, la stessa documentazione è netta. Nelle pagine di setup per Windows e Linux dice che serve un Mac per compilare progetti con codice nativo per iOS. Suggerisce Expo Go, che esegue il tuo JavaScript su un iPhone vero durante lo sviluppo. Copre schermate e logica. Non produce un’app che puoi pubblicare.
Cosa richiede macOS
- pod install. Il progetto iOS scarica React Native e le sue dipendenze native tramite CocoaPods. In questo passaggio gira anche il Codegen.
- xcodebuild. Xcode e l’SDK iOS esistono solo per macOS. Nella pagina dei requisiti di sistema di Xcode, Apple indica macOS Tahoe 26.2 o successivo per Xcode 26.6.
- Il simulatore. È incluso in Xcode, quindi anche lui esiste solo su Mac.
- Firma e upload. Questa parte è spiegata in pubblicare un’app iOS senza Mac.
Il workflow che abbiamo eseguito
Crea una nuova app con il comando di reactnative.dev. Esegue i test su Linux e Windows. Poi compila per iOS su un runner macos-26. I flag di init vengono dalla documentazione della CLI di React Native. Scelgono npm, saltano la domanda sui pod e saltano il setup di git. Mettilo in .github/workflows/rn-ios.yml e avvialo dalla scheda 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/iosNel tuo repository, sostituisci il passaggio di init con un checkout del tuo codice e l’installazione dei suoi pacchetti. Il resto non cambia. Sostituisci RNDemo con il nome del tuo workspace e del tuo scheme.
Cosa ha stampato l’esecuzione
Queste righe sono copiate dal log del job build-ios. L’intero job macOS è durato 2 minuti e 42 secondi.
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
La build Debug ha richiesto circa 39 secondi e quella Release circa 35. È veloce perché React Native 0.87 scarica un core già compilato. Il log di pod install lo diceva chiaramente. Le versioni più vecchie compilano molto più codice nativo, quindi lì aspettati build più lunghe.
Perché compilare due volte? Un’app Debug carica il suo JavaScript da Metro mentre gira. La build Release impacchetta il JavaScript nell’app come main.jsbundle, qui da 1,27 MB. Se la build Release passa, compilano sia il bundle sia il codice nativo.
Eseguilo su ogni pull request
Il workflow qui sopra si avvia a mano. Per intercettare i problemi su iOS prima del merge, cambia la riga del trigger, così gira anche sulle pull request:
on: pull_request: workflow_dispatch:
Quando una build fallisce, il log è lungo. Il nostro ha superato le 18.000 righe per due build piccole. Cerca "error:" nel log e leggi il primo risultato. Gli errori successivi sono spesso effetti collaterali del primo. Se fallisce pod install, guarda prima il Podfile e le tue dipendenze native.
Quanto costa
GitHub fattura ogni job arrotondando al minuto superiore. Il nostro job macOS è stato di 3 minuti. A $0.062 al minuto, la tariffa nel listino dei runner di GitHub a ottobre 2026, fanno circa 19 centesimi. I repository pubblici non pagano nulla per i runner standard. Per qualche build a settimana, è il modo più economico di avere una build iOS.
Con Expo c’è un’altra strada. EAS Build compila per iOS nel cloud di Expo. Il piano Free include 15 build iOS al mese in una coda a bassa priorità. Dopo, una build iOS media costa $2, secondo expo.dev/pricing a ottobre 2026.
Quando la CI non basta più
Un job di CI dimostra che l’app compila. Non può mostrarti l’app. Una build per il simulatore gira solo nel simulatore iOS, che ha bisogno dello schermo di un Mac. Quando un modulo nativo si rompe solo su iOS, vuoi Xcode aperto. Vuoi i breakpoint e un simulatore su cui cliccare. Per questo, leggi usare Xcode da Windows con un Mac remoto.
Inoltre il runner in hosting parte ogni volta vuoto. Ogni esecuzione scarica di nuovo pacchetti Node, gem e pod. Nella nostra esecuzione il job macOS aveva anche un avviso di GitHub. Diceva che i job macOS arm64 possono restare in coda più a lungo per limiti di capacità.
Chi non dovrebbe noleggiare un Mac per questo
Se compili qualche volta a settimana, resta sui runner in hosting o su EAS. Un Mac dedicato conviene da circa 2,242 minuti macOS al mese, alla tariffa base di GitHub. Conviene anche quando ti serve lo schermo. Se nessuna delle due cose è vera, un Mac a noleggio è una spesa che non ti serve.
Se superi quella soglia, lo stesso workflow gira su un runner macOS self-hosted. Cambia runs-on e punta xcode-select al tuo Xcode. Pod e derived data restano caldi tra un’esecuzione e l’altra. Vedi i prezzi per i piani M6.
Domande frequenti
Posso compilare un’app React Native per iOS su Windows?
+
Puoi scriverla e testarla su Windows, ma la build iOS richiede macOS. La documentazione di React Native dice che serve un Mac per compilare progetti con codice nativo per iOS. Un Mac in cloud o un runner di CI coprono quel passaggio.
Posso usare il simulatore iOS su Windows?
+
No. Il simulatore è incluso in Xcode, che gira solo su macOS. Puoi vedere il simulatore di un Mac remoto tramite un desktop remoto, oppure usare Expo Go su un iPhone vero durante lo sviluppo.
Quanto dura una build iOS di React Native su GitHub Actions?
+
Nella nostra esecuzione di ottobre 2026, una nuova app React Native 0.87.1 ha richiesto 2 minuti e 42 secondi per l’intero job macOS. Il tempo include pod install e due build per il simulatore, una Debug e una Release. Le app più grandi richiedono più tempo.
Mi serve un account Apple Developer per compilare per il simulatore?
+
No. Il nostro workflow ha compilato per il simulatore senza alcuna firma. Il programma Apple Developer a pagamento serve per firmare l’app per un dispositivo, per TestFlight o per l’App Store.