Introduction
La production est un tout autre jeu que le développement. Cette liste de vérification vous donne un chemin pratique, testé sur le terrain, pour durcir une application React Native en vue de sa sortie, sécuriser les données et les paiements, ajouter du monitoring, améliorer la performance, planifier les mises en production et récupérer suite aux incidents sur Android, iOS et Expo.
Vue d'ensemble du flux de travail
Utilisez un flux simple et explicite pour réduire le rétravail et les surprises :
- Planifier : définir les appareils cibles, les versions d'OS et les métriques de succès (sessions sans crash > 99,5 %, démarrage à froid p50 < 2 s, taux d'erreur API < 0,5 %, taux de réussite paiement > 99 %).
- Configurer : activer les indicateurs de version (Hermes, minification, réduction des ressources, inline requires), le versioning et la séparation des environnements.
- Sécuriser : protéger les secrets, verrouiller le transport réseau et passer en revue les permissions.
- Instrumenter : rapport de crash, gestionnaires d'erreurs JS, métriques de performance et métier.
- Tester : tests de fumée sur appareils d'entrée et haut de gamme ; bac à sable paiement ; réseau hors ligne et instable.
- Déployer progressivement : testeurs internes, déploiements étagés, surveillance des tableaux de bord.
- Exploiter : monitoring, propriété d'astreinte, sauvegardes et mises à jour régulières.
Configuration et indicateurs de build
Durcissez les builds de version sur les deux plateformes.
- Général
- Définissez un ID d'application / bundle ID correct (ex.
com.entreprise.nomapp) et un versioning semver (ex.1.7.0) avec numéros de build incrémentés à chaque envoi sur les stores. - Désactivez les bibliothèques et logs réservés au débogage en version release.
- Séparez les points de terminaison et les clés pour dev, staging et production via
app.config.jsou fichiers.envpar environnement.
- Configuration Metro : accélérer le démarrage en différant les requires
// metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: { inlineRequires: true }
})
}
};
- Android (Gradle)
- Activez Hermes et R8, réduisez les ressources, séparez les ABIs pour réduire la taille de l'APK.
// android/app/build.gradle
project.ext.react = [ enableHermes: true ]
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
splits {
abi { enable true; reset(); include 'armeabi-v7a','arm64-v8a','x86_64'; universalApk false }
}
}
- Supprimez les logs en release via plugin Babel :
// babel.config.js
plugins: [
['transform-remove-console', { exclude: ['error', 'warn'] }]
]
- Configurez la config de sécurité réseau ; évitez le cleartext sauf si requis et limité. Exemple
res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.exemple.com</domain>
</domain-config>
</network-security-config>
- Configurez Play App Signing et des keystores sécurisés.
- iOS (Xcode)
- Activez Hermes dans le Podfile si vous l'utilisez, définissez les indicateurs Release (élimination du code mort, bitcode désactivé pour les chaînes d'outils actuelles, niveau d'optimisation
-Os). - Appliquez ATS (HTTPS) avec exceptions seulement si absolument requis et documentées dans
Info.plist. - Configurez le provisioning et la signature corrects pour Release.
Secrets et sécurité
- N'intégrez jamais de secrets de longue durée dans l'application. Gardez les clés privées sur le serveur.
- Stockez les jetons d'accès dans le stockage sécurisé de la plateforme :
- iOS : Keychain (restreindre le groupe d'accès et le niveau d'accessibilité selon les besoins, ex.
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly). - Android : EncryptedSharedPreferences ou stockage soutenu par Keystore.
- Évitez de stocker des secrets dans AsyncStorage.
- Paiements
- Stripe : conservez la clé publiable dans l'app, mais créez les clés éphémères côté serveur. Ne stockez pas les secrets clients sur l'appareil.
- Google Play Billing : validez les achats sur un serveur sécurisé ; ne faites pas confiance aux vérifications côté client uniquement.
- Permissions : demandez seulement le nécessaire ; fournissez une justification in-app ; gérez le refus avec élégance.
- Transport : imposez HTTPS/TLS, pinez les domaines si vous contrôlez le backend ; définissez des délais raisonnables (ex. 10 s connexion, 30 s lecture).
Monitoring et rapport de crash
- Ajoutez un rapporteur de crash (natif + JS) et du monitoring de performance (ex. Sentry, Datadog, Bugsnag).
- Initialisez tôt au démarrage de l'app et incluez la version, le numéro de build, l'appareil et l'ID utilisateur ou de session (respectez la vie privée et le consentement).
- Capturez les erreurs et rejets JS non gérés :
import { setJSExceptionHandler, setNativeExceptionHandler } from 'react-native-exception-handler';
setJSExceptionHandler((e, isFatal) => {
// envoyer à votre service de crash
Sentry.captureException(e);
}, true);
setNativeExceptionHandler(errorString => {
// envoyer infos crash natif
Sentry.captureMessage(errorString);
});
- Suivez : temps de démarrage (à froid/chaud), gels d'UI (> 16 ms chutes de frame), échecs réseau, résultats du flux paiement, et durées de transition d'écran.
- Alertes : définissez des seuils pour sessions sans crash (< 99,5 %), pics d'erreur (> 5 % en 5 min), abandons paiement (> 2 % déviation).
Performance et démarrage
- Utilisez Hermes pour un démarrage plus rapide et une mémoire réduite (généralement 20-30 % plus rapide TTI sur appareils d'entrée de gamme).
- Activez
inlineRequireset chargez paresseusement les écrans et modules lourds. - Évitez le travail coûteux au démarrage ; différez l'analytique et les récupérations non critiques jusqu'après le premier affichage.
- Optimisez les images : WebP/AVIF quand supporté, tailles correctes, mise en cache via en-têtes
cache: 'force-cache'. - Utilisez
FlatList/SectionListaveckeyExtractor,getItemLayoutquand possible ; évitez les tempêtes de re-rendu (mémoisez les props,useCallback/useMemoappropriément).
Réseau et résilience API
- Définissez délais et reprises avec recul exponentiel et gigue.
import axios from 'axios';
const api = axios.create({ baseURL: 'https://api.exemple.com', timeout: 10000 });
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const shouldRetry = (error) => !error.response || error.response.status >= 500;
api.interceptors.response.use(undefined, async (error) => {
const cfg = error.config;
cfg.__retryCount = cfg.__retryCount || 0;
if (cfg.__retryCount < 3 && shouldRetry(error)) {
cfg.__retryCount++;
const backoff = Math.min(1000 * 2 ** cfg.__retryCount, 8000);
const jitter = Math.random() * 500;
await delay(backoff + jitter);
return api(cfg);
}
return Promise.reject(error);
});
- Utilisez des clés d'idempotence pour les opérations d'écriture (surtout paiements).
- Support hors ligne : mettez en cache les lectures, mettez en file les écritures, et réconciliez au retour de la connectivité (utilisez
NetInfopour détecter le statut). - Validez SSL et appliquez ATS sur iOS. Évitez le trafic en clair ; si inévitable, limitez strictement hôtes et chemins.
Paiements : Play Billing et Stripe
- Google Play Billing (achats in-app ou abonnements)
- Utilisez le dernier BillingClient (v6+).
- Gérez les états d'achat :
Purchased,Pending, etUnspecified. Affichez une UI pour les achats en attente (ex. paiements en espèces dans certaines régions comme OXXO au Mexique ou Boleto au Brésil). - Acquittez toujours les achats sous 3 jours (consommables) ou avant d'accorder le droit (abonnements).
- Vérifiez les jetons d'achat côté serveur via l'API Play Developer.
- Supportez les montées/descentes d'abonnement et les modes de prorata (
IMMEDIATE_WITH_TIME_PRORATION, etc.). - Testez avec comptes test sous licence et produits bac à sable.
- Stripe (cartes, portefeuilles)
- Privilégiez
PaymentSheetpour un flux sécurisé et standardisé. - Générez les clés éphémères sur votre serveur ; n'intégrez jamais les clés secrètes dans l'app.
- Gérez l'authentification 3DS, le basculement d'app, et le cycle de vie
Activity/UIViewController. - Utilisez des clés d'idempotence pour les intentions de paiement afin d'éviter les doublons aux reprises.
- Journalisez les résultats des tentatives de paiement et corréléz avec les logs backend.
Considérations Expo
- Choisissez managed vs bare selon les besoins natifs.
- EAS Build
- Définissez des profils de build pour développement, prévisualisation et production.
- Utilisez les versions d'exécution et canaux pour une segmentation sûre des mises à jour.
- Mises à jour
- Utilisez les mises à jour OTA pour petits correctifs JS/assets conformes aux politiques des stores.
- Tout changement de module natif ou permission nécessite un nouveau build store.
- Config
- Maintenez
app.json/app.configen sync avec les métadonnées store (icônes, permissions, liens profonds, schémas).
Gestion des mises en production : Android et iOS
- Android
- Utilisez la piste de test interne pour tests de fumée, test fermé pour QA élargie, puis déploiement étagé vers la production (ex. 5 %, 25 %, 50 %, 100 %).
- Activez Play App Signing et les protections d'intégrité.
- Prévoyez un plan de retour arrière : arrêter le déploiement ou revenir à une version antérieure dans Play Console.
- iOS
- Utilisez TestFlight pour testeurs internes et externes (jusqu'à 10 k externes).
- Envisagez un déploiement progressif pour la production (options 1 jour, 7 jours, 30 jours).
- Fournissez les métadonnées de conformité et descriptions de permissions exactes dans App Store Connect.
- Versioning et métadonnées
- Utilisez le versioning sémantique pour la version marketing et incrémentez les numéros de build à chaque envoi.
- Maintenez des journaux de modifications et notes de mise à jour clairs.
Données, stockage et sauvegardes
- Classez les données : identifiants/jetons, contenu utilisateur, données API en cache, analytique.
- Stockez les données sensibles dans le stockage sécurisé ; jamais en clair dans fichiers ou AsyncStorage.
- Migrations : versionnez votre schéma pour SQLite ou magasins clé-valeur et testez montées et descentes de version.
- Sauvegardes Android
- Contrôlez la sauvegarde automatique avec un XML
fullBackupContentpour exclure les chemins sensibles (ex.shared_prefs,databases,files/keys). - Sauvegardes iOS
- Marquez les fichiers qui ne doivent pas être sauvegardés avec l'attribut
NSURLIsExcludedFromBackupKeyquand approprié. - Les éléments Keychain peuvent migrer lors des restaurations d'appareil ; prévoyez l'invalidation des jetons en conséquence (ex. lier jetons à l'ID appareil ou rotation au premier lancement après restauration).
- Coordination backend : assurez-vous que sauvegardes, rétention et exercices de restauration côté serveur s'alignent avec les attentes client.
Maintenance et SLO
- Définir des cibles
- Sessions sans crash : > 99,5 % (seuil Google Play "Excellent\u00a0\)).
- Démarrage à froid p50 < 2 s, p90 < 4 s sur appareils médians.
- Taux d'erreur API < 0,5 %, taux de réussite paiement > 99 %.
- Revues
- Revue monitoring hebdomadaire : crashes, ANR, régressions perf.
- Revue dépendances mensuelle : avis de sécurité et compatibilité (React Native, Gradle, Xcode, bibliothèques clés).
- Accès et clés
- Faites tourner les identifiants et nettoyez les accès inutilisés chaque trimestre.
Mises à niveau et compatibilité OS
- Planifiez des mises à niveau React Native et bibliothèques chaque trimestre ; évitez les grands sauts de version (ex. 0.72 -> 0.74, pas 0.70 -> 0.74).
- Suivez Android Gradle Plugin, Kotlin, Java, Xcode, Swift, et cibles SDK iOS/Android dans un fichier
VERSIONS.md. - Testez sur les dernières bêtas OS avant sortie publique ; corrigez les dépréciations tôt (ex. types de service foreground Android 14, manifestes de confidentialité iOS 17).
- Épinglez les versions de la chaîne d'outils dans
gradle.propertiesetPackage.swift/xcodeprojpour réduire les casses de build inattendues.
Réponse aux incidents et retours arrière
- Drapeaux de fonctionnalité et interrupteurs d'arrêt à distance (ex. LaunchDarkly, Firebase Remote Config) pour désactiver des fonctionnalités risquées sans mise à jour store.
- Stratégie de retour OTA (là où autorisé) pour correctifs JS-only via Expo Updates ou CodePush.
- Contrôles store
- Android : arrêter ou revenir sur déploiements étagés dans Play Console.
- iOS : retirer de la vente ou soumettre une revue accélérée pour correctifs urgents si nécessaire.
- Procédures
- Définissez les étapes pour panne paiement, panne API, et pic de crash.
- Incluez points de contact, liens logs, tableaux de bord, et arbres de décision (ex. "si sessions sans crash < 99 % pendant 15 min -> alerter astreinte -> vérifier Sentry -> si nouvelle version -> arrêter déploiement\u00a0\)).
Plan pilote local
Commencez petit pour vérifier rapidement et en toute sécurité.
Périmètre
- Activez Hermes et
inlineRequires. - Ajoutez le rapport de crash et capturez les erreurs JS non gérées.
- Enveloppez un appel API critique avec délais et recul, plus idempotence pour les écritures.
Vérification
- Mesurez le temps de démarrage à froid sur deux appareils (ex. Pixel 6a et Pixel 8) et comparez avant/après.
- Déclenchez une erreur JS gérée pour confirmer l'apparition dans le tableau de bord sous 60 secondes.
- Simulez des pannes réseau (mode avion, limitation) et confirmez les reprises et messages utilisateur.
Déploiement
- Envoyez sur une piste de test interne (Android) ou TestFlight (iOS) avec 10-20 testeurs.
- Critères de succès : aucun nouveau crash depuis les changements pilotes, démarrage à froid p50 amélioré > 10 %, et gestion d'erreur API vérifiée.
Conclusion
Une mise en production fiable provient d'opérations répétables : builds durcis, secrets sécurisés, monitoring robuste, performance ajustée, réseau résilient, gestion soignée des paiements, et déploiements disciplinés. Commencez par un pilote étroit, vérifiez les améliorations, puis étendez la couverture au reste de l'application. Maintenez les mises à niveau et la maintenance sur un rythme prévisible, et pratiquez les chemins de retour arrière avant d'en avoir besoin.