React Native et CodePush : déployer sans compter

React Native et CodePush : déployer sans compter

Les frontières entre développement mobile et développement Web sont devenues de plus en plus poreuses. On doit ce constat en partie à React Native : base de code en JavaScript, outillage complet apportant un confort de développement rare en mobile sans pour autant laisser les performances de côté ✨.

Reste une forte contrainte quant au déploiement : même s’il s’est considérablement amélioré depuis quelques années, le délai entre la mise en production et la disponibilité d’une application reste assez long (deux jours en moyenne sur iOS ⌛️), contrairement à un projet Web, dans lequel le déploiement continu est possible et permet une plus grande agilité.

Agilité difficile à retrouver au niveau des applications mobiles : même si la mise à jour a été publiée sur le store, c’est à l’utilisateur de l’installer. Ainsi des bugs, bien qu’identifiés et corrigés, peuvent toujours subsister, engendrant inéluctablement des versions d’applications hétérogènes. Cette problématique demande donc un effort de rétro-compatibilité conséquent (problématique de versionning d’API, etc…).


Jour de chance : ne passez pas par la case Store 🎆

Encore une fois, l’écosystème React Native nous apporte une solution par l’intermédiaire de CodePush (développé par Microsoft). Ce dernier permet de mettre à jour vos applications sans passer par les stores et ce de façon quasi instantanée.

CodePush est un service composé de plusieurs briques :

Le fonctionnement est simple :

  • vous écrivez votre bout de code ;
  • vous envoyez la mise à jour via le CLI ;
  • l’utilisateur ouvre son app, la mise à jour se télécharge selon une stratégie définie (arrière-plan, demande explicite…) ;
  • vous êtes content et l’utilisateur aussi 👩‍❤️‍👩.

En coulisses, c’est plutôt simple : une application React Native est composée d’un fichier binaire spécifique à la plateforme (Android / iOS) et d’un fichier bundle JS (généré par le packager de React Native). C’est ce dernier que CodePush va mettre à jour. Vous publiez votre nouveau bundle JS (sa totalité, il n’y a pas de gestion de “diff”) sur un serveur, le client installé dans votre application vérifie si une mise à jour est disponible, la télécharge et remplace l’ancien bundle. Si plusieurs mises à jour sont disponibles, il installera simplement la dernière.

CodePush peut donc mettre à jour uniquement le code JavaScript et certains assets de votre application. Il ne peut en aucun cas mettre à jour du code natif Android ou iOS. Concernant les assets, la liste des composants supportés est donnée ici.


Implémentation dans React Native 🤓

Afin de vous épargner quelques clics dans la doc, voici un récapitulatif de l’installation de CodePush au sein d’une application React Native :

1 – Installez l’outil CLI

$ yarn global add code-push-cli

2 – Créez un compte CodePush et connectez-vous

$ code-push register

Votre navigateur s’ouvre alors sur le Mobile Center, vous proposant de créer un compte. Terminez la procédure puis entrez le token donné dans votre console :

$ code-push register
Please login to Mobile Center in the browser window we've just opened.

Enter your token from the browser:

Le CLI va alors créer un fichier de config avec votre token (~/.code-push.config).

3 – Créez vos applications sur CodePush

Il est nécessaire d’en créer une par plateforme :

$ code-push app add <app_name_ios> ios react-native
$ code-push app add <app_name_android> android react-native

CodePush va vous afficher des clés de déploiement utiles pour la phase de release.

Applications

4 – Connectez votre application React Native

Ajoutez la librairie CodePush à votre project React Native :

$ yarn add react-native-code-push

Liez votre librairie à votre projet iOS/Android en renseignant vos clés de déploiement lorsque l’on vous les demande :

$ react-native link react-native-code-push

Enfin, connectez le composant racine de votre app avec codePush() :

import React from 'react';
import { View, Text } from 'react-native';
import codePush from "react-native-code-push";

const App = () => <View style={{ backgroundColor: "whitesmoke" }}><Text>Hello world</Text></View>;

export default codePush(App);

Et voilà ! Votre application est prête à recevoir des mises à jour ✨.

5 – Modifiez votre code

Nous allons modifier la couleur de la vue pour une couleur verte chartreuse 🍻

import React from 'react';
import { View, Text } from 'react-native';
import codePush from "react-native-code-push";

const App = () => <View style={{ backgroundColor: "chartreuse" }}><Text>Hello world</Text></View>;

export default codePush(App);

Ceci-fait, envoyez votre mise à jour sur les serveurs du Mobile Center avec le CLI :

$ code-push release-react MyApp-iOS ios

Par défaut, le déploiement se fait sur l’environnement de Staging, vous pouvez envoyer votre release en production grâce à l’option --deploymentName :

$ code-push release-react MyApp-iOS ios --deploymentName Production

Vos utilisateurs bénéficieront alors de votre mise à jour au lancement de l’application.

Déploiement


Stratégies de mise à jour ⛳️

Il est possible de choisir sa stratégie de mise à jour du code lors du lancement de l’application. C’est à vous de choisir celle qui s’intégrera le mieux à votre application. Le composant de CodePush est assez flexible et vous offre de nombreuses options / hooks pour implémenter votre stratégie. En voici quelques-unes :

Mise à jour en arrière plan + installation au prochain démarrage

const App = () => <Text>Hello world</Text>
export default codePush(App);

