E-NO
Applications mobiles 8 min de lecture

Guide de dépannage React Native : Résolution d'incidents tenant compte des versions

calendar_today Publié : 2026-08-09
update Dernière mise à jour : 2026-08-09
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Guide de dépannage React Native : Résolution d'incidents tenant compte des versions ».

React Native combine JavaScript et les environnements d'exécution natifs, ce qui rend le débogage puissant mais parfois délicat. La voie la plus rapide pour sortir de la plupart des échecs est un flux de travail cohérent et reproductible en six étapes : inventorier votre environnement et vos versions, reproduire avec une portée réduite, capturer les bons journaux, appliquer le plus petit changement sûr, vérifier, et annuler proprement si nécessaire. Ce guide fournit des commandes pratiques à copier-coller et des pointeurs de configuration pour les flux de travail bare et Expo sur Android et iOS. Vous apprendrez à lire les bons journaux, valider le comportement réseau, et corriger les problèmes courants de résolution de modules, de builds natifs, d'appels REST, de Google Play Billing, Stripe et RevenueCat. Chaque exemple inclut les résultats attendus, les modes d'échec et les étapes de récupération fiables au quotidien.

TL;DR — 5 commandes qui résolvent 80 % des incidents

  • npx react-native info — capturer l'inventaire de référence
  • npx react-native start --reset-cache — vider le cache Metro
  • cd android && ./gradlew clean assembleDebug --stacktrace — build Android propre
  • cd ios && pod deintegrate && pod install && cd .. — réinitialiser les pods iOS
  • rm -rf node_modules && npm ci — rafraîchissement universel des dépendances

Prérequis et hypothèses

Ce guide couvre React Native 0.72–0.76 sur trois types de flux de travail : bare workflow, Expo managed workflow et Expo development client. Systèmes d'exploitation hôtes : macOS (requis pour iOS), Linux et Windows. Ligne d'outils de base requise : Node 18 ou 20 LTS ; gestionnaire de paquets unique (npm 9+, Yarn 1.x ou pnpm 8+) ; JDK 17 ou 21 aligné avec Android Gradle Plugin (AGP) 8.x ; Android SDK avec platform-tools et build-tools 34+ ; Xcode 15+ avec cible de déploiement iOS 15.1+ ; CocoaPods 1.13+ ; Ruby 3.2+ (via rbenv/rvm/chruby, pas Ruby système) ; Watchman 2024+ ; fastlane récent si utilisé pour CI/CD. Non couverts : React Native <0.70, bases de code architecture classique uniquement sans Hermes, installations globales legacy react-native-cli, ou builds natifs Windows (React Native for Windows hors périmètre).

Architecture et flux des journaux (texte)

