Flutter, la révolution !

Flutter, la révolution ?Chez Fidelisa, nous suivons de près, et utilisons pour certains projets la technologie Flutter, proposée et poussée par Google.

Et Flutter est passée en beta lors du Mobile World Congress de Février 2018.

Nous sommes parmi les premiers en France  à avoir travaillé sur ces technologies. Voici notre retour d’expérience sur ce qu’elles apportent, et leurs contraintes. Une première partie pourra être lue par tout le monde… et la seconde, plus technique, s’adresse plus spécifiquement aux développeurs.

1 – Flutter : des applications rapides pour iOS et Android

Qu’est ce que Flutter ?

Flutter est un framework de développement d’applications mobiles. Ce framework est proposé en Open Source par Google. Il propose un moyen unifié de développer des applications Android et iOS à partir d’un code commun. Il permet également de simplifier la gestion des compatibilités entre versions d’OS différentes, véritable casse-tête pour le développeur.

Exemple d'Application flutter
Exemple d’application Flutter

Quels sont les points forts de Flutter ?

Google met en avant les points clés suivants :

haute vitesse de développement avec des fonctionnalités comme le « hot reload », un framework reactif, des widgets pré-existants et des outils intégrés aux environnements de développement

designs de qualité, personnalisables, reposant sur des widgets, une bibliothèque d’animations, une architecture en couches extensible

expérience de haute qualité sur les différentes plateformes grâce à un coeur à haute performance et une prise en compte de l’interopérabilité des plateformes

2 – Flutter pour les développeurs, qu’est-ce que ça change ?

Introduction

Langage de programmation : le Dart

Flutter s’appuie sur le langage de programmation Dart poussé par Google.

Moteur de rendu

Son moteur de rendu, Skia Graphics Library est le même que celui utilisé par Chrome… éprouvé donc.

Ce moteur de rendu est important, car Flutter dessine chaque composant sans s’appuyer sur les composants standard iOS ou Android. Bien-sûr, Flutter propose par défaut des composants propres, répliques des composants iOS ou Android d’origine afin de permettre une expérience native par défaut. Nous rentrerons dans le détail de ce fonctionnement dans la suite.

Outils de développement

Google fourni des plugins Flutter pour l’IDE IntelliJ, Android Studio et Visual Code.

Le plugin flutter intelliJ
Le plugin flutter intelliJ

Et on notera que Flutter semble bien lié (au niveau de ses équipes de développement notament) à l’OS Fuschia, OS sur lequel Google planche.

Bon, et alors me demanderez-vous… qu’y a-t-il de si particulier dans cette technologie ? Attachez vos ceintures, la suite sera un peu technique… et historique !

Pourquoi Flutter est-il révolutionnaire ?

Petite histoire du développement mobile…

Le développement d’applications mobiles est somme toute assez récent, pas de surprise donc à ce que les outils associés évoluent encore.

Les SDK iOS et Android

Apple lance son SDK en 2008, Google en 2009, chacun basé sur son langage propre : Objective-C et Java.

L’application communique avec la plateforme pour créer des widgets ou accéder à des services comme l’appareil photo. Le rendu des widgets est fait sur un Canvas et les événements sont renvoyés aux widgets. C’est une architecture assez simple, cependant, il faut créer des applications différentes pour chaque plateforme car les widgets et le langage de développement sont différents chez iOS et Android.

Les WebViews

Les premières plateformes multi-OS se sont basées sur le Javascript et les webviews. On pourra citer différents frameworks:  Titanium, PhoneGap, Cordova, Ionic…

Avant de publier son SDK iOS, Apple encourageait les développeurs à développer des webapps pour l’iPhone… l’utilisation des technologies web pour faire du cross-platform s’est donc imposé comme une évidence.

L’application génère du HTML et l’affiche dans une WebView sur la plateforme. Puisqu’il n’est pas aisé (et parfois pas possible) d’utiliser directement le Javascript pour communiquer avec les services du téléphone, l’utilisation d’un pont (“bridge”) est devenu nécessaire pour faire communiquer les deux environnements. Tant que les services ne sont pas appelés trop souvent, l’utilisation de ce pont n’impacte pas trop les performances des applications.

