Flutter

La future ex techno mobile?

Sommaire

1

1. Introduction à Flutter

2. Widgets everywhere

3. Le langage Dart

4. Gestion du State

5. Retours d'expériences & à priori

featuring...

Jamy, t'es où?

J'ai un gros souci (comme d'hab)!

J'ai promis à ma mère de lui développer une appli mobile pour son commerce d'herbes provençales, mais...

Développer en Android ET en iOS, ça coûte un bras!

Et React Native, c'est un peu has been!

1. Introduction

2

Ah mais bouge pas mon p'tit Fred, j'ai la solution à tes problèmes!

C'est nouveau, ça vient de sortir, et c'est from Google!

1. Introduction

3

Et pourquoi c'est si bien que ça Jamy?

Mais pour plein de raisons mon petit Fred!

GOOGLE

SDK officiel de dev Fuchsia

Multi device sans bridge JS

Moteur de rendu custom

Basé sur Dart

Everything is widget

Communauté

Tooling

1. Introduction

5

. Made by Google

. Version 1.0 en Décembre 2018

. SDK de développement officiel de Fuchsia

. Utilise les langage & SDK Dart

1. Introduction

6

. Moteur de rendu custom

. Gère chaque pixel à l'écran

. Utilise la librairie Skia

. Plus besoin de bridge JS

. Compilé AOT en code natif ARM

1. Introduction

7

. Ecriture de composants thémés Material & Cupertino

. Pas (encore) de switch automatique...

. Besoin de reproduire les widgets natifs :

1. Introduction

8

Ca m'a l'air super ça Jamy!

Mais plus concrétement, ça ressemble à quoi?

Bah c'est pas compliqué : des Widgets et du Dart

Ca m'avance pas trop...

2. Widgets everywhere

9

. Good look and feel

. Fast (very)

. Customisable & extensible

2. Widgets everywhere

10

. Petit trade off :

. Moteur de rendu embarqué dans le livrable

. Taille min d'APK : environ 4.7Mb

2. Widgets everywhere

11

new Card(
  child: new Center(
    child: new Column(
      children: [
        new Text('Pizza Time!')),
        new Icon(Icons.star, color: Colors.yellow)
      ]
    )
  )
)

. Pour ceux qui n'ont pas fait de React...

. Voici à quoi ressemblent les Widgets :

. TOUT EST WIDGET

. WIDGET TREE

2. Widgets everywhere

12

@override
Widget build(BuildContext context){
  return new Scaffold(
    appBar: new AppBar(
      title: new Text(widget.title),
    ),
    body: new Center(
      child: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          new Text('You have pushed the button this many times:'),
          new Text(
            '$_counter',
            style: Theme.of(context).textTheme.display1,
          ),
        ],
      ),
    ),
    floatingActionButton: new FloatingActionButton(
      onPressed: _incrementCounter,
      tooltip: 'Increment',
      child: new Icon(Icons.add),
    ),
  );
}

. Exemple de widget tree "complet" :

2. Widgets everywhere

13

MyApp

MaterialApp

MyHomePage

Scaffold

AppBar

Text

Center

Column

FloatingActionButton

Icon

Text

Text

Phase de Layout

Constraints

Layout Details

2. Widgets everywhere

14

C'est ça Fred!

OK Jamy, c'est easy donc...

J'empile mes Widgets et c'est tout?

Et selon le besoin, des StatelessWidget, des StatefulWidget, des InheritedWidget, etc

Euh... ?

2. Widgets everywhere

15

C'est pas compliqué Fred...

. La StatelessWidget effectue le rendu de ce qu'on lui passe.

class TitleWidget extends StatelessWidget {

  const TitleWidget(this.title, {
    Key key,
  }): assert(title != null), super(key:key);

  final String title;

  @override
  Widget build(BuildContext context){
    return Text(title, style: Styles.title);
  }
}

2. Widgets everywhere

16

. Le StatefulWidget gère un State interne... ;)

class CounterWidget extends StatefulWidget {
  CounterWidget({ Key key, this.initialCount }): super(key: key);
	
  final number initialCount;
	
  @override
  _CounterWidgetState createState() => new _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  number _count;

  @override
  void initState() {
    super.initState();
    this._count = this.widget.initialCount;
  }
	
  @override
  Widget build(BuildContext context){
    return RaisedButton.icon(
      icon: const Icon(Icons.add, size: 18.0),
      label: const Text('Current count is $_counter'),
      onPressed: () => setState(() => this._counter++),
    );
  }
}