[Metro Bundler] --(bundle JS)--> [Hermes/JSC Runtime] --(JSI)--> [Native Bridge]
- +-- Android: logcat (ReactNative, ReactNativeJS, System.err)
- +-- iOS: OSLog / Console Xcode (sous-système: com.apple.reactnative)
- +-- Crashs bytecode Hermes -> /data/data/<pkg>/files/.hermes/*.log
- +-- Journaux Metro (stdout/stderr, événements HMR, graphe de résolution)

Nouvelle architecture (Fabric/TurboModules) :
[Codegen] -> [C++/ObjC/Swift/Kotlin généré] -> [Fabric Renderer / TurboModule Registry]
Chemins des journaux : Metro (sortie Codegen), Gradle (generateCodegenArtifactsFromSchema), Xcode (journaux montage Fabric), logcat (enregistrement TurboModule)

Inventaire de l'environnement (développé)

Exécutez ce qui suit à la racine du projet pour remplir un en-tête d'incident. Copiez le modèle ci-dessous dans votre ticket.

# Modèle d'en-tête d'incident — copier la sortie dans le ticket
echo "=== EN-TÊTE INCIDENT ==="
echo "Date: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "Commit Git: $(git rev-parse HEAD 2>/dev/null || echo 'N/A')"
echo "Branche: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'N/A')"
npx react-native info
echo "--- Expo doctor ---"
npx expo doctor 2>/dev/null || echo "Expo CLI non disponible"
echo "--- Community CLI doctor ---"
npx @react-native-community/cli doctor 2>/dev/null || echo "Community CLI non disponible"
echo "--- Gradle ---"
gradle -v 2>/dev/null || (cd android && ./gradlew -v 2>/dev/null) || echo "Gradle non trouvé"
echo "--- Xcode SDKs ---"
xcodebuild -showsdks 2>/dev/null | head -20
echo "--- Ruby ---"
ruby -v && which ruby
echo "--- Watchman ---"
watchman --version 2>/dev/null || echo "Watchman non installé"
echo "--- Fastlane ---"
fastlane --version 2>/dev/null || echo "Fastlane non installé"
echo "--- Node/PM ---"
node -v && (npm -v || yarn -v || pnpm -v)
echo "=== FIN EN-TÊTE ==="

Éléments clés d'inventaire à enregistrer : version React Native et type de template ; moteur JS (Hermes par défaut, JSC en option) ; versions Node et gestionnaire de paquets avec type de lockfile ; distribution et version JDK, version AGP depuis android/build.gradle ou gradle/libs.versions.toml ; compileSdk et targetSdk Android SDK ; version Xcode, version CocoaPods, gestionnaire Ruby ; cible de déploiement iOS depuis Podfile ; version Watchman ; version fastlane si applicable.

Configuration de base sécurisée (développée)

Adoptez ces valeurs par défaut avant le travail d'incident pour réduire le rayon d'impact.

Gestion des paquets : Utilisez exactement un gestionnaire de paquets. Committez package-lock.json (npm), yarn.lock (Yarn 1.x) ou pnpm-lock.yaml (pnpm). Évitez les versions flottantes (^, ~) dans package.json pendant les incidents ; épinglez les versions exactes.

Résolution Metro (metro.config.js) :

module.exports = {
  resolver: {
    unstable_enablePackageExports: true,
    sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'mjs'],
    // Ajouter résolution personnalisée pour monorepos si nécessaire
  },
};

Configuration React Native (react-native.config.js) :

module.exports = {
  assets: ['./assets/fonts'],
  project: {
    ios: {},
    android: {},
  },
};

Propriétés Gradle (android/gradle.properties) :

org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
org.gradle.caching=true
android.enableJetifier=true
# Hermes par défaut
hermes_enabled=true

Wrapper Gradle (android/gradle/wrapper/gradle-wrapper.properties) :

distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip

Podfile (ios/Podfile) :

platform :ios, '15.1'
use_frameworks! :linkage => :static # ou :dynamic pour pods Swift
$RNFirebaseAsStaticFramework = true # si utilisation Firebase

Secrets et configuration : N'intégrez jamais de secrets (clés secrètes Stripe, jetons API) dans le client. Utilisez react-native-config (bare) ou expo-constants avec extra (Expo) pour les URLs de base et clés publiables selon l'environnement. Gardez les drapeaux debug-only (cleartext, exceptions ATS) hors des builds de release via variantes de build/xcconfigs.

Commandes de réinitialisation de base (matrice plateforme)

Flux de travailAndroidiOSNotes
Barecd android && ./gradlew clean assembleDebug --stacktracecd ios && pod deintegrate && pod install --repo-update && cd ..Exécuter adb reverse tcp:8081 tcp:8081 pour débogage appareil
Expo Managednpx expo prebuild --clean --platform android puis cd android && ./gradlew clean assembleDebugnpx expo prebuild --clean --platform ios puis cd ios && pod install --repo-updatenpx expo start -c vide le cache Metro
Expo Dev Clienteas build --profile development --platform android --localeas build --profile development --platform ios --localJournaux client dev via adb logcat / Console Xcode
Tousnpx react-native start --reset-cachenpx react-native start --reset-cacheRéinitialisation cache Metro universelle
Réinitialisation simulateuradb emu kill + cold bootxcrun simctl erase allOption nucléaire pour état obsolète

Équivalents Windows PowerShell :

Set-Content -Path android\local.properties -Value "sdk.dir=$env:ANDROID_SDK_ROOT"
.\android\gradlew.bat clean assembleDebug --stacktrace
npx expo prebuild --clean --platform android

Sources de journaux et corrélation

CibleSourceCommande / Accès
Metro bundlerTerminal stdout/stderrnpx react-native start --reset-cache
Journaux appareil Androidlogcat (filtré)adb logcat -s ReactNative:V ReactNativeJS:V System.err:V -v threadtime
Build AndroidGradlecd android && ./gradlew assembleDebug --stacktrace --scan
Runtime iOSConsole Xcode / OSLogxcrun simctl spawn booted log stream --predicate 'process == "MyApp"' --style compact
Vidages crash HermesSystème de fichiers appareiladb shell run-as com.myapp cat files/.hermes/*.log | npx metro-symbolicate
Expo managedExpo CLI / Metronpx expo start -c
EAS BuildTableau de bord EAS / CLIeas build:list --platform=android --limit=5 puis eas build:view
expo-updatesJournaux appareiladb logcat -s ExpoUpdates:V / Console Xcode filtre ExpoUpdates
Codegen Nouvelle ArchitectureGradle / Xcode./gradlew generateCodegenArtifactsFromSchema --stacktrace / Journal build Xcode Codegen

Analyse de crash Hermes : Après un crash natif sur Android, récupérez le journal Hermes et symbolisez :

adb shell run-as com.myapp cat files/.hermes/*.log | npx metro-symbolicate > hermes-crash.txt
# Pour profilage, activer profileur Hermes :
adb shell setprop debug.hermes.profiler 1
# Puis ouvrir chrome://tracing et charger le profil généré

Modèles de dépannage (nouveaux)

Dérive Codegen / Configuration TypeScript

Symptôme : error: cannot find module 'NativeMyModule' ou Codegen échoue avec erreurs TypeScript. Cause : react-native-codegen attend une configuration TypeScript stricte ; incompatibilités js/ts dans les fichiers spec. Correctif :

# Vérifier que Codegen peut analyser vos specs
npx react-native-codegen --help
# En bare workflow, régénérer
cd android && ./gradlew generateCodegenArtifactsFromSchema --stacktrace
cd ../ios && pod install --repo-update

Attendu : Fichiers C++/Swift/Kotlin générés sous build/generated/codegen (Android) et Pods/Headers/Private/React-Core/ReactCommon (iOS). Échec : TypeScript strict: false ou skipLibCheck manquant dans tsconfig.json. Récupération : Aligner tsconfig.json sur les défauts du template RN ; assurer que la version react-native-codegen correspond à la version RN.

TurboModule « Native module cannot be null »

Symptôme : Erreur JS Native module cannot be null pour un TurboModule personnalisé. Cause : Module non enregistré dans ReactNativeHost (Android) ou RCTBridge (iOS), ou Package non ajouté. Correctif : Vérifier que MainApplication.java / MainApplication.kt inclut new MyTurboModulePackage() dans getPackages(). Sur iOS, s'assurer que RCTAppSetupDefaultRootView inclut le module ou que l'autolinking l'a détecté (pod install --repo-update). Vérification : adb logcat -s ReactNative:V montre le succès de TurboModuleRegistry.getEnforcing.

Fabric « ShadowNode not found »

Symptôme : Crash dans FabricUIManager avec ShadowNode not found for tag. Cause : Incompatibilité de version entre react-native et react-native-reanimated / react-native-gesture-handler composants Fabric. Correctif : Épingler react-native-reanimated à la version compatible avec RN (ex. RN 0.74 → Reanimated 3.10.x). Assurer newArchEnabled=true dans gradle.properties et Podfile use_frameworks! :linkage => :static cohérent. Récupération : Désactiver temporairement Fabric pour le composant : UIManager.setViewManagerConfigurationDescription('MyView', null) en JS.

Erreurs Worklet Reanimated

Symptôme : WorkletError: "worklet" is not defined ou ReanimatedError: [Reanimated] Mismatch. Cause : Ordre d'import (react-native-gesture-handler doit être premier), babel-plugin-reanimated manquant, ou incompatibilité Hermes/JSC. Correctif :

// index.js ou App.js — tout premier import
import 'react-native-gesture-handler';

Vérifier babel.config.js :

plugins: [
  ['react-native-reanimated/plugin', { /* options */ }],
],

