Skip to content

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

  1. Construire le client. Dans le dossier [rdvmedecins_flutter] :
flutter build web --no-web-resources-cdn

La console affiche :

1
2
3
4
5
6
7
Compiling lib\main.dart for the Web...
Wasm dry run succeeded. Consider building and testing your application with the `--wasm` flag. See docs for more info: https://docs.flutter.dev/platform-integration/web/wasm
Use --no-wasm-dry-run to disable these warnings.
Expected to find fonts for (MaterialIcons, packages/cupertino_icons/CupertinoIcons), but found (MaterialIcons). This usually means you are referring to font families in an IconData class but not including them in the assets section of your pubspec.yaml, are missing the package that would include them, or are missing "uses-material-design: true".
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 9004 bytes (99.5% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
Compiling lib\main.dart for the Web...                             70,5s
√ Built build\web

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].

  1. 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 :
[Nest] LOG [RdvMedecins] client web servi depuis .../rdvmedecins-nestjs-json/client
[Nest] LOG [RdvMedecins] serveur JSON démarré : http://localhost:8080/api

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

  1. Construire l'application, en lui donnant l'adresse du serveur :
flutter build apk --dart-define=SERVEUR=http://192.168.1.20:8080

La console affiche (pour un APK construit sans [--dart-define]) :

1
2
3
4
Running Gradle task 'assembleRelease'...
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 3400 bytes (99.8% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
Running Gradle task 'assembleRelease'...                          193,4s
√ Built build\app\outputs\flutter-apk\app-release.apk (53.5MB)

(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.

  1. L'installer. Le téléphone étant relié à l'ordinateur (câble USB, débogage USB activé) :
flutter install

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 ».

  1. 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].