C’est la stratégie par défaut de CodePush (sans aucune configuration). CodePush va télécharger le bundle JS dès que possible et l’installer au prochain démarrage. La mise à jour est transparente mais peut mettre un peu de temps à être installée, car l’application doit être relancée.

Mise à jour en arrière plan + installation lorsque l’app revient de l’arrière plan

const App = () => <Text>Hello world</Text>
export default codePush({ checkFrequency: codePush.CheckFrequency.ON_APP_RESUME, installMode: codePush.InstallMode.ON_NEXT_RESUME })(App);

Même workflow que précédemment mis à part que la mise à jour est appliquée lorsque l’app revient de l’arrière plan (et non lorsqu’elle est arrêtée/relancée).

Mise à jour explicite avec une alerte

const App = () => <Text>Hello world</Text>
export default codePush({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE })(App);

Lorsque la mise à jour est dispo, une alerte s’affiche proposant à l’utilisateur de l’installer (lors de la release vous pouvez ajouter l’option --mandatory pour la rendre obligatoire). Attention cependant les conditions d’Apple pour iOS interdisent d’afficher une alerte de mise à jour, privilégiez donc ce comportement avec des applications Android.

Aussi, CodePush met à votre disposition des méthodes de cycle de vie codePushStatusDidChange() et codePushDownloadDidProgress() appelées à chaque étape importante :

class MyApp extends Component {
    codePushStatusDidChange(status) {
        switch(status) {
            case codePush.SyncStatus.CHECKING_FOR_UPDATE:
                console.log("Checking for updates.");
                break;
            case codePush.SyncStatus.DOWNLOADING_PACKAGE:
                console.log("Downloading package.");
                break;
            case codePush.SyncStatus.INSTALLING_UPDATE:
                console.log("Installing update.");
                break;
            case codePush.SyncStatus.UP_TO_DATE:
                console.log("Up-to-date.");
                break;
            case codePush.SyncStatus.UPDATE_INSTALLED:
                console.log("Update installed.");
                break;
        }
    }

    codePushDownloadDidProgress(progress) {
        console.log(progress.receivedBytes + " of " + progress.totalBytes + " received.");
    }
}

MyApp = codePush(MyApp);

Cela permet d’intégrer au mieux la mise à jour : barre de progression, mise à jour de l’interface…


Sécurité 🔐

Mettre à jour votre application à la volée est une opération assez critique. Afin de garantir l’intégrité du code, CodePush propose de signer le bundle généré, la signature de celui-ci sera alors vérifiée lors de son installation côté client. Il vous faudra générer une clé asymétrique (publique/privée) :

$ openssl genrsa -out private.pem
$ openssl rsa -pubout -in private.pem -out public.pem

Vous devez alors utiliser l’option --privateKeyPath lors de la release de votre bundle pour signer votre code. Les détails sur cette fonctionnalité se trouvent ici.


Utilisations 🔎

L’utilisation de CodePush au sein de son application peut répondre à plusieurs cas :

✨ Résolution de bugs

Le cas le plus général est celui de la résolution de bugs. CodePush est l’outil parfait pour délivrer rapidement des hotfixs sur vos applications.

✨ Amélioration de l’UX/UI

Vous pouvez également mettre à jour des petits détails de vos UIs, des informations utiles à l’expérience utilisateur. Ou même changer le design de votre application un jour donné (Noël, Pâques …) si cela vous fait plaisir.

✨ A/B testing

Chose que je n’ai pas signalée, CodePush permet de déployer des releases sur un pourcentage d’utilisateurs donné. Il devient alors aisé de faire du A/B testing dans votre application. La commande suivante permet de mettre en production une release de Staging vers Production sur 42% des utilisateurs :

$ code-push promote <APP_NAME> Staging Production -r 42

✨ Easter eggs

Changer d’easter eggs toutes les semaines. 😎


Témoignages 🎙

En pratique, cela améliore grandement l’agilité de tous les acteurs d’un projet :

Le développeur

« Je peux enfin hotfixer mes applications le vendredi sans devoir rejouer toute la chaîne de build. » @Thibault

L’intégrateur

« Ce décalage de 1 pixel est désormais un mauvais souvenir, j’ai pu le corriger illico presto. Mon œuvre est totale. » @Jonathan

Le e-marketeur

« Nous avons pu lancer notre nouvelle campagne disruptive sociale, le plan de tagguage dans l’app a été modifié ASAP avec un Time To Market minimal. » @Anthony


Mot de la fin 👋

CodePush est donc un très bon outil à ajouter dans son workflow afin de gagner en agilité sur les projets mobiles pour toutes les raisons évoquées ci-dessus. On notera tout de même quelques contraintes :

  • Application dépendante d’un outil SaaS ;
  • Limitation des mises à jour au code JavaScript ;
  • Limite des mises à jour OTA (Over The Air) avec Apple : il ne faut pas qu’elle apporte de grosses fonctionnalités. Dans ce cas, il faudra passer par une mise à jour classique via l’App Store ;
  • Flou quant au coût éventuel du service. Pour l’instant il est complètement gratuit et sans limite, à voir comment le produit évolue.

Ayant ces quelques points en tête, n’hésitez pas à essayer CodePush sur vos applications React Native, je suis convaincu de la légitimité d’un tel outil.

Happy Coding ✌️

Nos formations sur le sujet

  • React Native

    Développez des applications mobiles natives et cross-platform pour iOS et Android grâce à React Native.

blog comments powered by Disqus