Bloquer les versions obsolètes
Ce cookbook explique comment bloquer les anciennes versions d’une application Flutter grâce à un contrôle côté backend Symfony.
L’objectif : forcer l’utilisateur à mettre à jour lorsque son application n’est plus compatible avec le backend.

Les extraits présents dans ce cookbook sont issus d’un dépôt d’exemples:
- Symfony: https://bitbucket.org/doingfr/doing-cookbooks-examples/src/main/enforce-app-version/symfony/
- Flutter: https://bitbucket.org/doingfr/doing-cookbooks-examples/src/main/enforce-app-version/flutter/
Tu peux y consulter la version intégrale (structure, tests, configuration). Les morceaux de code ici sont volontairement allégés.
TL;DR
Un header X-App-Version envoyé par l’app mobile est comparé à une version minimale (APP_MIN_MOBILE_VERSION). Si trop ancienne → réponse HTTP 426 avec un JSON de guidance (versions + liens store) et l’app affiche un écran de mise à jour bloquant.
Principe général
- Flutter envoie la version courante dans le header
X-App-Versionà chaque requête. - Symfony compare cette version avec la version minimale requise (
APP_MIN_MOBILE_VERSION). - Si la version est inférieure → le backend renvoie un HTTP 426 Upgrade Required.
- Flutter intercepte ce code et affiche un dialog bloquant proposant la mise à jour (App Store / Play Store).
Architecture
| Élément | Rôle |
|---|---|
| Frontend | Flutter → ajoute le header X-App-Version et gère le code 426 |
| Backend | Symfony → compare la version et renvoie 426 si obsolète |
| HTTP Code | 426 Upgrade Required → version incompatible |
| Payload | JSON indiquant la version minimale et les liens de mise à jour |
Structure du cookbook
| Partie | Fichier | Code repo | Contenu |
|---|---|---|---|
| Backend Symfony | symfony.mdx | Bitbucket ↗ | Config, listener, endpoint /ping, tests, observabilité |
| Frontend Flutter | flutter.mdx | Bitbucket ↗ | Header auto, interception 426, popup mise à jour |
Exemple rapide
- Requête valide
- Requête obsolète
- Sans header (toléré ici)
curl -i -H "X-App-Version: 2.3.1" https://api.example.com/ping
# HTTP/1.1 200 OK
curl -i -H "X-App-Version: 2.2.0" https://api.example.com/ping
# HTTP/1.1 426 Upgrade Required
curl -i https://api.example.com/ping
# HTTP/1.1 200 OK
Exemple de réponse JSON
{
"error": "app_version_upgrade_required",
"message": "Une nouvelle version de l’application est nécessaire pour continuer.",
"min_required_version": "2.3.0",
"current_version": "2.2.1",
"stores": {
"android": "https://play.google.com/store/apps/details?id=com.example.app",
"ios": "https://apps.apple.com/app/id1234567890"
}
}
Monitoring et observabilité
Cette partie est indispensable si l'ajout de la feature a lieu dans une application existante afin d'éviter toute suprise lors du déploiement. Elle sera traitée notamment dans la partie Symfony.
| Élément | Pourquoi |
|---|---|
Compteur par version (mobile_version_request) | Suivre répartition des apps en circulation |
| Ratio erreurs 426 | Détecter pic après déploiement version minimale |
| Log structuré canal dédié | Investiguer versions rejetées et corréler avec incidents |
| Dashboard répartition (top 10 versions) | Décider date d’obsolescence prochaine |
Commence par collecter les versions (header présent) sans blocage (APP_FORCE_UPDATE_ENABLED=false), puis active le blocage une fois la majorité des utilisateurs sur la nouvelle version.
Checklist déploiement
Bien vérifier ces points avant de déployer pour éviter tout problème.
- Version minimale publiée sur stores (Android / iOS).
- Clé de traduction disponible dans toutes les locales.
- Monitoring (compteur + ratio 426) configuré.
- Communication envoyée aux devs front (et éventuellement aux utilisateurs via note de publication).
- Tests automatisés verts (voir symfony.mdx).
FAQ
Pourquoi utiliser le code HTTP 426 ?
Il est sémantiquement dédié aux exigences de mise à niveau et évite la confusion avec des codes d’erreur d’authentification ou de syntaxe.
Que faire si l’utilisateur ne peut pas mettre à jour ?
Prévoir un message de support (FAQ, email). On peut aussi offrir un mode dégradé si techniquement possible.
Peut-on envoyer la version dans le body ?
Oui, mais le header est plus simple à centraliser via un interceptor HTTP côté mobile et ne nécessite pas de modifier chaque payload.
Comment choisir la version minimale ?
En général quand >80–90% du parc a migré sur la nouvelle version, après quelques jours sans incident critique.
➡ Pour la mise en œuvre détaillée backend, voir symfony.mdx. Pour Flutter: implémentation à venir dans flutter.mdx.