Mobiapps, le REX Flutter (Garanti sans dinosaure)

Flutter [fluht-er]

Nouveau venu dans le monde des applications hybrides, Flutter s'est rapidement imposé comme un outil à suivre et sur lequel il faudra compter dans les années à venir. Actuellement classé 16e parmi les dépôts populaires GitHub (d'après Gitstar Ranking), on peut remarquer que Flutter est plus populaire, techniquement, que React Native ou encore Ionic par exemple.

Porté par Google, Flutter s'adresse actuellement aux acteurs du développement mobile désireux de maintenir un code unique entre des applications iOS /Android et permettant un rendu et des performances très proches du natif.

Il faut savoir également que la volonté de Google est d'étendre le support jusqu'à la génération d'applications "Desktop" et "Web" à partir du même code, pour supporter respectivement des applications macOS / Linux (portage Windows encore en développement) et du Web standard (HTML, JavaScript, CSS) mais que ces fonctionnalités ne sont pas encore stable (Alpha & Beta) et donc non utilisables en production.

La technique

Avant de nous lancer dans les détails de notre expérience, et afin de mieux appréhender la suite, il convient de rappeler quelques points techniques propres à Flutter.

Le Framework

Flutter est un Framework (compatible Android 4.1.X et iOS 8) qui s'appuie sur son propre moteur de rendu Skia (OpenGL ou Metal pour Apple) et ne fournit donc pas simplement une surcouche (wrapper) aux composants natifs mais bel et bien une bibliothèque de Widgets qui "émule" (dessine) le rendu des différents composants natifs et va même au-delà de ce qui existe aujourd'hui dans les catalogues iOS/Android. La construction d'une interface s'articule donc autour de ces Widgets personnalisables qui ont la particularité de se succéder les uns aux autres et de créer ainsi un rendu hiérarchisé.

Concernant l'architecture actuellement préconisée, il ressort principalement un pattern: "BLoC". Ce concept s'appuie sur un composant essentiel de Flutter:les streams; il permet de gérer différents états dans l'application à partir d'évènements et de construire une interface dynamique en réponse à un ensemble de règles métier.

Enfin, sachez qu'une connaissance des environnements natifs (XCode/Swift, Android Studio/Kotlin) est souhaitée pour la mise en place de projet car comme tout projet hybride il vous faudra parfois configurer un manifest ou ajouter des "capabilities" directement dans votre application.

Le langage

Il est intéressant de noter que pour développer Flutter, Google a choisi le langage Dart (lui aussi développé par Google) mais que ce choix ne s'est pas fait uniquement par intérêt mais bel et bien à la suite d'une étude impliquant plus d'une douzaine de langages.

Voici les principales raisons de ce choix:

  • Dart est AOT (Ahead Of Time), donc un langage haut niveau compilé vers un langage machine, ce qui permet à une application Flutter d'être optimisée pour l'architecture qu'elle cible.
  • Dart est aussi JIT (Just In Time), ce qui permet de compiler à la volée (utilisé surtout en phase de développement) et de recharger instantanément une modification sans avoir à relancer l'application à chaque modification.
  • Dart facilite la création d'animations et de transitions tournant à 60fps grâce à sa gestion des allocations mémoire, du garbage collector et de l'absence de mémoire partagée (et donc de verrous)
  • Dart est simple à prendre en main car il s'agit d'un langage moderne proche de TypeScript par exemple et qui possède beaucoup de similitudes avec Kotlin ou encore Swift.

L'écosystème

Flutter dispose d'une communauté très active, en témoigne les nombreuses mises à jour (1 à 2 par mois) du Framework, et dispose même d'une plateforme dédiée au recensement de ses plugins nommée Pub.dev (comme Packagist ou encore Cocoapods). On retrouvera donc sur cette plateforme les plugins officiels ainsi que ceux développés par la communauté classés par popularité.

Au cours de nos développements, nous avons également été agréablement surpris par la quantité d'articles/tutoriels/vidéos disponibles en ligne et par le panel assez large de sujets qui sont traités malgré la relative jeunesse de la solution.

