Aller au contenu principal

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.

Démo blocage version obsolète : l'application envoie sa version, reçoit un HTTP 426 Upgrade Required lorsqu'elle est trop ancienne, puis affiche un écran de mise à jour forcée avec liens vers les stores
Code source complet

Les extraits présents dans ce cookbook sont issus d’un dépôt d’exemples:

Tu peux y consulter la version intégrale (structure, tests, configuration). Les morceaux de code ici sont volontairement allégés.

Symfony : 1h Flutter : 1h Total : 2h

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

  1. Flutter envoie la version courante dans le header X-App-Version à chaque requête.
  2. Symfony compare cette version avec la version minimale requise (APP_MIN_MOBILE_VERSION).
  3. Si la version est inférieure → le backend renvoie un HTTP 426 Upgrade Required.
  4. Flutter intercepte ce code et affiche un dialog bloquant proposant la mise à jour (App Store / Play Store).

Architecture

ÉlémentRôle
FrontendFlutter → ajoute le header X-App-Version et gère le code 426
BackendSymfony → compare la version et renvoie 426 si obsolète
HTTP Code426 Upgrade Required → version incompatible
PayloadJSON indiquant la version minimale et les liens de mise à jour

Structure du cookbook

PartieFichierCode repoContenu
Backend Symfonysymfony.mdxBitbucket ↗Config, listener, endpoint /ping, tests, observabilité
Frontend Flutterflutter.mdxBitbucket ↗Header auto, interception 426, popup mise à jour

Exemple rapide

curl -i -H "X-App-Version: 2.3.1" 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é

remarque

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émentPourquoi
Compteur par version (mobile_version_request)Suivre répartition des apps en circulation
Ratio erreurs 426Dé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
Mise en place progressive

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.

  1. Version minimale publiée sur stores (Android / iOS).
  2. Clé de traduction disponible dans toutes les locales.
  3. Monitoring (compteur + ratio 426) configuré.
  4. Communication envoyée aux devs front (et éventuellement aux utilisateurs via note de publication).
  5. 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.