Voici mon humble retour d’expérience sur un mois de développement sur React Native, ainsi que la publication d’une application dans le Play Store et Apple Store.

Le projet

Mapado permet au organisateurs d’évènements de vendre des billets pour leurs évènements. Nous avions besoin de proposer une solution pour pouvoir scanner les billets des participants.

Étant donné que nos utilisateurs cible sont de petites structures, nous voulions une solution accessible. Nous nous sommes donc penché sur un scan de billet par terminal mobile.

Le choix de la techno se posait entre Développement natif (rayé d’entré de jeu, on n’y connait rien + deux fois le code à produire / maintenir), Titanium, Cordova / Ionic et React native.

On a eu développé un projet en Titanium, mais vraiment trop la galère, vous pouvez échangez avec Sylvère sur twitter si vous avez des questions 🙂

Le choix s’est finalement vite réduit entre Ionic et React Native. Je vous passe les détails, mais on est parti sur ReactNative.

Mes connaissances avant le projet

Je suis un développeur web, prinpalement PHP. La norme ES2015 (ex-ES6) permet de faire des trucs cools en JS, donc je me mets au JS.
Je n’y connais rien à iOS, Objective-C / Swift ni Android, Le Java me rappelle de vieux souvenirs de mes études il y a 10 ans.

Sans être un grand virtuose de React et de son écosystème, j’ai travaillé en amont sur un projet assez gros fait en React avec Redux et Immutable (j’avais suivi cet excellent tuto).

React s’appréhende finalement assez vite, et c’est le bonheur à débugger comparé à son gros concurrent Angular : step-by-step dans le navigateur, brique fonctionnelles bien découplées, erreurs compréhensibles, etc.

Immutable a toujours quelques problèmes mais dans l’ensemble, ça fonctionne bien.

Redux est aussi assez simple à mettre en place, et les outils de dev sont vraiment très puissant. Je recommande chaudement l’extension Chrome Redux dev tools.

Découverte de React Native et de son écosystème

React native est plutôt simple à installer. Le plus bloquant étant finalement l’installation du SDK Android. Si vous n’avez pas un ordi qui est une bête de course, je vous recommande aussi d’utiliser Genymotion si vous codez pour un projet personnel.

React est shippé avec une page de démo et le tutoriel est assez simple mais couvre finalement bien la découverte de ReactNative.

Les vues sortent assez facilement, l’auto-reload est super efficace depuis la version 0.24. On peut débugger le JS dans Chrome, mettre des breakpoints et faire du step-by-step.

L’extension redux devtools fonctionnent aussi.

Installation de composants annexes

Pour scanner mes billets, j’ai eu besoin d’installer :

  • un détecteur de  code barre pour scanner les billets,
  • un composant pour lire un mp3 (on joue un son au scan d’un billet),
  • un composant pour laisser l’écran actif pendant le scan
  • Notre icon-font Mapado

IconFont

Là, ça se complique un peu: pour notre iconfont, pas de meilleurs choix que de passer par React Native Vector Icons. Ça fonctionne presque simplement mais ça installe plein de font qui ne m’intéresse pas, et c’est un peu galère d’installer un font custom. J’aurai bien aimé pourvoir utiliser des SVG directement, mais cela ne semble pas simple avec Android (même pas cherché sur iOS du coup).

Écran actif

Pour le fait de laisser l’écran actif pendant le scan, react-native-idle-timer fonctionne bien, est simple et cross-platform.

Lecture de média

Pour la lecture des MP3, j’ai opté pour react-native-sound :

  • Sur Android, super simple une fois qu’on a compris où mettre les fichiers dans le dossier android
  • Sur IOS, une vraie plaie, il faut référencer ses fichiers dans XCode, et au final je n’ai pas eu le choix que de mettre les fichiers à la racine (ou plutôt je n’ai pas trouvé).

Scan de code barre

Le scan de code barre était vraiment le côté le moins sympa. Aucune librairie commune iOS et Android gère bien le scan de code barre. react-native-camera à l’air le plus avancé, mais vraiment en beta pour Android (il faut utiliser la branche master, et pas mal de retours sur le côté non fonctionnel).

Pour Android du coup, j’ai utilisé react-native-barcodescanner.

L’écran de scan ressemble à ça:

écran scan billet 2écran de scan de billets

C’est un écran assez interactif qui à un “Header” plus un footer qui s’anime au scan d’un billet + avec des timeouts.

L’accès à l’appareil photo et le scan de code barre est très consommateur. J’ai eu des gros problèmes de lenteurs sur Android à cause de cet écran. Lorsque l’on passait en paysage, le composant affichait d’énormes barres noires et ne scannait plus de code barre, j’ai du coup interdit (à contre-cœur) à l’appli de passer en paysage.

En changeant le style (oui oui le style !), c’est mieux: le header et le footer sont en position “absolute” et le composant de scan est en full screen derrière.

Bref une bonne galère sur cet écran.

Ce que j’ai apprécié

Facebook travaille vraiment sur React et ReactNative et les mises à jour sont très fréquentes fréquentes.

Idem sur les composants externes, je trouve les mainteneurs des packages assez reactif et assez ouvert à la modification. On sent que l’écosystème est jeune et en pleine ébullition.

Facebook fait aussi un vrai effort travail d’uniformisation entre iOS et Android sur tout ce qui est possible, tout en gardant les spécificités de chaque OS (ex: loader multicolore sur Android). Microsoft est en train de faire le portage pour Windows, Windows Phone et Xbox. C’est vraiment très appréciable.