Les applications Reactive

Des plateformes réactives comme ReactJS ont été ensuite plébiscitées, car elles simplifient la création des webviews. En 2015, la création de React Native a apporté ces technologies au monde du mobile.

React Native est populaire à juste titre, mais comme un accès est nécessaire entre l’environnement Javascript et l’environnement du téléphone, l’utilisation d’un pont est indispensable. Les widgets du téléphone sont appelés relativement souvent (60 fois par seconde lors d’animations par exemple). Cela peut donc engendrer des problèmes de performance. Tout l’art du développement React Native est donc de minimiser ce qui passe par le pont (ce qui se passe dans chaque environnement est rapide, c’est la communication entre environnements qui devient le goulot d’étranglement).

Flutter (nous y voilà !)

Flutter propose des vues dynamiques similaire à React Native. Ce framework choisit cependant une approche différente pour réduire les problématiques de performance (dues au pont). Ainsi, Flutter a choisi d’utiliser Dart, un langage compilé (contrairement au Javascript).

Dart est compilé “en amont” en code natif pour les différentes plateformes cibles. Cela permet à Flutter de communiquer avec la plateforme sans passer par un pont (“bridge”, permettant de passer d’un contexte à l’autre). Le fait de compiler le code permet également de réduire le temps de démarrage de l’application.

Le fait que Flutter soir le seul SDK mobile proposant des vues dynamiques sans pour autant passer par un pont Javascript le rend déjà particulièrement intéressant… mais il y a bien plus révolutionnaire ! C’est sa gestion des widgets.

Widgets

Les widgets sont les éléments qui constituent l’interface d’une application. On peut aller jusqu’à dire que les widgets sont les éléments les plus importants du développement mobile. Ce sont souvent par les widgets qu’une application fonctionne parfaitement ou au contraire semble inutilisable.

  • le rendu visuel et l’interaction avec le widget sont clés ! Les widgets doivent non seulement être esthétiques et adaptés, quelle que soit la taille de l’écran. Ils doivent aussi donner une expérience d’interaction naturelle.

 

  • les widgets doivent être rapides dans leur affichage et leur utilisation.

 

  • enfin, les widgets doivent être personnalisables et pouvoir être modifiés et étendus afin de répondre aux besoins de l’application.

 

Flutter propose une nouvelle architecture où les widgets sont beaux, rapides, extensibles et personnalisables. En fait, Flutter n’utilise pas les widgets du téléphone ou du web. Il propose ses propres widgets.

Flutter déplace les widgets et le rendu dans l’application. Cela permet aux widgets d’être personnalisables et extensibles. Tout ce dont Flutter a besoin de la part de la plateforme est le Canvas dans lequel afficher le rendu du widget afin qu’il apparaisse à l’écran, qu’il puisse recevoir des événements (clics, gestes) et accéder aux services (GPS, appareil photo etc).

Il y a donc toujours une interface entre le programme en Dart (en vert) et le code de la plateforme (en bleu, pour iOS et Android). Cette interface se charge de l’encodage et du décodage des données… mais cette interface est incomparablement plus rapide que le pont Javascript.

Le fait de déplacer les widgets et le moteur de rendu dans l’application ne modifie pas son poids. Le poids minimum d’une application Flutter sur Android est d’environ 6.7MB, ce qui est comparable au poids d’applications construites avec des outils similaires.

C’est finalement à nous de déterminer si Flutter apporte suffisamment d’avantages pour s’y mettre… c’est ce dont nous allons discuter par la suite.

La disposition des éléments

Une des grandes améliorations apportées par Flutter est sa gestion de la disposition des éléments. La disposition (“layout”) détermine la taille et la position des widgets en fonction d’un ensemble de règles (ou contraintes).

D’habitude, le layout utilise un vaste ensemble de règles qui peuvent être appliquées à n’importe quel widget. Prenons comme exemple le CSS, qui est plutôt bien connu (mais le layout iOS ou Android est tout à fait similaire). Le CSS a des propriétés (les règles) qui sont appliquées à des éléments HTML (les widgets). CSS3 propose 375 propriétés.

