Uno script per pubblicare automaticamente su AppStore senza passare per Xcode
Odio le azioni lunghe e ripetitive quindi odio pubblicare app sullo Store di Apple.
Perchè? Te lo spiego subito…
Sviluppo principalmente app cross platform con Flutter e non uso Xcode ma Android Studio.
Fino ad oggi, ogni volta per pubblicare una build dovevo:
- pulire il progetto flutter
- aggiornare le dipendenze flutter
- se avevo installato librerie che richiedevano l’aggiornamento del progetto Apple lanciare anche:
pod install - poi aprire il progetto in Xcode
- lanciare la build
- attendere
- creare l’archivio
- attendere
- caricare l’archivio su App Store Connect
- attendere
- cliccare su “Finisci”
E se mi distraevo tra un click e l’altro (ahimè cosa per niente lontana dalla realtà 🥲) ecco che ci mettevo un’ora solo per completare la pubblicazione.
Di recente sto rilasciando aggiornamenti frequenti su un’app al quale sto lavorando e dopo un mese di sviluppo ero davvero stanco di questa situazione! Dovevo fare qualcosa per velocizzare questo processo o sarei impazzito.
Dopo un po' di ricerche su Google, StackOverflow e GitHub ho trovato il modo per creare un’automazione e consentirmi di buildare e pubblicare su App Store tutto in un solo colpo.
Prima di vedere il codice e come lavora devi però creare un key per autorizzare il tuo Mac a inviare la build all’App Store Connect.
Creazione della chiave API

Apri App Store Connect:
- Dal menù in alto clicca su “Utenti e accessi”
- Clicca sulla tab “Integrazioni”
- Seleziona dal pannello laterale “API di App Store Connect”
- Clicca infine sul “+”
Inserisci un nome identificativo della chiave e assicurati di selezionare nel campo “Accesso” il valore “Gestore dell’app” o “Amministrazione” altrimenti la chiave non avrà abbastanza permessi per inviare la build.

Attenzione: scarica la chiave subito dopo averla creata.
È l’unica occasione che avrai per scaricare il file. Il file della chiave ha estensione .p8.
Ti serviranno anche i codici ID CHIAVE e Issuer ID presenti in questa sezione.
Nella root del tuo progetto ora crea la cartella private_keys e inseriscila subito nel file .gitignore,
non inserire mai chiavi o secret su git. Copia al suo interno la chiave generata al punto precedente.
Vediamo il codice
Ho creato un gist su GitHub con il codice completo.
Per funzionare correttamente devi sostituire le seguenti variabili:
KEY_ID: imposta il valore del campo ID CHIAVEISSUER_ID: imposta il valore del campo Issuer ID
Metti una stellina al gist se ti è stato di aiuto ❤️