La stack de debug est vraiment puissante, le step by step dans le navigateur est top. La seule chose qui manque est de pouvoir voir les appels réseaux comme on le ferait en JS “classique”.

rnpm permet d’installer / linker vos dépendances facilement, que ce soit pour iOS ou Android. Ça fonctionne bien tant que votre composant n’est pas trop complexe (cf. plus loin le sdk facebook).

Les points de blocages

La navigation

Le composant de Navigation est un peu “étrange” à comprendre. Ce composant ré-implémente un navigation similaire à ce qui se fait dans un navigateur, à une différence prêt: les composants React ne sont pas “démontés” lorsque l’on change de page. Il faut vraiment le voir comme un “empilement” de composants tous actifs, jusqu’au moment au l’on “pop” cette page de la stack de navigation.

De plus, le code pour gérer les routes est un peu bizarre.

FlexboxNative

Avec ReactNative on peut faire du flexbox ! Youpi ! Sauf qu’il a une implémentation un peu étrange, qui fait que ce n’est pas aussi “puissant” que dans le navigateur. Couplé au fait que flexbox est assez complexe à appréhender et qu’on ne l’utilise toujours presque pas sur des applications Web, ce n’est pas forcément simple au début.

En plus de ça, il manque un moyen de pouvoir naviguer dans le “DOM” pour voir l’état d’un nœud.

L’enseignement que j’ai pu en tirer est vraiment de “Keep it Simple”. Si vous n’arrivez pas à faire quelque chose, alors repartez de la base.
La philosophie de React à ce sujet est que chaque composant doit être simple, et c’est vrai: plus c’est simple, plus c’est efficace 🙂

Facebook SDK

J’ai essayé d’installer un “simple” facebook connect. Facebook a pourtant développé le react-native-facebook-sdk mais ça doit être un composant assez “vieux” pour ReactNative.

Il ne s’installe pas avec rnpm, il y a énormément de fichiers à modifier dans les dossiers “iOS” et “Android”. Une fois installé, il faut installer nativement le SDK sur iOS et Android à priori. Surement une paille pour un habitué des dites plateformes, mais tellement complexe et aux antipodes de ce que ReactNative promet.

Facebook travaille dessus cela dit (edit du 21/05/2016 : la v0.2.0 indique avoir corrigé le tir sur rnpm. Je testerai ça)

La perf

C’est un gros sujet sur ReactNative, il y a une page complète sur la documentation officielle. Dans les quick wins que j’ai pu faire à ce sujet:

  • Utiliser le InteractionManager.runAfterInteractions
  • Faire les même optims que pour React, et en particulier optimiser vos méthodes “shouldComponentUpdate” des composants. Le module why-did-you-update a pas mal fait parler de lui il y a quelques jours, malheureusement je n’ai pas réussi à le faire fonctionner sur ReactNative. J’ai du coup fait les choses à la main composant par componsants:

iOS et Apple Store

Bon je passe sur le fait qu’il faut un Mac pour coder sur iOS. Je passe sur le fait que le simulateur n’autorise pas d’accéder à une webcam pour simuler la camera (pratique pour le scan 😉 ), et qu’il faut donc que je pique l’ordi de la graphiste (ça va, elle n’est pas là en ce moment), et les iPhones de mes collègues pour développer.

Le build sur Android est vraiment simple et très efficace. Rien à dire. Par contre pour builder sur iPhone, il faut aller modifier un fichier en fonction de si l’on veut utiliser son serveur de dev ou compiler les JS sur le terminal (le fichier “ios/NomDeLapp/AppDelegate.m”, pensez à le modifier avant de builder pour AppStore).

La génération des assets pour iOS est vraiment une plaie, il faut générer des images dans plein de tailles différentes.  La solution que je pense pas mal utilisent, c’est photoshop ou imagemagick pour changer les tailles. Ce n’est surement pas ce que Apple souhaite, mais ça passe, c’est juste chiant.

Générer le splash screen est assez chiant aussi quand on n’a pas l’habitude, c’est un écran à génerer dans XCode, avec plein de contraintes à gérer, et l’interface graphique de XCode c’est vraiment pas simple. J’aurais presque préféré modifier directement un fichier XML quelque part avec des liens sur des fichiers.

C’est assez connu, mais j’ai découvert ça: Apple est assez long et embêtant sur la publication dans le store, là ou chez Android, 30 minutes après la mise à jour est déployée sur les terminaux.

Conclusion

Je sais que j’ai listé pas mal de chose négatives, mais cette expérience sur ReactNative est vraiment positive pour moi. J’ai simplement listé tout ça pour vous aider a ne pas tomber dans les même panneaux que moi.

Déjà, si c’était à refaire, je le repasserai par React Native sans problème. Ce sera d’ailleurs surement notre plateforme pour travailler sur nos futurs apps et en particulier l’application Mapado.

Le petit plus

Nous sommes la billetterie du parc d’attraction Miniworld Lyon qui ouvre fin juin 2016. Ils ont eux le besoin de scanner des billets à l’entrée de tourniquets dans ce genre là.

Pas question d’avoir de scan Android ici mais des trucs bien plus efficace. La solution pour laquelle nous avons opté est un scanner branché en USB à un raspberry pi.

Étant donné que toute la logique de scan était déjà implémentée dans notre app, je ne voulais pas re-coder la même chose. Ce qui est cool, c’est que tout fonctionne simplement et parfaitement bien avec la stack et se greffe très bien redux + notre api + sdk Javascript. Plus de React ici, mais le seul code que j’ai eu à faire est de coder l’interface avec le scanner usb et la logique de récupération des billets qui est différente. Le code identique est mutualisé.

Bibliographie