2. Widgets everywhere

17

Tiens Fred, question!

Un formulaire de login...

Stateless ou Stateful?

Euh... ?

2. Widgets everywhere

18

. L'InheritedWidget permet le partage de données.

. Uniquement pour ses enfants dans le Widget tree.

class MyInheritedWidget extends InheritedWidget {
   MyInheritedWidget({
      Key key,
      @required Widget child,
      this.user,
   }): super(key: key, child: child);
	
   final User user;
	
   static MyInheritedWidget of(BuildContext context) {
      return context.inheritFromWidgetOfExactType(MyInheritedWidget);
   }

   @override
   bool updateShouldNotify(MyInheritedWidget oldWidget) => user!= oldWidget.user;
}

2. Widgets everywhere

19

. L'InheritedWidget permet le partage de données.

. Uniquement pour ses enfants dans le Widget tree.

class ParentWidget... {
  ...
  @override
  Widget build(BuildContext context) {
    return new MyInheritedWidget(
      user: user,
      child: ChildWidget(...)
    );
  }
}

class ChildWidget... {
   ...
   @override
   Widget build(BuildContext context){
      final MyInheritedWidget inheritedWidget = MyInheritedWidget.of(context);
		
      return new Container(
         color: inheritedWidget.user.name,
      );
   }
}

2. Widgets everywhere

20

Les plus :

. Facile à prendre en main

. Maintenabilité, factorisation

. Contrôle total sur le rendu de son application et ses mises à jour

Les moins :

. Beaucoup de widgets... 

. Attention aux performances

. Slivers

3. Le langage Dart

21

. Dart 2.0

. Orienté objet

. Mono thread

Gestion de l'asynchronisme avec les Future

On m'a dit que Kotlin/TS étaient mieux...

. Performant, compilation en code natif

3. Le langage Dart

22

. Facilités de développement :

user ??= User();
score = json['score']?.toDouble() ?? 0;
List<String>()
    ..addAll(_existingUsers)
    ..addAll(newUsers)
    ..sort(_sortUsers)
    ..forEach((user) => print("User : ${user.name}"));
