Gestionnaire d'assets dynamiques (OtaAssetManager)
Le moteur natif C++/Rust applique des patchs binaires différentiels sur le code Dart compilé (binaire d'application sur Android, artefact de patch sur iOS), mais il ne réécrit pas l'archive en lecture seule flutter_assets/ empaquetée dans l'APK ou l'IPA d'origine lors de l'installation depuis le Store.
Pour mettre à jour à chaud des ressources statiques (fichiers de traduction JSON i18n, bannières promotionnelles, icônes SVG, polices ou configurations locales) sans soumettre une nouvelle version sur les Stores, le SDK fournit OtaAssetManager (lib/src/assets/ota_asset_manager.dart).
Architecture et fonctionnement
- Vérification du cache local : Le SDK vérifie si l'asset est déjà présent sur le disque du terminal.
- Contrôle d'intégrité : L'empreinte du fichier local est comparée à l'empreinte attendue.
- Téléchargement si nécessaire : En cas d'absence ou de non-concordance, l'asset est téléchargé et mis en cache.
- Mise à disposition : L'asset est immédiatement utilisable par les widgets Flutter.
1. Décrire un asset distant (OtaRemoteAssetDescriptor)
Chaque ressource téléchargeable est représentée par une instance immuable de OtaRemoteAssetDescriptor :
const descriptor = OtaRemoteAssetDescriptor(
assetKey: 'assets/i18n/fr_CM.json',
downloadUrl: 'https://ota.saramoney.internal/assets/fr_CM_v2.json',
expectedSha256: '99e887f4f4b6bf9d3abb767d3b5f215e0009e4d26cb7b958497e8b291e1b96dc',
);
| Champ | Type | Description |
|---|---|---|
assetKey | String | Clé logique de l'asset (ex: assets/images/promo.png ou assets/i18n/fr_CM.json). |
downloadUrl | String | URL HTTP/HTTPS complète permettant de télécharger le fichier sur le serveur On-Premise. |
expectedSha256 | String | Empreinte SHA-256 hexadécimale attendue (insensible à la casse, normalisée en minuscules). |
2. Télécharger, vérifier et mettre en cache (OtaAssetManager)
Initialisation
OtaAssetManager prend en paramètre un Directory cacheDirectory (où seront stockés les fichiers vérifiés) et un http.Client? httpClient optionnel (utile pour injecter un client avec timeouts personnalisés ou un MockClient en test) :
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:tk_ota_push/tk_ota_push.dart';
final cacheDir = Directory(p.join(Directory.systemTemp.path, 'ota_assets_cache'));
final assetManager = OtaAssetManager(cacheDirectory: cacheDir);
Structure du cache sur disque (cachedFileFor)
La méthode cachedFileFor(OtaRemoteAssetDescriptor descriptor) construit un chemin déterministe isolé par empreinte SHA-256 :
- Elle nettoie
assetKeyen remplaçant tout caractère hors[a-zA-Z0-9._/-]par_(safeKey). - Elle normalise
expectedSha256en minuscules (cleanHash). - Le fichier est stocké sous :
<cacheDirectory.path>/<cleanHash>/<safeKey>.
Ainsi, dès que vous publiez une nouvelle version d'un asset avec un nouveau expectedSha256, son chemin en cache change automatiquement, évitant tout conflit d'invalidation de cache.
Récupération avec vérification SHA-256 (getOrDownloadAsset)
try {
final File localAssetFile = await assetManager.getOrDownloadAsset(
descriptor,
headers: const {'Accept': 'application/json'},
);
final String jsonContent = await localAssetFile.readAsString();
// Utiliser le fichier local validé
} on OtaAssetIntegrityException catch (e) {
// L'empreinte SHA-256 reçue diffère de expectedSha256
debugPrint('Alerte intégrité asset ${e.assetKey} : attendu=${e.expectedSha256}, reçu=${e.actualSha256}');
} on HttpException catch (e) {
// Le serveur a répondu avec un code HTTP != 200
debugPrint('Erreur réseau téléchargement asset : $e');
}
Comportement détaillé de getOrDownloadAsset
- Vérification du cache existant :
- Si
targetFile.existsSync()est vrai,getOrDownloadAssetrelit les octets du fichier local et recalcule son condensatsha256. - Si le condensat correspond à
expectedSha256, le fichier est retourné immédiatement (0 appel réseau). - Si le fichier en cache a été altéré sur le disque (
cachedSha != expected), il est immédiatement supprimé (targetFile.deleteSync()) et re-téléchargé.
- Si
- Téléchargement HTTP :
- Effectue un
GETsurUri.parse(descriptor.downloadUrl)avec lesheadersoptionnels. - Si
response.statusCode != 200, lève uneHttpExceptioncontenant le code HTTP et l'URI.
- Effectue un
- Validation cryptographique SHA-256 :
- Calcule
sha256.convert(response.bodyBytes). - Si
actualSha != expected, lève uneOtaAssetIntegrityExceptionavant toute écriture sur le disque.
- Calcule
- Persistance atomique :
- Crée l'arborescence parente (
targetFile.parent.createSync(recursive: true)), écrit les octets vérifiés et retourne leFile.
- Crée l'arborescence parente (
3. Garde-fou de cohérence des assets embarqués (computeAssetsManifestHash)
En complément de OtaAssetManager, la CLI tk-ota-push calcule lors de chaque release et patch l'empreinte canonique SHA-256 de tous les fichiers déclarés dans la section flutter.assets de votre pubspec.yaml via FlutterProject.computeAssetsManifestHash() (lib/src/cli/project.dart).
Ce hash est transmis au serveur dans le champ assetsManifestHash (assets_manifest_hash) pour tracer toute modification des assets embarqués entre une Release Store et ses Patchs.