Fastlane: Make and Ship App Store Screenshots (2026 Guide)
fastlane est une chaîne d'outils Ruby destinée à automatiser les tâches fastidieuses de publication d'applications iOS et Android. Ses trois actions dédiées aux captures d'écran — snapshot, frameit et deliver — couvrent l'intégralité du pipeline : pilotez votre application au sein d'un test XCUITest pour capturer les images brutes, intégrez-les dans des cadres d'appareils avec des textes marketing, et envoyez le résultat sur App Store Connect. Ce guide détaille ce pipeline de bout en bout avec les fichiers de configuration, les définitions de lanes (chemins) et le workflow de CI dont vous avez besoin.
À la fin, vous disposerez de : une configuration Ruby verrouillée avec Bundler, une clé d'API App Store Connect, un fichier Snapfile et un script SnapshotHelper.swift fonctionnels, un fichier Framefile.json contenant les mots-clés et titres par capture d'écran, un fichier Deliverfile optimisé pour les envois exclusifs de captures d'écran, un fichier Fastfile à quatre lanes et un workflow GitHub Actions pour exécuter l'ensemble sur un runner macos-26.
1. Prérequis et modèle mental
Avant d'installer Ruby, clarifions le schéma conceptuel. Le pipeline de captures d'écran se compose de trois étapes indépendantes, chacune gérée par une action fastlane distincte :
- Capture — un test XCUITest s'exécute sur un simulateur et appelle
snapshot("01-Home")aux moments clés que vous souhaitez enregistrer. L'actionsnapshotde fastlane démarre les simulateurs requis, bascule chacun d'eux sur la bonne locale, lance le test et place les PNG générés dans le dossierfastlane/screenshots/<locale>/. - Habillage —
frameitlit chaque fichier PNG, choisit un cadre d'appareil en fonction de la résolution de l'image, ajoute éventuellement un fond d'écran et un titre marketing, puis génère un fichier_framed.pngà côté de l'original. - Envoi —
deliverparcourt le dossier de captures d'écran, associe chaque image à une famille d'affichage App Store Connect (par exemple, iPhone 6,9", iPad 13") et remplace le jeu de captures d'écran sur la version éditable de l'App Store via l'API App Store Connect.
Chaque étape peut être exécutée indépendamment. Vous pouvez réaliser des captures d'écran sans les envoyer, habiller des captures produites par un autre outil ou envoyer des captures pré-générées sans jamais faire appel au simulateur.
2. Installer fastlane proprement : Bundler
N'utilisez pas brew install fastlane. Verrouillez la version de fastlane par projet avec Bundler afin que chaque machine qui construit votre projet (votre ordinateur, celui d'un collègue, la CI) exécute la même version. Depuis la racine du projet :
# system Ruby on macOS 14+ is fine, but rbenv/asdf is cleaner
gem install bundler
bundle init
echo 'gem "fastlane"' >> Gemfile
bundle install --path vendor/bundle
# from now on, run fastlane via:
bundle exec fastlane <lane>Validez Gemfile et Gemfile.lock dans Git. Ajoutez vendor/bundle à votre fichier .gitignore. Initialisez ensuite fastlane dans le projet :
bundle exec fastlane init
# choose option 4: "Manual setup"Cela crée un dossier fastlane/ contenant Fastfile and Appfile. Renseignez votre identifiant de bundle et votre identifiant d'équipe dans le fichier Appfile :
# fastlane/Appfile
app_identifier("com.example.myapp")
apple_id("[email protected]") # only needed if you fall back to legacy auth
team_id("ABCDE12345") # Developer Portal team ID3. La clé d'API App Store Connect
L'authentification par identifiant/mot de passe est obsolète pour les nouveaux comptes et protégée par la double authentification pour les autres, ce qui la rend inutilisable en CI. Utilisez plutôt une clé d'API App Store Connect . Dans App Store Connect → Utilisateurs et accès → Intégrations → Clé d'API App Store Connect :
- Générer une clé d'API (cette opération ne s'effectue qu'une seule fois par équipe ; les fichiers
.p8perdus ne peuvent pas être téléchargés de nouveau). - Attribuez-lui le rôle de Gestionnaire d'apps. Le rôle de Développeur est insuffisant pour envoyer des captures d'écran ; le rôle d'Administrateur est supérieur à vos besoins.
- Notez l'Identifiant de clé (10 caractères, par exemple
ABCD1234EF) et l'Identifiant de l'émetteur de l'équipe (l'UUID situé en haut de la même page). - Téléchargez le fichier
AuthKey_ABCD1234EF.p8.
fastlane lit la clé à partir d'un fichier JSON. Enregistrez-le sous le nom fastlane/asc_api_key.json (et ajoutez ce chemin à votre .gitignore) :
// fastlane/asc_api_key.json
{
"key_id": "ABCD1234EF",
"issuer_id": "57246542-96fe-1a63-e053-0824d011072a",
"key": "-----BEGIN PRIVATE KEY-----\nMIGTAg...truncated...A==\n-----END PRIVATE KEY-----",
"duration": 1200,
"in_house": false
}duration correspond à la durée de validité de chaque jeton JWT généré (en secondes) ; le maximum accepté par Apple est 1200 (20 minutes). Le champ key contient l'intégralité du fichier .p8, y compris les lignes BEGIN/END PRIVATE KEY, avec des \n littéraux pour les sauts de ligne.
En CI, n'ajoutez jamais ce fichier JSON au dépôt. Enregistrez le contenu du JSON sous forme de secret unique (par exemple ASC_API_KEY_JSON) et générez le fichier à la volée lors de l'exécution — vous trouverez un exemple dans la section GitHub Actions ci-dessous.
4. snapshot — Capturer des captures d'écran avec XCUITest
snapshot fonctionne en injectant un petit utilitaire Swift dans votre cible de test d'interface utilisateur (UI). Cet utilitaire s'intègre au moteur de test de sorte que chaque appel à snapshot("nom") depuis votre test réalise une capture d'écran du simulateur, la nomme et l'enregistre dans un dossier que fastlane sait localiser.
Générer l'utilitaire de capture
bundle exec fastlane snapshot initCela crée les fichiers fastlane/Snapfile et fastlane/SnapshotHelper.swift. Ajoutez le fichier SnapshotHelper.swift à votre cible de test d'interface utilisateur dans Xcode (glissez-déposez le fichier et assurez-vous que seul "MyAppUITests" est coché comme cible — ne l'incluez jamais dans le binaire final de l'application).
Snapfile
Le fichier Snapfile indique à snapshot quels appareils démarrer, dans quelles locales exécuter chaque test et quel schéma de test d'interface utilisateur appeler :
# fastlane/Snapfile
devices([
"iPhone 17 Pro Max", # 6.9" -> 1320 x 2868 (required slot in 2026)
"iPhone 17 Pro", # 6.3" -> 1206 x 2622 (optional, nicer in store listings)
"iPad Pro 13-inch (M4)", # 13" -> 2064 x 2752 (required if you ship an iPad build)
])
languages([
"en-US",
"de-DE",
"fr-FR",
"es-ES",
"ja",
])
scheme("MyAppUITests") # the UI-testing scheme that runs Snapshot tests
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)
override_status_bar(true) # 9:41, full battery, full signal
concurrent_simulators(true)
stop_after_first_error(true)
number_of_retries(1)Points clés :
devices— les noms doivent correspondre exactement à ce que renvoie la commandexcrun simctl list devices. Apple modifie ces noms chaque année (par exemple, "iPhone 17 Pro Max" a remplacé "iPhone 16 Pro Max"). Si le nom d'un appareil est incorrect, snapshot l'ignorera sans message d'erreur.languages— transmettez soit un code de région complet comme"en-US", soit un code de langue simple comme"ja". Chaque entrée génère un sous-dossier dansoutput_directory.override_status_bar(true)— utilise la commandesimctl status_bar overridepour afficher 9:41, une batterie pleine et un signal réseau/Wi-Fi maximal sur chaque capture d'écran. Apple ne l'exige pas formellement, mais la plupart des validateurs s'y attendent.concurrent_simulators— lance plusieurs simulateurs en parallèle. Cela réduit le temps d'exécution global proportionnellement au nombre d'appareils, mais chaque simulateur consomme environ 3 Go de RAM, ce qui s'avère lourd pour les serveurs de CI limités.clear_previous_screenshots— supprime le dossierfastlane/screenshots/<locale>/avant chaque exécution. Sans cette option, les captures d'écran obsolètes issues de tests supprimés s'accumuleraient indéfiniment.
Intégrer snapshot dans votre test XCUITest
SnapshotHelper expose deux fonctions globales : setupSnapshot(_:) (à appeler une fois par test) et snapshot(_:) (à appeler dès que vous souhaitez enregistrer un écran).
// MyAppUITests/MyAppUITests.swift
import XCTest
final class MyAppUITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
let app = XCUIApplication()
setupSnapshot(app) // injects the locale + screenshot bridge
app.launchArguments += [
"-UITests",
"-AppleLanguages", "(\(Snapshot.deviceLanguage))",
"-AppleLocale", Snapshot.currentLocale,
]
app.launch()
}
func testScreenshots() {
let app = XCUIApplication()
snapshot("01-Home") // tap pattern: drive UI, then snapshot
app.tabBars.buttons["Library"].tap()
snapshot("02-Library")
app.cells.element(boundBy: 0).tap()
snapshot("03-Detail")
app.navigationBars.buttons.element(boundBy: 0).tap()
app.tabBars.buttons["Settings"].tap()
snapshot("04-Settings")
}
}Quelques conseils pratiques :
- Transmettez l'argument de lancement
-UITestset détectez-le dans votre application pour désactiver les outils d'analyse, injecter des données déterministes, ignorer les écrans d'accueil ou simuler les appels réseau. Les validateurs (et vous-même plus tard) vous en remercieront. - L'appel à
snapshotest bloquant jusqu'à la fin de la capture d'écran, vous pouvez donc enchaîner immédiatement sur l'interaction suivante. - Si l'interface contient des animations, ajoutez
UIView.setAnimationsEnabled(false)via un argument de lancement. Capturer une image en pleine animation produit des visuels flous. - Nommez vos captures avec un préfixe numérique (
01-,02-) pour que l'ordre des fichiers corresponde à l'ordre d'affichage dans App Store Connect. L'outildeliverles envoie dans l'ordre alphabétique.
Lancer snapshot
bundle exec fastlane snapshot
# or, equivalently, in a Fastfile lane:
# capture_ios_screenshotsLes captures sont générées dans fastlane/screenshots/<locale>/iPhone 17 Pro Max-01-Home.png et consorts. Snapshot produit également un fichier screenshots.html — ouvrez-le pour visualiser toutes les locales et tous les appareils sur une seule page.
5. frameit — Ajouter des cadres d'appareils et des titres
Les captures d'écran brutes ne montrent que l'écran de l'appareil. frameit les intègre dans des cadres d'appareils physiques, ajoute éventuellement un fond d'écran, un titre promotionnel et un libellé de « mot-clé » plus petit juste au-dessus.
# Download device frames once (cached under ~/.frameit/)
bundle exec fastlane frameit download_frames
# Frame everything in fastlane/screenshots, including subfolders
bundle exec fastlane frameit --use_platform IOSPour chaque fichier foo.png de l'arborescence, frameit génère un fichier foo_framed.png à côté. Les originaux sont conservés ; deliver sélectionne automatiquement la version habillée lorsqu'elle existe (et se rabat sur la version brute sinon).
Framefile.json
Les cadres par défaut ressemblent à des captures de test de développement — cadre noir, sans fond ni texte. Personnalisez-les avec le fichier fastlane/screenshots/Framefile.json :
// fastlane/screenshots/Framefile.json
{
"device_frame_version": "latest",
"default": {
"keyword": {
"font": "./fonts/Inter-SemiBold.ttf",
"color": "#FFFFFF",
"padding": 50
},
"title": {
"font": "./fonts/Inter-Bold.ttf",
"color": "#FFFFFF"
},
"background": "./background.png",
"padding": 80,
"show_complete_frame": false,
"title_below_image": false,
"stack_title": true
},
"data": [
{
"filter": "Home",
"keyword": { "color": "#9F7AEA" },
"frame": "BLACK"
},
{
"filter": "Settings",
"keyword": { "color": "#3B82F6" },
"frame": "WHITE"
}
]
}Champs principaux :
background— un fichier PNG sur lequel est superposé l'appareil encadré. Il doit être plus large que votre capture d'écran la plus grande. Par défaut,frameitcentre verticalement l'appareil ; les optionstitle_below_imageetshow_complete_framecontrôlent la disposition du texte et du cadre.data[]— surcharges de configuration spécifiques par capture, basées sur un filtre de texte appliqué au nom de fichier. La deuxième entrée ci-dessus ne s'applique qu'aux fichiers dont le nom contient « Settings ». Utile pour faire varier les thèmes de couleurs d'un écran à l'autre.frame— surcharge la couleur du cadre de l'appareil pour les fichiers correspondants. Les valeurs reconnues parframeitdans le fichierFramefile.jsonsontBLACK,WHITE,GOLDetROSE_GOLD. Les visuels des cadres sont téléchargés depuis les fichiers Sketch de ressources marketing d'Apple via la commandefastlane frameit download_frames.
Fichiers title.strings et keyword.strings par locale
Les textes marketing proviennent de deux fichiers de chaînes parallèles par langue — title.strings pour le titre principal et keyword.strings pour le libellé plus petit situé au-dessus. Les clés correspondent aux noms de fichiers des captures, sans extension ni préfixe d'appareil :
/* fastlane/screenshots/en-US/title.strings */
"01-Home" = "Track every match.\nIn one tap.";
"02-Library" = "Your full history,\nalways with you.";
"03-Detail" = "Drill into any session.";
"04-Settings" = "Sync across all devices.";/* fastlane/screenshots/en-US/keyword.strings */
/* keywords are rendered above the title, smaller */
"01-Home" = "FAST";
"02-Library" = "ORGANIZED";
"03-Detail" = "DEEP";
"04-Settings" = "EVERYWHERE";Les traductions se placent dans fastlane/screenshots/de-DE/title.strings et fastlane/screenshots/de-DE/keyword.strings, fastlane/screenshots/ja/title.strings, etc. Utilisez \n pour insérer des retours à la ligne. Les langues manquantes afficheront la capture d'écran sans texte (aucun titre affiché) — il n'y a pas de repli automatique vers l'anglais.
Polices de caractères
Déposez les fichiers TTF ou OTF dans fastlane/screenshots/fonts/ et référencez-les par leur chemin relatif dans le fichier Framefile.json. Les polices variables sont supportées. Si vous référencez une police inexistante, frameit utilisera silencieusement une police sans empattement par défaut, et le résultat visuel sera incorrect sans avertissement préalable.
6. deliver — Envoyer vers App Store Connect
deliver parcourt le dossier de captures d'écran, associe chaque PNG à une famille d'affichage App Store Connect, puis communique avec l'API App Store Connect pour remplacer le jeu de captures de la version en cours d'édition. Avec l'authentification par clé d'API et un fichier Deliverfile bien paramétré, l'étape d'envoi se résume à une seule commande.
Structure des dossiers
deliver s'attend à une structure plate par langue — pas de sous-dossier par appareil. La famille d'affichage est détectée à partir de la résolution de l'image (et, en cas d'ambiguïté, d'après le préfixe d'appareil présent dans le nom de fichier généré par snapshot) :
fastlane/screenshots/
├── en-US/
│ ├── iPhone 17 Pro Max-01-Home_framed.png # 6.9" iPhone
│ ├── iPhone 17 Pro Max-02-Library_framed.png
│ ├── iPad Pro 13-inch (M4)-01-Home_framed.png # 13" iPad
│ ├── title.strings
│ └── keyword.strings
├── de-DE/
│ └── ...
└── Framefile.jsonDeliverfile
# fastlane/Deliverfile
app_identifier("com.example.myapp")
team_id("ABCDE12345")
# Auth via App Store Connect API key (preferred over username/password).
api_key_path("./fastlane/asc_api_key.json")
# Where to read screenshots / metadata from.
screenshots_path("./fastlane/screenshots")
metadata_path("./fastlane/metadata")
# Only push screenshots — leave the binary, pricing, IAPs, etc. alone.
skip_binary_upload(true)
skip_metadata(false)
skip_screenshots(false)
skip_app_version_update(true)
# Don't ask for confirmation in CI.
force(true)
overwrite_screenshots(true)
run_precheck_before_submit(false)
submit_for_review(false)
# Match a screenshot file against the right App Store display family.
# Useful when fastlane's resolution-based detection is ambiguous.
ignore_language_directory_validation(false)Les drapeaux (flags) les plus importants :
skip_binary_upload— sans cette option,delivercherchera un fichier IPA et refusera de s'exécuter s'il est absent.skip_metadata— réglez surtruesi vous souhaitez uniquement envoyer des captures et ne disposez pas de dossierfastlane/metadata/. Réglez surfalsepour publier vos titres localisés, descriptions, mots-clés et textes promotionnels dans le même appel.force(true)— évite la demande de confirmation « Êtes-vous sûr ? » quedeliveraffiche avant d'envoyer les fichiers. Requis en CI.overwrite_screenshots(true)— supprime le jeu de captures d'écran existant dans chaque famille d'affichage avant d'envoyer les nouvelles images. Sans cette option, les nouveaux fichiers s'ajoutent aux anciens jusqu'à la limite de 10 captures, puis l'envoi échoue.run_precheck_before_submit(false)—precheckrecherche les termes à risque dans les métadonnées (« Bêta », noms de concurrents, mots censurés). C'est idéal avant de soumettre une application, mais inutile pour une simple mise à jour de captures.
Simulation, puis envoi
# verify which display families and locales will be touched, no upload
bundle exec fastlane deliver --verify_only
# inspect the resolved configuration
bundle exec fastlane deliver --print_resolved_options
# real upload
bundle exec fastlane deliverLors du premier envoi réel, deliver génère un aperçu HTML sous fastlane/preview.html et attend votre confirmation (sauf si force(true) est activé). Ouvrez systématiquement cet aperçu la première fois que vous ajoutez une famille d'appareils — c'est là que se révèlent les éventuelles erreurs d'association.
7. Le fichier Fastfile complet
Un fichier unique contenant quatre lanes couvrant la capture, l'habillage, la capture combinée à l'habillage, et l'envoi complet. Le développement local utilise une lane dédiée ; la CI en utilise une autre.
# fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "Capture screenshots with snapshot"
lane :screenshots do
capture_ios_screenshots # alias for snapshot
end
desc "Frame screenshots with frameit"
lane :frame do
frame_screenshots(
path: "./fastlane/screenshots",
use_platform: "IOS"
)
end
desc "Build framed screenshots end-to-end"
lane :build_marketing do
capture_ios_screenshots
frame_screenshots(path: "./fastlane/screenshots", use_platform: "IOS")
end
desc "Upload screenshots to App Store Connect"
lane :upload_screenshots do
upload_to_app_store( # alias for deliver
skip_binary_upload: true,
skip_metadata: true,
skip_app_version_update: true,
force: true,
overwrite_screenshots: true,
run_precheck_before_submit: false
)
end
desc "Full release pipeline: capture, frame, upload"
lane :ship_screenshots do
capture_ios_screenshots
frame_screenshots(path: "./fastlane/screenshots", use_platform: "IOS")
upload_to_app_store(
skip_binary_upload: true,
skip_metadata: true,
skip_app_version_update: true,
force: true,
overwrite_screenshots: true
)
end
endcapture_ios_screenshots, frame_screenshots et upload_to_app_store sont les noms officiels des actions snapshot, frameit et deliver. Les noms courts fonctionnent toujours, mais les noms longs sont plus explicites et n'entrent pas en conflit avec des mots-clés Ruby.
8. Intégration continue (CI) sur GitHub Actions
La génération de captures d'écran est lente (comptez environ 15 minutes pour 5 langues × 3 appareils) mais se prête bien à la parallélisation sur simulateurs. Un unique runner macos-26 avec simulateurs simultanés est généralement suffisant.
# .github/workflows/screenshots.yml
name: Screenshots
on:
workflow_dispatch:
push:
paths:
- "fastlane/**"
- "MyAppUITests/**"
jobs:
screenshots:
runs-on: macos-26 # Xcode 26.x default; macos-15 also works with explicit xcode-select
timeout-minutes: 90
env:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
FASTLANE_SKIP_UPDATE_CHECK: "1"
FASTLANE_HIDE_CHANGELOG: "1"
steps:
- uses: actions/checkout@v4
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_26.3.app
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true
- name: Write App Store Connect API key
run: |
mkdir -p fastlane
echo "$ASC_API_KEY_JSON" > fastlane/asc_api_key.json
env:
ASC_API_KEY_JSON: ${{ secrets.ASC_API_KEY_JSON }}
- name: Capture, frame, upload
run: bundle exec fastlane ios ship_screenshots
- name: Archive framed screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: screenshots
path: fastlane/screenshotsÉléments garantissant la fiabilité de votre CI :
- Verrouillez la version de Xcode. Utilisez
sudo xcode-select -savec un chemin explicite. Les runners hébergés par GitHub intègrent plusieurs versions de Xcode, et la version par défaut est celle choisie arbitrairement pour le mois en cours. - Verrouillez l'image du runner. Utilisez une image spécifique telle que
macos-26oumacos-15, et non pasmacos-latest. Une mise à jour du runner trois semaines avant une livraison est le genre de surprise à éviter. - Mettez en cache l'installation de Bundler. L'option
bundler-cache: truedans l'actionsetup-rubyfait gagner une minute ou deux à chaque exécution. - Générez la clé d'API depuis un secret unique. Enregistrer séparément
key_id,issuer_idetkeysimplifie la rotation des clés mais augmente le risque d'erreurs. Un secret unique structuré en JSON convient parfaitement pour les petites équipes. - Publiez les captures habillées sous forme d'artéfact même si l'étape d'envoi échoue. Vous voudrez presque toujours inspecter les visuels générés avant de relancer le workflow.
9. Erreurs courantes et solutions
« Could not find a device matching... »
Les noms des appareils pour Snapshot doivent correspondre exactement à ceux renvoyés par la commande xcrun simctl list devicetypes. Apple sort un nouvel appareil haut de gamme chaque année, et sa nomenclature basée sur l'année civile fait évoluer rapidement les outils. L'appareil "iPhone 17 Pro Max" requiert Xcode 26 (sorti à l'automne 2025) ; sous Xcode 16, l'appareil de 6,9 pouces s'appelait "iPhone 16 Pro Max". Après chaque mise à jour de Xcode, relancez la commande xcrun simctl list devicetypes | grep iPhone et mettez à jour votre fichier Snapfile.
« Unable to verify upload » / 401 Unauthorized
Votre jeton JWT a expiré pendant l'envoi, la clé d'API a été révoquée ou son rôle a été rétrogradé. Vérifiez que la valeur duration dans le fichier asc_api_key.json ne dépasse pas 1200, puis générez une nouvelle clé.
« App Store Connect is locked »
La version vers laquelle vous effectuez l'envoi est dans l'état En cours d'examen ou En attente de publication par le développeur. Les captures d'écran sont en lecture seule dans ces états. Créez une nouvelle version (statut « Préparation à la soumission ») et relancez le processus.
Les captures d'écran sont associées à la mauvaise famille d'affichage
deliver effectue l'association selon la résolution de l'image. Si vous exportez une capture d'iPhone 6,9 pouces à 1320 × 2868, elle sera placée dans l'emplacement 6,9 pouces ; si vous la redimensionnez à 1284 × 2778, elle finira dans l'emplacement hérité de 6,5 pouces. Si les deux familles d'affichage coexistent sur votre version d'application, indiquez la famille d'appareils dans le nom de fichier — c'est le préfixe que snapshot ajoute automatiquement. Les exports manuels l'oublient souvent.
« Screenshot has alpha channel » / transparence inattendue
App Store Connect rejette historiquement les fichiers PNG contenant de la transparence, et deliver émet toujours une alerte lorsqu'il détecte un canal alpha. Bien que la page des spécifications de captures d'écran d'Apple ne mentionne plus explicitement cette règle, aplatir le canal alpha reste la solution la plus sûre. Traisez le fichier avec sips -s format png en utilisant un profil de couleur PNG, ou réexportez l'image sans canal alpha. Le rendu composite de frameit est toujours opaque ; la sortie brute de simctl io ... screenshot peut contenir de la transparence si votre vue racine n'est pas opaque.
« Locale ru-RU does not exist for this app »
deliver effectue les envois uniquement vers les locales d'App Store Connect déjà configurées sur la version. Ajoutez d'abord la langue dans App Store Connect (ou utilisez l'option force_create_app(true) + les métadonnées dans deliver), puis relancez.
Les simulateurs simultanés saturent la mémoire RAM
Chaque simulateur d'iPhone 17 Pro Max démarré avec le clavier affiché consomme environ 2,5 Go de RAM. Sur un MacBook équipé de 16 Go de RAM, exécuter trois simulateurs en même temps provoquera une saturation de la mémoire swap et un plantage des tests. Configurez l'option concurrent_simulators(false) localement et laissez la CI exécuter les simulateurs en parallèle sur un runner plus puissant.
10. Quand fastlane s'avère superflu
Le pipeline de captures d'écran de fastlane est idéal si :
- Vous disposez déjà d'une cible de test d'interface utilisateur et votre équipe est à l'aise avec la maintenance des environnements XCUITest.
- Vous souhaitez que les captures d'écran soient un artéfact de votre CI, régénéré à chaque livraison.
- Vous localisez votre application et souhaitez définir la mise en page une fois pour toutes dans le code, sans avoir à la redessiner pour chaque langue.
Ce n'est pas la bonne solution si :
- Vous souhaitez contrôler finement la direction artistique de chaque capture (typographie, composition, éléments décoratifs).
frameitest un moteur de gabarits (templates), pas un outil de conception graphique. - Vous devez publier une capture d'écran de qualité marketing pour une fonctionnalité qui n'existe pas encore dans l'application, ou qui est protégée par un feature flag inaccessible par vos tests.
- Vous êtes un développeur solo qui préfère concevoir ses visuels une fois pour toutes dans une application Mac puis cliquer sur Envoyer. La maintenance de la chaîne d'outils Ruby, associée à XCUITest et au verrouillage des versions Xcode représente une charge réelle.
Pour un flux de travail centré sur le design, Screenshot Bro répond aux mêmes besoins — mises en page localisées, cadres d'appareils, envoi en un clic vers App Store Connect avec la même clé d'API — le tout sans la complexité de configuration d'XCUITest.
Fiche récapitulative (TL;DR)
# Setup (once)
bundle init && echo 'gem "fastlane"' >> Gemfile && bundle install
bundle exec fastlane init
bundle exec fastlane snapshot init
bundle exec fastlane frameit download_frames
# Per release
bundle exec fastlane ship_screenshotsVoilà pour le pipeline complet. Deux commandes lors de l'installation, une commande par publication. La complexité est masquée dans les fichiers de configuration présentés ci-dessus — et une fois créés, ils ne changent presque plus.
Vous hésitez à mettre en place cette solution ou préférez utiliser une application Mac dédiée ? Consultez l'article Fastlane snapshot comparé à Screenshot Bro pour un comparatif détaillé et découvrir comment combiner les deux approches.