Passiamo all’azione
Se lanci lo script ./build_ios.sh questo è più o meno l’output che ti dovresti aspettare:
./build_ios.sh
🧹 Pulisco il progetto...
Cleaning Xcode workspace... 5,8s
Deleting build... 827ms
Deleting .dart_tool... 23ms
Deleting ephemeral... 0ms
Deleting Generated.xcconfig... 0ms
Deleting flutter_export_environment.sh... 0ms
Deleting Flutter.podspec... 0ms
Deleting .flutter-plugins-dependencies... 0ms
🏛️ Eseguo la build dell'IPA...
Resolving dependencies... (2.7s)
Downloading packages...
_fe_analyzer_shared 88.0.0 (92.0.0 available)
analyzer 8.1.1 (9.0.0 available)
archive 4.0.2 (4.0.7 available)
...
< cutted >
...
xml 6.5.0 (6.6.1 available)
Got dependencies!
87 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.
Archiving < your package name >...
Automatically signing iOS for device deployment using specified development team in Xcode project: 22W4NC5C8V
Running pod install... 5,5s
Running Xcode build...
Xcode archive done. 212,2s
✓ Built build/ios/archive/Runner.xcarchive (236.6MB)
[✓] App Settings Validation
• Version Number: 1.0.25
• Build Number: 25
• Display Name: < your app name >
• Deployment Target: 13.0
• Bundle Identifier: < your package name >
Building App Store IPA... 38,8s
✓ Built IPA to build/ios/ipa (39.6MB)
To upload to the App Store either:
1. Drag and drop the "build/ios/ipa/*.ipa" bundle into the Apple Transporter macOS app https://apps.apple.com/us/app/transporter/id1450874784
2. Run "xcrun altool --upload-app --type ios -f build/ios/ipa/*.ipa --apiKey your_api_key --apiIssuer your_issuer_id".
See "man altool" for details about how to authenticate with the App Store Connect API key.
🚀 Caricamento su App Store Connect...
Running altool at path '/Applications/Xcode.app/Contents/SharedFrameworks/ContentDelivery.framework/Resources/altool'...
2025-11-19 17:17:44.447 INFO: [ContentDelivery.Uploader.600000438040]
==========================================
UPLOAD SUCCEEDED with no errors
Delivery UUID: < your delivery uuid >
Transferred 38728882 bytes in 14.892 seconds (2.6MB/s, 20.806Mbps)
==========================================
No errors uploading archive at 'build/ios/ipa/< app name >.ipa'.
✅ Caricamento completato.
Ho censurato un po' di informazioni sensibili dal log e ho sfoltito un po' le porzioni inutilmente verbose.
Appena è finita l’esecuzione dello script puoi andare immediatamente su App Store Connect e troverai la build pronta ad aspettarti 😃
Non è bellissimo? Non devi fare altri click e nel mentre che lui lavora puoi prenderti una pausa.
E per Android?
Non ho ancora sviluppato nulla di totalmente automatico per Android, perchè la procedura di pubblicazione su Play Store è molto più snella di quella su App Store.
Però ho ugualmente scritto una piccola automazione per facilitarmi giusto qualcosina.
In questo scenario quello che mi dava più fastidio è che dopo aver compilato l’app dovevo
aprire manualmente la cartella build/app/outputs/bundle/release/
e trovare il file app-release.aab da caricare sullo store.
Ho fatto in modo che su Mac mi apre automaticamente il finder direttamente in quel path.
Attenzione: il tutto funziona solo se lanci ./build_android.sh dalla root del progetto
(perchè il path è relativo) ma se hai esigenze particolari puoi aggiornare il path mettendo quello assoluto (linea 14).
Trovi qui il link al gist, ricordati sempre la stellina se ti è stato utile ❤️
Passiamo di nuovo all’azione
./build_android.sh
🧹 Pulisco il progetto...
Cleaning Xcode workspace... 5,4s
Deleting build... 1.149ms
Deleting .dart_tool... 18ms
Deleting ephemeral... 0ms
Deleting Generated.xcconfig... 0ms
Deleting flutter_export_environment.sh... 0ms
Deleting Flutter.podspec... 0ms
Deleting .flutter-plugins-dependencies... 0ms
🏛️ Eseguo la build dell'Appbundle...
Resolving dependencies...
Downloading packages...
_fe_analyzer_shared 88.0.0 (92.0.0 available)
analyzer 8.1.1 (9.0.0 available)
archive 4.0.2 (4.0.7 available)
...
< cutted >
...
xml 6.5.0 (6.6.1 available)
Got dependencies!
87 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.
Running Gradle task 'bundleRelease'... 72,4s
✓ Built build/app/outputs/bundle/release/app-release.aab (83.2MB)
🚀 Sei pronto per caricare il bundle su Play Store.
Potenzialmente questi script che ho scritto potrebbero essere utilizzati anche in una pipeline su GitHub Actions o GitLab CI con pochissime modifiche, ci stavo già lavorando infatti, ma poi ho temporaneamente messo da parte questa ulteriore automazione per dedicarmi ad altro.
Sei riuscito ad utilizzare i miei script?
Raccontami nei commenti come è andata e se ho velocizzato anche il tuo workflow.
Se preferisci un contatto più diretto puoi raggiungermi nel canale Telegram
Immagine di copertina generata con 🍌 Nano Banana.
AP