class TextCollapsible extends StatefulWidget {
  const TextCollapsible(
    this.text,
    {
      Key key,
      this.numDisplayChars = 150
    }
  ) : assert(text != null),
      super(key: key);

3. Le langage Dart

23

. Mixins power :

. Une interface avec implémentation

class CircularPercentIndicatorState extends State<CircularPercentIndicator>
  with SingleTickerProviderStateMixin {

  ...
  _animationController = AnimationController(
    vsync : this,
    ...
mixin SingleTickerProviderStateMixin on State implements TickerProvider {
  ...
  @override
  Ticker createTicker(TickerCallback onTick) {
    ...

3. Le langage Dart

24

. Hooks power :

class Example extends HookWidget {
  final Duration duration;

  const Example({Key key, @required this.duration})
      : assert(duration != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = useAnimationController(duration: duration);
    return Container();
  }
}

3. Le langage Dart

25

. S'intègre parfaitement aux patterns de de développement Flutter :

final onTextChanged = PublishSubject<String>();

final Stream<List<User>> _users$ = onTextChanged
  .distinct()
  .debounce(const Duration(milliseconds: 250))
  .switchMap<List<User>>((String term) => _searchUsers(term))
  .startWith([]);
 @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<User>>(
      stream: _users$,
      builder: (BuildContext context, 
                AsyncSnapshot<List<User>> snapshot) {
        final List<User> users = snapshot.data;
        ...

. Aparté sur la librairie RxDart :

3. Le langage Dart

26

Les plus :

. Rapidité de développement

. Performances

. Facilité de prise en main

Les moins :

. Pas aussi poussé qu'un Kotlin ou un Typescript?

. Pas de spread operator ou de destructuring ;)

4. Gestion du State

27

Jamy, j'ai bien compris le fonctionnement des widgets...

Mais une question me taraude quand même...

Mes objets métiers globaux, je les mets où?

J'aurais bien une réponse Fred...

4. Gestion du State

28

Y a de la DI avec Flutter & Dart?

Bah je vais faire des singletons alors!

Tu sors.

Nan

4. Gestion du State

29

. Je crée mon StateContainer avec un InhéritedWidget.

class AppStateContainer extends StatefulWidget {
  ...
  static AppStateContainerState of(BuildContext context) {
    return ...;
  }
}

class AppStateContainerState extends State<AppStateContainer> {
  AppState _state;
  User get user => state.user;
  void addProduct(Product product) { setState(() => _state.user.addProduct(product)) }
  
  @override
  Widget build(BuildContext context) {
    return new _InheritedStateContainer(data : _state, child: ...);
  }
}

class _InheritedStateContainer extends InheritedWidget {
  final AppStateContainerState data;
  ...
  @override bool updateShouldNotify(_InheritedStateContainer old) => true;
}

4. Gestion du State

30

. Je crée mon StateContainer avec un InhéritedWidget.

. Oui, mais... ?

class AppState {
  bool isLoading;

  User user;
  Cart cart;
  List<Product> products;

  ...

  AppState({
    this.isLoading = false,
    this.user,
    this.cart,
    this.products
  });
class UserCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AppStateContainerState state =
      AppStateContainer.of(context);
    return new Text('${state.user?.name}');
  }
}
class CartWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AppStateContainerState state =
      AppStateContainer.of(context);
    ...
    return RaisedButton(
      child: Text('Add Item'),
      onPressed: () => state.addProduct(item)
    );
  }

4. Gestion du State

31

Un InheritedWidget pour chaque donnée du State...

Oui, et c'est pour ça que d'autres alternatives existent.

C'est un peu lourd ça non?

4. Gestion du State

32

. Gestion du State global de l'application.

. flutter_redux :

4. Gestion du State

33

. flutter_redux :

StoreProvider

State

StoreConnector

Widgets

Actions

Reducers

Middleware

4. Gestion du State

34

. Séparation UI - logique métier

. BLoC :

. Gestion du State local

. Basé sur les Streams :

. StreamController

. Sinks

. Streams

4. Gestion du State

35

. BLoC :

class CounterBloc {
  final StreamController<int> _counterController = StreamController<int>();

  Stream<int> get getCount => _counterController.stream;
  
  void updateCount(int newCount) {
    _counterController.sink.add(newCount);
  }
  
  void dispose() {
    _counterController.close();
  }
}

. Création du BLoC :

4. Gestion du State

36

 

. BLoC :

@override
Widget build(BuildContext context) {
  return StreamBuilder<int>(
    stream: bloc.getCount,
    initialData: 0,
    builder: (context, snapshot) => Row(
      children: [
         Text('${snapshot.data}'),
         RaisedButton(
           onPressed: () => bloc.updateCount(snapshot.data + 1),
           child: Text('Increment')
         )
      ]
    )
  );
}

. Utilisation dans mes widgets :

4. Gestion du State

37

. Combo flutter_redux & "BLoC"

. Le premier pour le State GLOBAL

. Le deuxième pour le State LOCAL

38

Jamy, j'ai quand même très peur...

Y a mon pote qui est expert mobile, il m'a dit que Flutter n'a aucun avenir...

Ah oui, il a eu une mauvaise expérience avec Flutter?

Non, il a lu un thread Reddit.

5. Retours d'expérience et à priori

39

Plugins pour la suite Intellij & VSCode

Jamy, Flutter c'est super récent, il doit y avoir 0 tooling :/

Flutter CLI

HOT HOT RELOADING

UI, CPU, Memory debug tools

etc...

5. Retours d'expérience et à priori

40

Communauté & doc très importantes

Jamy, et la communauté? Vais-je être seul avec mes questions?

5. Retours d'expérience et à priori

41

Nope. 7Mo en release pour une appli de 60+ widgets

Jamy, on m'a dit que la taille des livrables était monstrueuse :/

Jamy, on m'a dit que les perfs étaient pourries :/

En dev, oui. Mais aucun souci en release.

5. Retours d'expérience et à priori

5. Retours d'expérience et à priori

43

Jamy, et à choisir avec React Native?

etc...

En conclusion...

44

. Flutter est une solution viable pour la création d'applications mobiles multi-devices complexes.

. Est-ce le meilleur choix entre natif et React? Bah ça dépend ;)

Super ta conclusion...

En conclusion...

45

. Les plus :

. Moteur de rendu custom

. Hot reloading

. Widgets

. Dart

. Les moins :

. Moteur de rendu custom

. Widgets

. Debug & errors

flutter : retour d'expérience

By Laurent WROBLEWSKI

flutter : retour d'expérience

  • 1,213