Le CSS inclut plusieurs modèles de positionnement différents parmi lesquels : des modèles de containeurs, des éléments flottants, des tableaux, du texte en colonnes, des média paginés etc. D’autres modèles, comme les flexbox et les grilles ont ensuite été ajoutées car les développeurs et designers ont eu besoin de gagner en contrôle sur le positionnement (ils utilisaient alors des tableaux et des pixels transparents pour positionner correctement leurs éléments). Dans le système de positionnement traditionnel, un nouveau modèle de positionnement ne peut pas être ajouté par le développeur, flexbox et les grilles ont donc dû être ajoutées à CSS et implémentés dans tous les navigateurs.

Une autre problématique des systèmes traditionnels de positionnement est que plusieurs règles peuvent interagir et entrer en conflit sur un même élément; et chaque élément a régulièrement des dizaines de règles qui s’appliquent à lui. Cela rend le positionnement lent. Pire, la performance de positionnement des éléments est généralement d’ordre N2 par rapport au nombre d’éléments… Plus on a d’éléments, plus le positionnement des éléments ralentit.

Flutter a commencé comme expérimentation par des membres de l’équipe du navigateur Chrome, chez Google. Ils ont cherché à voir si un moteur de rendu plus rapide pouvait être créé en modifiant les règles de positionnement traditionnelles. Après quelques semaines, ils ont obtenu des améliorations significatives des performances. Ils ont identifié différents éléments :

  • la plupart des dispositions sont relativement simples : du texte sur une page pouvant défiler, des rectangles dont la taille dépend de la taille de l’écran, quelques tableaux ou éléments flottants.
  • les dispositions font très souvent partie d’un sous-arbre de widgets, et ce sous-arbre utilise un seul modèle de positionnement; donc ces widgets ne devraient supporter qu’un nombre limité de règles.

Ils en ont conclu que la disposition des événements pouvait être significativement simplifiée en changeant radicalement d’approche :

  • au lieu d’avoir un large ensemble de règles pouvant être appliquées à chaque widget, chaque widget spécificiera son modèle de positionnement propre.
  • puisque chaque widget a alors un nombre beaucoup plus réduit de règles de positionnement, le positionnement peut être largement optimisé.
  • pour simplifier un peu plus, tout ce qui sera manipulé sera transformé en widget.

Voici un exemple de code Flutter pour créer un widget simple et son positionnement :

new Center(
  child: new Column(
    children: [
      new Text('Hello, World!')),
      new Icon(Icons.star, color: Colors.green)
    ]
  )
)

Le code est suffisamment simple pour que vous puissiez imaginer ce qu’il va afficher, mais voici le résultat :

Dans ce code, tout élément est un widget, notamment le positionnement. Le widget Center  centre des widgets « enfants » dans un widget « parent » (par exemple l’écran). Le widget de positionnement Column positionne ses « enfants » (une liste de widgets) verticalement. La colonne contient un widget Text et un widget Icon (qui a une propriété : sa couleur).

En effet, dans Flutter, le centrage ou les marges internes sont des widgets qui s’appliquent à leurs enfants. L’application elle même est un widget, tout comme la navigation.

Flutter inclut plusieurs widgets de positionnement: colonnes, lignes, grilles etc. De plus, Flutter a un système de positionnement unique nommé “positionnement en ruban” (sliver layout model), utilisé pour permettre l’utilisation des ascenseurs de page.

Le positionnement dans Flutter est si rapide qu’il peut être utilisé pour le défilement. Réfléchissez-y un moment. Le défilement doit être absolument instantané et fluide de manière à ce que l’utilisateur ait l’impression que l’image de l’écran est attachée à son doigt lorsqu’il le fait glisser sur l’écran physique.

En utilisant le layout pour le défilement, Flutter peut implémenter des types avancés de défilement, comme ceux ci-dessous. Notez qu’il s’agit ici de GIF animés, Flutter est encore plus fluide. Nous mettons le lien vers des applications en fin d’article pour que vous puissiez le tester avec de vraies applications.

Flutter gallery app
Posse demo app
Posse demo app

 

La plupart du temps, Flutter gère le positionnement en une seule passe, de manière linéaire, afin de pouvoir traiter un grand nombre de widgets. Et bien sûr, il gère un cache afin d’éviter tout calcul de positionnement inutile.