Attendu : Aucune erreur worklet ; animations s'exécutent sur thread UI. Échec : Oublier de vider le cache Metro après modification config babel.

Réseau et SSL en profondeur

Débogage appareil avec adb reverse

# Metro bundler
adb reverse tcp:8081 tcp:8081
# Serveur API local
adb reverse tcp:3000 tcp:3000
# Vérifier
adb reverse --list

Contournement SSL Pinning Charles / Proxyman

  • Installer CA sur appareil/émulateur : adb push charles-ssl-proxying-certificate.pem /sdcard/Download/ puis Paramètres → Sécurité → Installer depuis carte SD.
  • Ou utiliser network_security_config.xml (debug uniquement) :
<!-- android/app/src/debug/res/xml/network_security_config.xml -->
<network-security-config>
  <base-config cleartextTrafficPermitted="true">
    <trust-anchors>
      <certificates src="system" />
      <certificates src="user" />
    </trust-anchors>
  </base-config>
  <debug-overrides>
    <trust-anchors>
      <certificates src="system" />
      <certificates src="user" />
    </trust-anchors>
  </debug-overrides>
</network-security-config>
  • Référencer dans AndroidManifest.xml (variante debug uniquement via android:networkSecurityConfig="@xml/network_security_config").

Exceptions ATS iOS (Debug uniquement)

