Mettre en place la CI/CD iOS sur GitHub Actions de zéro
Voici tout le pipeline d’une app iOS sur GitHub Actions, dans l’ordre où vous le construisez. D’abord compiler et tester. Puis la signature. Puis l’archivage et l’envoi. Chaque étape est courte et le YAML est prêt à copier. Il fonctionne sur les runners hébergés par GitHub et sur un Mac dédié. La seule ligne qui change est runs-on.
1. Le squelette
name: ios
on:
pull_request:
push:
branches: [main]
concurrency:
group: ios-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: macos-latest # or [self-hosted, macOS, your-label]
timeout-minutes: 30
steps:
- uses: actions/checkout@v42. Choisissez le Xcode
Les images hébergées livrent plusieurs versions de Xcode. Choisissez-en une explicitement, pour qu’une mise à jour d’image ne change pas votre build sans prévenir :
- run: sudo xcode-select -s /Applications/Xcode_26.6.app
- run: xcodebuild -versionSur un Mac dédié, la version est figée une fois sur la machine, et cette étape disparaît.
3. Les dépendances
- uses: actions/cache@v4
with:
path: |
~/Library/Caches/org.swift.swiftpm
Pods
key: ${{ runner.os }}-deps-${{ hashFiles('**/Package.resolved', '**/Podfile.lock') }}
- run: pod install --repo-update # CocoaPods projects only4. Compiler et tester sur un simulateur
- run: |
xcodebuild test \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 17' \
-resultBundlePath TestResults \
| xcpretty
- uses: actions/upload-artifact@v4
if: failure()
with: { name: test-results, path: TestResults }Arrêtez-vous ici pour les pull requests. Tout ce qui suit relève de la release et n’a sa place que sur main.
5. La signature de code sans session Mac partagée
Utilisez une clé API App Store Connect plutôt qu’un identifiant Apple. Stockez l’ID de la clé, l’ID de l’émetteur et le contenu du fichier .p8 comme secrets du dépôt. Laissez ensuite xcodebuild signer avec des profils gérés dans le cloud :
- run: echo "${{ secrets.ASC_KEY_P8 }}" > AuthKey.p8
- run: |
xcodebuild archive \
-scheme MyApp -configuration Release \
-archivePath build/MyApp.xcarchive \
-allowProvisioningUpdates \
-authenticationKeyPath "$PWD/AuthKey.p8" \
-authenticationKeyID "${{ secrets.ASC_KEY_ID }}" \
-authenticationKeyIssuerID "${{ secrets.ASC_ISSUER_ID }}"6. Exporter et envoyer sur TestFlight
- run: |
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportPath build/export \
-exportOptionsPlist ExportOptions.plist \
-allowProvisioningUpdates \
-authenticationKeyPath "$PWD/AuthKey.p8" \
-authenticationKeyID "${{ secrets.ASC_KEY_ID }}" \
-authenticationKeyIssuerID "${{ secrets.ASC_ISSUER_ID }}"
- run: |
xcrun altool --upload-app -f build/export/MyApp.ipa -t ios \
--apiKey "${{ secrets.ASC_KEY_ID }}" --apiIssuer "${{ secrets.ASC_ISSUER_ID }}"Beaucoup d’équipes enveloppent les étapes 5 et 6 dans fastlane. Les commandes sous-jacentes sont les mêmes.
7. Où partent les minutes, et le choix du runner
Sur un runner hébergé, les étapes 2 et 3 se répètent à chaque job et sont facturées environ $0.062 à $0.102 la minute. Sur un Mac dédié, elles ont lieu une fois et les caches restent chauds. C’est pourquoi les équipes qui dépassent environ 2,242 minutes par mois passent tout le pipeline sur une machine à prix fixe. Elles ne changent que la ligne runs-on. Le guide du pipeline sur matériel dédié couvre cet aspect.
Questions fréquentes
Ai-je besoin d’un Mac pour faire de la CI iOS sur GitHub Actions ?
+
Oui. Compiler et signer des apps iOS demande Xcode, qui ne tourne que sur macOS. Le job de build a donc besoin d’un runner macOS, hébergé par GitHub ou sur un Mac que vous contrôlez.
Comment signer une app iOS en CI sans mon identifiant Apple ?
+
Créez une clé API App Store Connect. Stockez son ID, l’ID de l’émetteur et le contenu du .p8 comme secrets, et passez-les à xcodebuild avec -allowProvisioningUpdates. Aucun identifiant Apple ni mot de passe de trousseau n’est nécessaire sur le runner.
Les tests doivent-ils tourner sur chaque pull request ?
+
Compilez et testez sur chaque pull request, sur un seul simulateur. Gardez l’archivage, la signature et l’envoi sur TestFlight pour main uniquement. Ce sont les étapes lentes et coûteuses.
Qu’est-ce qui change quand je passe ce pipeline sur un Mac dédié ?
+
La ligne runs-on. Le choix de Xcode et le cache des dépendances deviennent inutiles, car la machine les garde entre les jobs. Et aucune file d’attente ne précède le build.