Et si, malgré vos recherches, vous ne trouvez pas votre bonheur, sachez qu'il est possible avec Flutter de créer facilement un plugin Dart incluant une interface vers du code natif (soit iOS, soit Android, soit les 2) et que le développement peut se faire dans un module autonome, testable et debuggable depuis votre IDE favori avant d'être intégré dans votre projet principal.

Notre expérience projet

Suite à l'étude de Flutter chez Mobiapps nous avons donc décider de partir sur cette solution pour produire 2 nouvelles applications (Android 7+ et iOS 10.3+) pour la mise à jour ambitieuse d'un projet de plusieurs mois comportant 4 développeurs.

Ce projet étant un jeu, il avait pour spécificité de disposer d'une interface commune entre iOS et Android avec un design entièrement personnalisé ainsi qu'une navigation atypique (pas de push/pop de vue standard comme on peut voir en natif).

Fonctionnalités majeures

L'ensemble des fonctionnalités ci-dessous ont été intégrées avec soit le plugin officiel, soit un plugin de la communauté et pour certaines vous trouverez plus de détails.

  • Achats InApp - Play Store / App Store: Cette fonctionnalité est une des seules qui a nécessité de faire un code spécifique par plateforme à partir du plugin. Le code est resté malgré tout côté Dart et un simple `if(Platform.isIos)` permet de distinguer les cas et de traiter le rattrapage des achats selon les spécificités des plateformes (en effet le plugin met à disposition un wrapper sur les objets achats propre à l'OS).
  • AdRewards Firebase
  • Live2D: Gestion de modèles 3D dans le jeu à l'aide de WebGL, inclusion d'un fork du plugin Webview pour gérer la transparence.
  • Notifications push & locales: Utilisation du plugin Firebase Cloud Messaging.
  • Tracking: AppsFlyer & Google Analytics
  • Dézippe de packages (modèles 3D)
  • Lecture/écriture API REST (JSON): La librairie Dio permet d'effectuer les appels HTTP et d'utiliser Retrofit ainsi qu'un module JSON pour générer du code à partir d'annotations et récupérer ainsi des classes prêtes à l'emploi. A noter que l'usage de générateur est très commun avec Flutter car l'introspection (reflection) n’est pas possible avec Dart.
  • Authentification Facebook & Apple
  • Musique/sons: Intégration de bruitages d'interfaces ainsi que de musiques venues des Webservices après téléchargement.
  • i18n: (6 langues) Nous sommes partis sur un plugin permettant d'inclure des traductions au format JSON et gérant le changement de langue depuis l'application.
  • Besoin d'avoir beaucoup d'animations
  • Build sur différents environnements: (dev & prod) solution développée via une librairie que nous avons réalisée pour une gestion des environnements par fichier de configuration JSON.
  • Préférences utilisateur: Nous avons développé notre propre plugin pour cette partie car le plugin officiel proposé préfixe toutes les clés et ne permet donc pas de récupérer les données déjà existante de l'application précédente.
  • Google Play Games & Apple Game Center: nous avons également développés nos propres besoin, cette fois à partir d'un fork de plugin existant qui permettait la connexion mais pas la sauvegarde de données sur les clouds natifs.

Comme vous pouvez le constater ci-dessus, nous avons dû intégrer un grand nombre de fonctionnalités et pour aucune d'entre elles nous avons été bloqués ou avons rencontrées des difficultés particulières.

Architecture adoptée

L'envergure de notre projet nous a poussé à adopter un découpage modulaire afin de mieux séparer les tâches et permettre la réutilisation de certains modules dans de futurs jeux. On trouvera ainsi le schéma suivant pour représenter le découpage global:

Côté architecture fonctionnelle, nous sommes partis sur l'implémentation du pattern BLoC sur nos divers modules, le tout orchestré par des filtres sur des streams d'évènements pour simplifier le workflow général et pour permettre aux différents modules de s'abonner à des évènements particuliers et de réagir en conséquence tout en ignorant le reste du système.

Notez également que la multiplication des modules gravitant autour de l'application principale n'a pas eu d'impact notable sur les performances lors du développement, et que la prise en charge des modifications dans un module était bien prise compte au rechargement à chaud dans l'application lancée.

Concernant la partie UI, comme indiqué précédemment, nous n'avons pas utilisé de navigation standard pour la simple et bonne raison que les écrans n'étaient pas construits de la sorte. Nous nous sommes donc retrouvés avec un empilement de vues nous permettant tour à tour de donner la priorité d'affichage à certains éléments du jeu sur d'autres sans perturber la progression du jeu. Pour résumer, cela donne le schéma suivant:

où l'on voit que les erreurs s'affichent au plus haut niveau, suivit d'éventuelles modales, puis du blocage de la partie login au besoin ; et enfin les différentes interfaces de jeu, du menu en passant par les dialogues jusqu'à la représentation Live2D en guise de racine visuelle.

Notre bilan

Les plus

Les points qui nous ont le plus emballés:

  • La courbe d'apprentissage rapide du langage Dart.
  • Le rechargement à chaud immédiat du code est une grande force pour la construction des écrans et la phase de développement.
  • La gestion automatique de plusieurs animations nous a permis d'offrir une meilleure expérience utilisateur qu'à l'accoutumé.
  • La personnalisation à l'extrême des composants sans difficultés.
  • Richesse du catalogue de Widgets qui surpasse le support natif.
  • L'environnement technique (Visual Studio Code, Android Studio) et les Dev Tools très performants et simples à prendre en main.
  • Une architecture libre à concevoir (contrairement à certains Framework comme Angular pour ne citer que lui).
  • Une documentation riche et de nombreux supports écrits et vidéos.
  • Une communauté active.
  • Une homogénéité parfaite entre les plateformes iOS et Android grâce à l'usage d'un moteur de rendu.
  • Des mises à jour régulières (ex: release le jour de la sortie d'iOS 14 pour pallier un soucis de build).

Les moins

Les points mitigés:

  • Les temps de compilations sont liés au commandes natives (gradle, cocoapods, XCode..) et mieux vaut donc posséder un processeur i7 pour ne pas perdre trop de temps à chaque build
  • La communauté bien qu'active, est encore peu mâture en terme de contenu et ne proposera donc pas systématiquement un plugin adapté à vos besoins les plus spécifiques
  • Nécessite tout de même un référent natif pour la mise en place du projet voir la configurations de certains plugins
  • Vigilance sur le hot reload qui a tendance à perdre sa hiérarchie quand vous modifiez un Widget "Stateless" en "Statefull" et inversement, ou que vous ajoutez des blocs après affichage d'un écran; il faut parfois relancer l'application avant de conclure que le code produit ne fonctionne pas.
  • Nous avons rencontrés des soucis de crash que nous n'avons pu résoudre sur iOS avec les téléphones ne supportant pas l'architecture 64bits et les avons donc exclus du support (concerne l'iPad Retina, l'iPhone 5 & 5c pour les versions 10.3+)

Neutre

Enfin, deux points sur lesquels nous n'avions pas d'attentes particulières en terme d'efficience et qui ne sont au final ni des déceptions, ni de francs succès:

  • La gestion du responsive sur notre projet, étant compatible téléphone et tablette, a été comme sur toutes les plateformes, effectuée au cas par cas et a nécessité de choisir des breakpoints pour adapter des fonts, des tailles d'éléments ou autre.
  • Le poids final de l'application est lui aussi très respectable puisque très proche de la taille finale constatée sur les plateformes natives, donc sans mauvaise surprise de ce côté.

Conclusion

Malgré notre passé de développeur sur des technologies différentes (mélange de développeurs back Php, front JS , Android, iOS, ou hybride) il est ressorti à l’unanimité que le développement sur Flutter fût un vrai plaisir et une franche réussite. Ajoutons à cela une gestion simplifiée des plannings et des tâches dû au fait que Flutter soit hybride et vous comprendrez alors que Mobiapps continuera d’accompagner et proposer des projets autour de cet outil.

Si vous souhaitez en savoir plus, n'hésitez pas à nous contacter via notre formulaire de contact.

Maxime HERMOUET - Développeur Sénior