Utiliser xcconfig par configuration :

// Debug.xcconfig
NSAppTransportSecurity = {
  NSExceptionDomains = {
    "localhost" = {
      NSExceptionAllowsInsecureHTTPLoads = YES;
      NSIncludesSubdomains = YES;
    };
  };
};

Release.xcconfig : Aucune exception ; imposer HTTPS.

Contournement Certificate Pinning (Tests uniquement)

Bibliothèques : react-native-ssl-pinning (Android), TrustKit (iOS). Ne jamais livrer de contournement pinning en production. Utiliser uniquement pour QA contre staging avec certificats connus.

Délais par défaut Fetch vs Axios vs Ky

Recommandation : Envelopper tous les appels réseau avec un délai de 10–15s et logique de réessai (backoff exponentiel, max 3 réessais).

  • fetch : Aucun délai par défaut ; implémenter AbortController avec setTimeout.
  • axios : Défaut 0 (pas de délai) ; définir timeout: 10000 dans config instance.
  • ky : Défaut 10s ; configurable via option timeout.

Facturation et paiements (développé)

Google Play Billing (react-native-iap / react-native-purchases)

ITEM_UNAVAILABLE / SKU non trouvé :

  • Vérifier correspondance exacte ID produit dans Play Console (sensible à la casse).
  • Produit doit être Actif, pas « Inactif » ou « Brouillon ».
  • Compte testeur doit être dans la liste Testeurs de licence (pas seulement piste de test interne).
  • Utiliser la piste de test interne pour propagation la plus rapide (minutes vs heures).

BillingClient pas prêt :

import { initConnection, getProducts, purchaseProduct } from 'react-native-iap';

await initConnection();
// Attendre ready
const products = await getProducts({ skus: ['premium_monthly'] });

Vérification : adb logcat -s BillingClient:V IabHelper:V montre onBillingSetupFinished avec OK.

RevenueCat / react-native-purchases

Erreurs courantes :

  • Purchases.configure appelé plusieurs fois ou avant AppRegistry.
  • Incohérence calcul droit : customerInfo.entitlements.active['pro'] vs all['pro'].
  • logIn / logOut non équilibrés ; IDs anonymes fuient entre utilisateurs.
  • restorePurchases échoue sur simulateur (nécessite appareil).

