Préparez vos projets pour Flutter 1.12 !
Publié le par Edouard Marquez
Article de 2019 : certaines étapes peuvent être obsolètes.
Cet article est une traduction de ma publication en anglais sur Medium.
Pas plus tard qu’hier, j’ai voulu tester la dernière version bêta de Flutter. Alors que je n’avais jamais rencontré de problème majeur avec ce framework, je me suis confronté à mon premier bug, qui m’a occupé pendant quelques heures…
Tout bon développeur vous le dira : une bonne pratique est de toujours utiliser des versions stables, afin d’éviter d’inutiles complications.
Mais comme vous le savez peut-être, la semaine prochaine, Google organise un événement, le Flutter Interact, où une nouvelle version de Flutter devrait être rendue disponible.
Comment tester une version bêta de Flutter ?
Flutter est découpé en plusieurs branches (ou channels) : stable, beta, dev et master, par ordre de stabilité.
Vous pouvez facilement voir sur quelle branche vous vous trouvez avec la commande flutter channel
:
~|⇒ flutter channel
Flutter channels:
* stable
dev
master
beta
Passer d’une branche à l’autre est aussi simple que cette commande :
~|⇒ flutter channel nouveauchannel
Note : n’oubliez pas d’exécuter la commande flutter upgrade juste après, afin de resynchroniser votre ordinateur avec le dépôt central.
Mais quel est le problème sur cette bêta ?
Comme vous le savez peut-être, Flutter a plusieurs modes de fonctionnement, dont :
- Release : génère une application pour le Google Play ou l’App Store ;
- Debug : utilisé pendant vos développements.
En mode release, tout fonctionne parfaitement avec la bêta. Que vous génériez une IPA (iOS), un App Bundle ou un APK (Android) à partir de votre projet Flutter, il n’y a aucun changement majeur à noter entre les versions stable et bêta.
Mais lorsque j’ai voulu exécuter mon application pour commencer à la modifier, j’ai rencontré cette erreur étrange :
Launching lib/main.dart on AOSP on IA Emulator in debug mode...
Running Gradle task 'assembleDebug'...
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':app:compileInternalDebugKotlin'.
> Could not resolve all files for configuration ':app:internalReleaseRuntimeClasspath'.
> Could not find io.flutter:x86_release:1.0.0-af04338413c3ed73316350f64248a152433073b6.
Searched in the following locations:
- https://dl.google.com/dl/android/maven2/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.pom
- https://dl.google.com/dl/android/maven2/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar
- https://jcenter.bintray.com/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.pom
- https://jcenter.bintray.com/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar
- http://download.flutter.io/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.pom
- http://download.flutter.io/io/flutter/x86_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/x86_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar
Required by:
project :app
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 31s
Finished with error: Gradle task assembleDebug failed with exit code 1
En lisant rapidement, on comprend qu’il manque une dépendance. Mais comment se fait-il que tout fonctionnait en mode release ?
En y regardant de plus près, on se rend compte que c’est une dépendance x86 qui manque. Ni une, ni deux, j’ai donc testé sur mon smartphone, qui a un processeur ARM… et cette fois-ci, plus aucune erreur 🤨.
Le problème vient de l’émulateur
Je ne l’avais jamais remarqué jusqu’alors, mais tous mes AVD (Android Virtual Devices, les émulateurs Android) utilisaient une image x86. En passant à une image x86_64, mon problème s’est résolu de lui-même.
Qu’ai-je appris ici ? Avant de migrer vers la prochaine version de Flutter, assurez-vous de basculer tous vos émulateurs Android vers des images x86_64… sinon vous serez bloqué comme moi !
Mais pourquoi Google a-t-il fait ce changement ?
Jusqu’à présent, vous pouviez déboguer vos applications Flutter sur un émulateur Android (x86 ou x86_64), mais il était impossible de générer une application pour les boutiques (mode release) pour ces architectures.
Si je cite la FAQ de Flutter :
Actuellement, Flutter ne permet pas de compiler pour Android x86 (bug #9253).
Toutefois, les applications conçues pour ARMv7 ou ARM64 fonctionnent (via l’émulation ARM) sur de nombreux terminaux Android x86.
L’équipe Flutter semble avoir changé d’avis sur le sujet (la part de marché du x86 étant trop faible pour y consacrer du temps), puisqu’une pull request a récemment été fusionnée : elle permet non seulement de déboguer en x86_64, mais aussi d’utiliser le mode release avec cette architecture. C’est pour cette raison que l’image x86 ne fonctionne plus : seul le x86_64 est pris en charge.
Après avoir perdu du temps dans les issues et le code sur GitHub, j’aurais vraiment apprécié un message plus explicite que celui-ci. Espérons que l’équipe ait le temps de faire cette petite modification d’ici l’événement du 11 décembre.
N’oubliez pas de mettre à jour votre code
La prochaine version de Flutter ne va pas seulement casser vos émulateurs Android : elle va aussi générer un certain nombre d’avertissements.
Le plus important concerne la méthode inheritFromWidgetOfExactType de la classe State, désormais dépréciée. Pour les plus curieux, les explications sont dans
la PR sur GitHub.
La commande flutter analyze affiche désormais ce type d’erreur :
info • 'inheritFromWidgetOfExactType' is deprecated and shouldn't be used. Use dependOnInheritedWidgetOfExactType instead.
Il ne reste donc qu’à transformer votre code comme indiqué. Il faut pour cela passer de :
InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect });
// Ex. : context.inheritFromWidgetOfExactType(YourInheritedWidget)
À :
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object aspect });
// Ex. : context.dependOnInheritedWidgetOfExactType<YourInheritedWidget>()
Vous êtes maintenant prêt pour la prochaine version de Flutter ! 🥳