Personnalisation du design

Puisque les widgets font maintenant partie de l’application, de nouveaux widgets peuvent être créés, et les widgets existants peuvent être personnalisés pour en changer le comportement ou le look. La tendance en termes de design d’applications mobiles tend à s’éloigner de la standardisation à outrance que nous avons vue ces dernières années pour aller vers des designs spécifiques et personnalisés.

Flutter est livré avec un ensemble riche de widgets pour Android, iOS et Material Design (de fait, Flutter est le framework ayant probablement l’implémentation la plus fidèle des normes Material Design que Fidelisa affectionne particulièrement). Les développeurs d’applications peuvent utiliser la souplesse du modèle pour personnaliser ces widgets ou en créer de nouveaux en fonction de leurs besoins.

Plus d’information sur les vues réactives

Les bibliothèques gérant des webviews réactives ont introduit la notion de DOM virtuel. Le DOM est le “Document Object Model” HTML, une API utilisée par Javascript pour manipuler un document HTML, dans lequel le document est représenté par un arbre d’éléments. Le DOM Virtuel est une version abstraite de ce DOM.

Dans les webviews réactifs (par exemple avec ReactJS ou d’autres), le DOM virtuel n’est pas mutable et est reconstruit de zéro dès qu’un changement est fait. Le DOM virtuel est comparé au DOM réel pour lister un ensemble de changements minimum à exécuter. Ils sont alors exécutés pour mettre à jour le DOM. Enfin, la plateforme génère un rendu du DOM réel et le peint sur le Canvas.

Cette charge de travail peut sembler importante, mais elle vaut le coup car manipuler le DOM directement est très couteux en termes de performance.

React Native utilise le même procédé, mais pour les applications mobiles. Au lieu de manipuler le DOM, il manipule les widgets natifs de la plateforme mobile. Au lieu de manipuler un DOM virtuel, il construit un arbre virtuel de widgets et le compare à l’arbre de widgets natifs et ne met à jour que ceux qui ont changé.

Souvenez-vous que React Native doit communiquer avec les widgets natifs à travers un pont, donc l’arbre de widgets virtuel aide à minimiser ce qui est transmis à travers le pont, tout en permettant l’utilisation de widgets natifs. Enfin, une fois les widgets natifs mis à jour, la plateforme génère le rendu sur le Canvas.

React Native est une belle avancée pour le développement mobile et a été une source d’inspiration pour Flutter, mais Flutter pousse le principe un cran plus loin.

Souvenez-vous qu’avec Flutter, les widgets et le moteur de rendu sont remontés au niveau de l’application. Il n’y a pas de widgets natifs à manipuler… et l’arbre de widgets virtuel est donc en fait l’arbre de widgets tout court. Flutter génère le rendu de l’arbre de widgets et le peint sur le canvas de la plateforme : simple et (diablement) efficace.

Le moteur de rendu de Flutter en lui-même est intéressant : il utilise un ensemble de structures en arbre interne pour générer le rendu des widgets qui doivent être mis à jour sur l’écran. Les widgets qui n’ont pas été modifiés, même ceux qui ont simplement été déplacés, sont servis depuis le cache, ce qui est incroyablement rapide. C’est une des choses qui rendent le défilement si performant avec Flutter.

Si vous voulez plus d’informations sur le moteur de rendu de Flutter, voici une vidéo qui devrait vous intéresser.

Vous pouvez également explorer le code source de Flutter, car Flutter est open source. Vous pouvez donc bien sûr modifier et personnaliser tout ou partie de l’ensemble (moteur de rendu, moteur d’animations, moteur de reconnaissance de gestes, widgets etc.)

Le langage de programmation Dart

Flutter, comme les autres systèmes utilisant des vues réactives, rafraichit la vue à chaque nouvelle image. Il crée donc de nombreux objets qui ne vivront que le temps d’une image (soit un soixantième de seconde). Fort heureusement, Dart utilise un système de “garbage collector” générationnel qui est très efficace pour ces objets éphémères. De plus, l’allocation des objets peut être fait avec un pointeur simple, ce qui est rapide et ne demande pas de système de lock. Dart possède également un compilateur qui inclut uniquement le code nécessaire à votre application : vous pouvez utiliser une large librairie de widgets même si vous en utilisez seulement un ou deux.