Modèle de configuration :

import Purchases from 'react-native-purchases';

Purchases.configure({
  apiKey: Platform.select({ ios: 'appl_...', android: 'goog_...' }),
  useAmazon: false,
  observerMode: false, // true seulement si vous gérez les achats vous-même
});

// Vérification droit
const customerInfo = await Purchases.getCustomerInfo();
const isPro = customerInfo.entitlements.active.pro !== undefined;

Vérification côté serveur : Appeler l'API REST RevenueCat /v1/subscribers/{app_user_id} depuis votre backend pour valider les droits avant d'accorder l'accès.

Apple StoreKit 2 / App Store Connect

  • Tester avec fichier de configuration StoreKit (.storekit) dans Xcode pour test local sans réseau.
  • Transaction.currentEntitlements (iOS 15+) pour vérification sur appareil.
  • Vérification reçu côté serveur : POST https://api.revenuecat.com/v1/subscribers/{id} ou endpoint Apple /verifyReceipt (déprécié, utiliser App Store Server API).

Performance et profilage

OutilObjectifCommande / Configuration
react-native-performance (Sentry)Vitals, frames lentes, TTInpm i @sentry/react-native + Sentry.init({ dsn, enablePerformance: true })
why-did-you-renderRe-rendus inutilesnpm i @welldone-software/why-did-you-render + patcher React dans App.js
hermes-profile / chrome://tracingProfilage CPUadb shell setprop debug.hermes.profiler 1 → charger trace dans Chrome
metro-bundle-analyzerTaille bundlenpx metro-bundle-analyzer → ouvrir rapport HTML
react-native-reanimated profileurTemps exécution workletReanimated.setProfilingEnabled(true) en dev

