12. Déploiement
En développement, l'application tourne sous le contrôle de [flutter run] : en mode « debug », plus lent, avec le rechargement à chaud et les vérifications ([assert]) de [Flutter]. Pour la livrer, on la construit en mode « release » : du code optimisé, sans outils de développement. On construit une version par plate-forme.
12.1. La version web
- Construire le client. Dans le dossier [rdvmedecins_flutter] :
La console affiche :
Deux avertissements, sans conséquence : la compilation en [WebAssembly] serait possible (cf. plus bas) ; une bibliothèque de [Flutter] mentionne les icônes du style [iOS] ([CupertinoIcons]), que l'application n'utilise pas.
Le compilateur [dart2js] a traduit toute l'application ([Dart], [Flutter] et les paquets) en [JavaScript], dans le dossier [build/web/] :
- [index.html] : LA page de l'application, qui charge [flutter_bootstrap.js], puis [main.dart.js] (3,5 Mo, environ 1 Mo une fois compressé par le serveur) : NOTRE code, et tout celui de [Flutter] et des paquets, optimisé. [Flutter] ne produit pas de HTML : l'application dessine elle-même chaque pixel dans un canevas, avec le même moteur que sur le téléphone ;
- [canvaskit/] : ce moteur de dessin ([Skia], compilé en [WebAssembly] : [canvaskit.wasm], 7 Mo). Sans l'option [--no-web-resources-cdn], il serait téléchargé depuis un serveur de [Google] ; avec elle, il est livré avec l'application, qui ne dépend plus d'aucun site extérieur ;
- [assets/] : les ressources du [pubspec.yaml] (les dictionnaires, les polices). Les icônes sont « élaguées » (« tree-shaken ») : seules celles qu'utilise l'application sont gardées dans la police des icônes ;
- au premier chargement, le navigateur télécharge quelques mégaoctets (le moteur de dessin, surtout), puis les garde en cache. C'est la principale faiblesse de [Flutter] pour le web : il convient mieux aux applications (qu'on ouvre et qu'on utilise longtemps) qu'aux sites (qu'on parcourt en passant).
L'option [--wasm] compile l'application en [WebAssembly] plutôt qu'en [JavaScript] : elle est plus rapide, dans les navigateurs qui le permettent ([Chrome], [Edge], [Firefox] récents) ; les autres reçoivent automatiquement la version [JavaScript].
- La déposer dans le serveur. On copie le CONTENU du dossier [build/web/] dans un dossier [client/] à la racine du serveur JSON ([rdvmedecins-nestjs-json/client/index.html], [rdvmedecins-nestjs-json/client/main.dart.js]...), puis on relance le serveur. Il affiche :
L'application complète est alors à l'adresse http://localhost:8080. Le serveur sert les fichiers du client, et renvoie [index.html] pour toute autre adresse hors de /api : recharger la page /agenda fonctionne (c'est le routeur du client qui l'affiche). C'est le fichier [src/web/client-spa.ts] du serveur qui fait ce travail. L'application est servie par le serveur de l'API : l'adresse relative de [config.dart] ([''], soit [/api/...]) est la bonne.
On peut aussi essayer la version construite sans le serveur JSON, avec n'importe quel serveur de fichiers, mais les requêtes /api n'aboutiront pas.
12.2. La version Android
- Construire l'application, en lui donnant l'adresse du serveur :
La console affiche (pour un APK construit sans [--dart-define]) :
(Quelques avertissements de [Gradle] et de [Java], sans conséquence, ont été retirés.) La première construction est longue : [Gradle] télécharge ses propres outils et bibliothèques ; les suivantes sont bien plus rapides.
Le compilateur de [Dart] a traduit l'application en code machine, pour les trois familles de processeurs des téléphones [Android] (ARM 32 bits, ARM 64 bits, x86 64 bits), et l'outil de construction d'[Android] ([Gradle]) l'a emballée, avec le moteur de [Flutter], dans un fichier APK : le format d'installation des applications [Android]. Il contient trois fois l'application et son moteur, un exemplaire par famille de processeurs, d'où sa taille. [--split-per-abi] produirait trois APK plus petits, un par famille de processeurs ; un « App Bundle » (plus bas) laisse la boutique ne livrer à chaque téléphone que ce dont il a besoin.
- L'installer. Le téléphone étant relié à l'ordinateur (câble USB, débogage USB activé) :
On peut aussi copier le fichier APK sur le téléphone et l'ouvrir : [Android] demande alors d'autoriser l'installation d'applications « de sources inconnues ».
- Pour une vraie publication :
- l'application doit être signée avec une clé propre au développeur : le projet généré par [flutter create] signe la version « release » avec la clé de débogage, ce qui suffit pour des essais, mais pas pour une boutique. La documentation de [Flutter] (« Build and release an Android app ») décrit la création de la clé et la configuration de [Gradle] ;
- le [Google Play Store] attend un « Android App Bundle » plutôt qu'un APK : [flutter build appbundle] ;
- le nom et l'icône de l'application se règlent dans [android/app/src/main/AndroidManifest.xml] ([android:label]) et [android/app/src/main/res/mipmap-*/] ;
- le serveur doit être en HTTPS (les mots de passe circulent), et la ligne [android:usesCleartextTraffic="true"] disparaît du manifeste.
12.3. Le serveur en production
En production réelle, on n'oubliera pas le fichier [.env] du serveur :
- un [JWT_SECRET] long et aléatoire ;
- [CAPTCHA_TEST] vide ;
- [COOKIE_SECURE=true] si le site est servi en HTTPS (il doit l'être). Le client mobile renvoie le cookie quelle que soit cette option : c'est le navigateur qui la respecte ;
- [TRUST_PROXY=true] si le serveur est placé derrière un proxy ([nginx]...), pour que la limitation des tentatives voie l'adresse IP réelle des clients.
On lance alors le serveur compilé : [npm run build], puis [npm run start:prod].