“Hot reload”

Une des fonctionnalités populaires de Flutter est sa capacité à effectuer des “hot reload” dynamiques. Vous pouvez ainsi effectuer des changements dans une app Flutter alors qu’elle tourne, et cela rechargera le code de l’app qui a changé et le laissera reprendre là où elle en était, la plupart de temps quasiment instantanément.

Ainsi, si l’application rencontre une erreur, vous pouvez corriger cette erreur et continuer comme si l’erreur n’avait jamais existé. Et même si vous avez à effectuer un rechargement complet de l’application… c’est vraiment rapide.

Les développeurs disent donc que cela leur permet de “peindre” leur application, en faisant un changement à la fois, et en voyant le résultat quasiment instantanément, sans avoir à la redémarrer.

Compatibilité

Puisque les widgets et le moteur de rendu font maintenant partie de l’application et non de la plateforme, nul besoin de bibliothèque de compatibilité pour s’adapter à certaines plateformes. Vos apps fonctionneront, et de la même manière quelque soit la version (récente) des OS – Android Jelly Bean et plus récent et iOS 8.0 et plus récent. Cela réduit largement le temps de test pour les versions plus anciennes des OS. Et votre application devrait rester compatible avec les versions futures des OS.

Une question se pose alors : puisque Flutter n’utilise pas les widgets natifs, combien de temps faudra-t-il aux widgets Flutter pour être mis à jour lorsqu’une nouvelle version d’iOS ou Android sortira avec un nouveau widget ou avec un changement de look des widget existants ?

Plusieurs éléments peuvent nous rassurer :

  • Google utilise largement Flutter en interne et a donc intérêt à garder à rester proche des widgets OEM existants.
  • si pour une raison ou une autre Google est trop lent à faire évoluer Flutter, n’importe qui peut le faire en personnalisant ou en étendant des widgets existant… même nous. Nous pouvons donc toujours avancer avec ou sans mise à jour de la part de Google.
  • les points ci-dessus n’ont lieu d’être que si l’on souhaite que les changements impactent notre application. Si on ne veut pas modifier notre application suite aux changements propres aux OS, il n’y a rien à faire ! Les widgets sont dans l’application, donc un changement de widget du côté de l’OS n’aura pas d’impact (négatif, en s’intégrant mal par exemple) dans notre application si nous choisissons de ne pas la modifier.
  • enfin, nous pourrons modifier une app afin qu’elle utilise un nouveau widget disponible et ce, même dans les versions plus anciennes des OS !

Autres avantages

La simplicité de Flutter le rend rapide, et ses possibilités de personnalisation et d’extension le rendent puissant.

Dart a un dépot de paquets logiciels afin d’étendre les capacités de nos applications. On retrouve par exemple des paquets simplifiant l’utilisation de Firebase afin de créer une application sans serveur. On retrouve toutes sortes de contributions, par exemple également des paquets appelés “plugins” simplifiant l’accès aux services de la plateforme comme l’appareil photo ou l’accéléromètre quel que soit l’OS.

Enfin, Flutter est open source. Couplé au fait que le moteur de rendu fait partie de notre application, nous pouvons personnaliser à peu près tous les éléments de notre application. Voici (en vert) ce qui peut être personnalisé :

En résumé, qu’est-ce qui rend Flutter si intéressant et nouveau ?

Si on devait résumer le long texte ci-dessus, on pourrait dire :

  • on a l’avantage des vues réactives, sans passer par un pont Javascript
  • c’est rapide et fluide; il s’agit de code natif compilé
  • le développeur a un contrôle total sur les widgets et la disposition des éléments
  • plein de beaux widgets personnalisables sont déjà intégrés
  • de bons outils de développement intégrés… et le hot reload !
  • plus de performance, plus de compatibilité

Et nous oublions probablement l’essentiel… tellement essentiel qu’il parait évident :

Flutter permet de construire des applications rapides et performantes pour différentes plateformes à partir d’un code commun !

Quelques liens pour aller plus loin :

Vous souhaitez en discuter ? Contactez-nous.