Profilage rapide : adb shell setprop debug.hermes.profiler 1, reproduire scénario, adb shell setprop debug.hermes.profiler 0, récupérer trace : adb shell run-as com.myapp cat files/.hermes/*.trace | npx metro-symbolicate > profile.json, ouvrir chrome://tracing → Charger.

CI/CD et signaux d'automatisation

Téléversement artefacts GitHub Actions

- name: Upload Gradle scan
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: gradle-scan-${{ github.run_id }}
    path: android/build/reports/scan/

- name: Upload Xcode result bundle
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: xcode-result-${{ github.run_id }}
    path: build.xcresult

Lien Gradle Scan

./gradlew assembleRelease --no-daemon --scan -PreactNativeArchitectures=arm64-v8a
# Sortie : "Publishing build scan... https://gradle.com/s/xxxx"

Bundle de résultats Xcode

xcodebuild -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -configuration Release \
  -destination generic/platform=iOS \
  -resultBundlePath build.xcresult \
  -quiet
# Analyser avec xcparse ou xcresulttool

Journaux EAS Build

eas build:list --platform=android --limit=5
eas build:view <build-id> --logs

Sortie Fastlane Scan/Gym

# Fastfile
lane :test do
  scan(
    workspace: "MyApp.xcworkspace",
    scheme: "MyApp",
    result_bundle: true,
    output_directory: "fastlane/test_output"
  )
end

Annulation et récupération (développé)

Annulation Expo Updates

# Lister mises à jour récentes
npx expo-updates:list
# Annuler vers précédente
npx expo-updates:rollback
# Ou publier nouvelle mise à jour avec bundle précédent
eas update --branch production --message "Rollback vers v1.2.3"

Reconstruction EAS Build depuis cache

eas build --profile production --platform android --clear-cache
# Ou reconstruire commit spécifique
eas build --profile production --platform android --commit <sha>

Automatisation Git Bisect

# Bisect automatisé pour régression
git bisect start HEAD <bon-tag>
git bisect run npm ci && npm test
git bisect reset

Isolation reconstruction module natif

# Réinstaller deps JS sans scripts de rebuild natif
npm ci --ignore-scripts
# Puis reconstruire natif uniquement
cd android && ./gradlew clean assembleDebug
cd ../ios && pod install --repo-update

Scénario technique réaliste

Scénario : Build release Android crashe au démarrage avec java.lang.UnsatisfiedLinkError: libhermes.so après mise à niveau RN 0.73→0.74 et ajout de react-native-reanimated 3.x.

1. Capture d'inventaire

npx react-native info
# Sortie montre : RN 0.74.2, Hermes activé, AGP 8.2.2, JDK 21, Reanimated 3.10.0

2. Corrélation des journaux

# logcat pour crash natif
adb logcat -s ReactNative:V System.err:V -v threadtime > crash.log
# Vidage crash Hermes
adb shell run-as com.myapp cat files/.hermes/*.log | npx metro-symbolicate > hermes-crash.txt

Lignes logcat clés :

E System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "libhermes.so" not found
E System.err: at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:...)
E ReactNativeJS: Fatal: TurboModuleRegistry.getEnforcing(...): 'NativeReanimated' non trouvé

3. Portée réduite

  • Désactiver Reanimated : Commenter import 'react-native-reanimated'; et utilisation Reanimated.
  • Rebuild : cd android && ./gradlew clean assembleRelease --stacktrace.
  • Résultat : App se lance → Reanimated est le déclencheur.

4. Cause racine et correctif

Cause : RN 0.74 requiert react-native-reanimated 3.10+ avec Fabric activé. libhermes.so manquant car hermes_enabled=true mais newArchEnabled=false dans gradle.properties — liaisons JSI Hermes pour TurboModules non générées. Config soLoader dans android/app/build.gradle manquante jniLibs pour Hermes.

Correctif (android/gradle.properties) :

hermes_enabled=true
newArchEnabled=true # Requis pour TurboModules/Fabric

Correctif (android/app/build.gradle) :

dependencies {
  // Assurer empaquetage libs JSI Hermes
  implementation "com.facebook.react:hermes-engine:+"
}

Correctif (ios/Podfile) :

use_frameworks! :linkage => :static
# Assurer pods Reanimated utilisent Fabric
pod 'React-RCTFabric', :path => '../node_modules/react-native/React/Fabric'

Exécuter :

cd android && ./gradlew clean assembleRelease --no-daemon --scan -PreactNativeArchitectures=arm64-v8a
cd ../ios && pod install --repo-update

5. Vérifier

  • APK release s'installe et se lance sur appareil.
  • adb logcat -s ReactNative:V montre succès TurboModuleRegistry.getEnforcing: NativeReanimated.
  • Animations Reanimated s'exécutent sur thread UI (pas de chutes thread JS).

6. Plan d'annulation

# Annuler gradle.properties
git checkout HEAD -- android/gradle.properties
# Annuler version Reanimated
npm install [email protected] # dernière version compatible RN 0.73
# Rebuild
cd android && ./gradlew clean assembleRelease

Décision : Si délai critique, annuler RN vers 0.73.3 et Reanimated vers 3.6.2 ; planifier migration RN 0.74 avec QA dédiée.

Conclusion

Le dépannage React Native est le plus efficace lorsque vous stabilisez l'environnement, rassemblez des journaux à fort signal et appliquez le plus petit changement sûr. Avec un inventaire clair, des paramètres de debug et release prévisibles, et une routine disciplinée de vérification et d'annulation, la plupart des problèmes deviennent simples à isoler et corriger. Utilisez les commandes d'inventaire pour établir une base de référence, les commandes de journaux pour observer le comportement réel sur Metro, logcat, OSLog et vidages crash Hermes, et les correctifs pilotés par exemples ici pour résoudre les problèmes courants de résolution Metro, builds Android et iOS, mise en réseau REST, Google Play Billing, Stripe et intégrations RevenueCat. Gardez les changements petits, vérifiez localement sur les deux plateformes, et annulez rapidement si nécessaire. Avec le temps, cette approche raccourcit la durée des incidents et rend les résultats fiables dans votre équipe.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO