Remote Config Gatekeeper en 3 étapes
Dans une implémentation OTA classique (auto_update: true), chaque ouverture de l'application mobile déclenche une requête HTTP POST /api/v1/patches/check vers le serveur OTA. Sur une flotte de plusieurs millions de terminaux, cela représente des millions d'appels quotidiens alors même qu'aucun nouveau patch n'a été publié, consommant inutilement la bande passante serveur et les données mobiles des utilisateurs.
Le RemoteConfigGatekeeper (lib/src/gatekeeper/remote_config_gatekeeper.dart) résout ce problème en évaluant localement en mémoire 3 conditions cumulatives à partir d'un payload JSON léger (issu de votre chargement de configuration habituel au démarrage : Firebase Remote Config, appel d'initialisation API métier, etc.).
Architecture et flux de décision
- Vérification au démarrage : Contrôle de l'état de santé du dernier lancement et gestion d'éventuels rollbacks.
- Contrôle de conformité : Évaluation des politiques de sécurité locales sur le terminal.
- Requête de mise à jour : Interrogation du serveur TkushPatch avec les métadonnées d'environnement.
- Téléchargement et application : Récupération du correctif signé si toutes les conditions sont remplies.
Les 3 conditions cumulatives
La méthode RemoteConfigGatekeeper.evaluate(...) vérifie dans l'ordre strict suivant :
-
Condition 1 — Correspondance de la Version Release (
targetReleaseVersion) :- Compare
installedReleaseVersion.trim()avecremoteConfig.targetReleaseVersion.trim(). - Si l'une des deux chaînes est vide ou si
installed != target, le Gatekeeper retourne immédiatementGatekeeperVerdict.skippedVersionMismatch(shouldCallOtaServer: false). - Utilité : un utilisateur qui exécute encore la version
1.0.0+2(ou qui vient d'installer la1.0.0+4) n'interrogera jamais le serveur pour un patch destiné uniquement à la1.0.0+3.
- Compare
-
Condition 2 — Interrupteur de disponibilité (
patchAvailable) :- Vérifie que
remoteConfig.patchAvailable == true. - Si
false, retourneGatekeeperVerdict.skippedNoPatchAvailable(shouldCallOtaServer: false). - Utilité : permet de couper instantanément toute interrogation du serveur OTA en un clic depuis votre Remote Config sans redéployer quoi que ce soit.
- Vérifie que
-
Condition 3 — Monotonie stricte du numéro de patch (
latestPatchNumber) :- Lit le patch actuellement exécuté par le moteur Rust (
currentPatchNumber ?? 0) et le compare àremoteConfig.latestPatchNumber. - Si
currentPatch >= latestPatch, retourneGatekeeperVerdict.skippedAlreadyUpToDate(shouldCallOtaServer: false). - Si
currentPatch < latestPatch, les 3 conditions sont réunies : retourneGatekeeperVerdict.allowed(shouldCallOtaServer: true).
- Lit le patch actuellement exécuté par le moteur Rust (
Le modèle OtaRemoteConfig
La classe OtaRemoteConfig (lib/src/models/ota_remote_config.dart) supporte à la fois le format snake_case et le format camelCase lors de la désérialisation via OtaRemoteConfig.fromJson(Map<String, dynamic> json) :
| Propriété Dart | Clés JSON acceptées par fromJson | Type | Défaut | Rôle |
|---|---|---|---|---|
targetReleaseVersion | target_release_version, targetReleaseVersion | String | '' | Version complète ciblée (x.y.z+build). |
patchAvailable | patch_available, patchAvailable | bool | false | Active ou coupe la recherche de patch pour cette version. |
latestPatchNumber | latest_patch_number, latestPatchNumber | int | 0 | Numéro du dernier patch publié (int, num ou String numérique convertie). |
forceUpdate | force_update, forceUpdate, force_critical_update | bool | false | false = téléchargement silencieux ; true = mise à jour critique bloquante. |
releaseNotes | release_notes, releaseNotes | String? | null | Message descriptif transmis à onCriticalUpdateRequired. |
Exemples de payloads JSON serveur / Remote Config
Scénario A : Aucun patch publié pour la Release courante (0 appel réseau)
{
"target_release_version": "1.0.0+3",
"patch_available": false,
"latest_patch_number": 0,
"force_update": false
}
Scénario B : Mise à jour silencieuse en arrière-plan (Patch #2 disponible)
{
"target_release_version": "1.0.0+3",
"patch_available": true,
"latest_patch_number": 2,
"force_update": false,
"release_notes": "Optimisation du chargement de l'historique des transactions."
}
Scénario C : Mise à jour critique forcée avec modale bloquante
{
"target_release_version": "1.0.0+3",
"patch_available": true,
"latest_patch_number": 3,
"force_update": true,
"release_notes": "Mise à jour de sécurité requise pour valider vos opérations."
}
Matrice complète des verdicts (GatekeeperVerdict) et modes d'exécution (OtaUpdateExecutionMode)
| État de l'appareil | Payload OtaRemoteConfig | GatekeeperVerdict | OtaUpdateExecutionMode | networkCallPerformed | restartRequired |
|---|---|---|---|---|---|
| Certificat APK invalide ou Root détecté | (Quelconque) | null (arrêté avant) | blockedBySecurityShield | false | false |
Version 1.0.0+2, Patch null | target: "1.0.0+3", available: true, latest: 1 | skippedVersionMismatch | blockedByGatekeeper | false | false |
Version 1.0.0+3, Patch null | target: "1.0.0+3", available: false, latest: 1 | skippedNoPatchAvailable | blockedByGatekeeper | false | false |
Version 1.0.0+3, Patch #2 | target: "1.0.0+3", available: true, latest: 2 | skippedAlreadyUpToDate | blockedByGatekeeper | false | false |
Version 1.0.0+3, Patch #1, en 4G (requireWifi: true) | target: "1.0.0+3", available: true, latest: 2, force: false | allowed | deferredToBackgroundTask | false | false |
Version 1.0.0+3, Patch #1, Wi-Fi & Batterie OK | target: "1.0.0+3", available: true, latest: 2, force: false | allowed | silentBackgroundUpdate | true | false |
Version 1.0.0+3, Patch #1, même en 4G | target: "1.0.0+3", available: true, latest: 2, force: true | allowed | criticalForcedUpdate | true | true (si téléchargé) |
enableGatekeeper: false | force: false (Wi-Fi/Batterie OK) | bypassedGatekeeperDisabled | silentBackgroundUpdate | true | false |
Lorsque forceUpdate: true, le SDK ignore la restriction requireWifiForSilentUpdate et le seuil de batterie minBatteryPercentageForSilentUpdate afin que le correctif critique puisse être téléchargé immédiatement, même sur réseau mobile 3G/4G.