Bridge est un composant architectural de React Native qui assure une communication asynchrone entre le thread JavaScript et l’environnement natif d’iOS et Android. Il transmet des messages JSON sérialisés via une file d’attente, permettant d’appeler des API natives à partir du code JS. Selon Meta, 2024, Bridge reste la base des applications existantes, bien qu’il perde en performance face à la nouvelle architecture basée sur JSI.
Points clés
Bridge est un élément architectural clé de React Native qui fournit une communication asynchrone bidirectionnelle entre le thread JavaScript, où la logique métier de l’application est exécutée, et les threads natifs iOS et Android. Depuis la sortie de React Native en 2015, Bridge a été le seul moyen pour le code JS d’interagir avec les API de la plateforme — caméra, géolocalisation, système de fichiers, notifications et autres capacités natives.
L’architecture Bridge est basée sur le principe de la file de messages (message queue). Lorsque le code JavaScript appelle une méthode native, la requête est sérialisée en une chaîne JSON, placée dans une file d’attente et envoyée de manière asynchrone côté natif. Le code natif traite la requête, exécute l’opération correspondante et renvoie le résultat via la même file d’attente au thread JS. Selon le rapport de Meta à la React Conf 2021, jusqu’à 10 000 messages par seconde traversent Bridge dans une application moyenne.
Les principaux threads impliqués dans le fonctionnement de Bridge : JavaScript Thread (exécution du code JS), Native Thread (exécution des opérations natives) et Shadow Thread (calcul de la mise en page avec Yoga). Chaque thread fonctionne indépendamment, garantissant la réactivité de l’UI — les animations natives ne sont pas bloquées par les calculs JS.
Bridge utilise trois mécanismes clés pour la communication : MessageQueue, la sérialisation JSON et le regroupement de messages (batching). MessageQueue est un composant interne de React Native qui gère la file d’attente des appels entre JS et le côté natif. Chaque appel de méthode native est placé dans une file d’attente, sérialisé et envoyé par lots pour optimiser les performances.
MessageQueue fonctionne sur le principe du lotissement : les appels de méthodes natives s’accumulent et sont envoyés en un seul groupe (lot) toutes les 5 à 15 millisecondes. Cela réduit la surcharge de sérialisation, car plusieurs appels sont emballés dans un seul paquet JSON. Côté natif, les messages sont désérialisés et distribués aux modules correspondants.
Les modules natifs sont enregistrés automatiquement via des macros ou des annotations. iOS utilise la macro RCT_EXPORT_MODULE, Android utilise l’annotation @ReactMethod. React Native analyse les modules enregistrés au démarrage de l’application et construit une carte JSON de configuration de toutes les méthodes disponibles. Cette carte est transmise à l’environnement JS, et JavaScript apprend quelles méthodes peuvent être appelées.
Les données suivent ce chemin : JavaScript appelle NativeModules.CalendarModule.createCalendarEvent(). La méthode est sérialisée en un message JSON avec l’identifiant du module, le nom de la méthode et les arguments. Le message entre dans MessageQueue. Sur le thread natif, le message est désérialisé et transmis au module correspondant. Le résultat de l’exécution est sérialisé en retour et envoyé au thread JS sous forme de Promise ou de callback.
// Native module call from JavaScript via Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Created event with id:', eventId);
})
.catch(error => {
console.error('Failed:', error);
});
Côté natif iOS, le module se présente comme une classe Objective-C avec la macro RCT_EXPORT_MODULE. La méthode est exportée avec la macro RCT_EXPORT_METHOD, et React Native l’enregistre automatiquement dans Bridge. Les arguments sont passés par position et doivent correspondre aux types JSON pris en charge : NSString, NSNumber, NSArray, NSDictionary, BOOL.
// iOS Native Module registration in Bridge
@interface CalendarModule () RCT_EXPORT_MODULE()
@end
@implementation CalendarModule
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name
location:(NSString *)location
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSNumber *eventId = createEvent(name, location);
resolve(eventId);
}
@end
Bridge présente un certain nombre de limitations fondamentales de performance. La principale est l’asynchronisme et la sérialisation obligatoires. Chaque appel de méthode native convertit les données en une chaîne JSON, ce qui ajoute de la latence et consomme de la mémoire. Pour les opérations avec de grands volumes de données, comme le traitement d’images ou le travail avec la vidéo, cela devient un goulot d’étranglement.
La sérialisation et la désérialisation JSON consomment du temps CPU et de la mémoire. Chaque message doit être converti en une chaîne côté JS, transmis via le pont et analysé côté natif. Selon les tests de Callstack (2022), la sérialisation d’un tableau de 10 000 nombres via Bridge prend environ 30 à 50 millisecondes, ce qui est inacceptable pour les appels haute fréquence.
Bridge n’est pas optimisé pour le transfert de grandes données binaires. Les photos, les fichiers audio et les flux vidéo nécessitent des approches alternatives — par exemple, écrire un fichier sur le disque et passer le chemin sous forme de chaîne. Cela crée une surcharge supplémentaire sur les opérations de lecture et d’écriture du système de fichiers.
La prise de conscience de ces limitations a conduit l’équipe de Meta à développer une nouvelle architecture React Native, dans laquelle Bridge est remplacé par JSI (JavaScript Interface) et Turbo Module. JSI permet d’appeler les méthodes natives directement, sans sérialisation, éliminant ainsi le principal inconvénient de Bridge.
La comparaison de Bridge et Turbo Module montre des différences fondamentales dans les approches architecturales. Bridge utilise une file de messages asynchrone avec sérialisation JSON, tandis que Turbo Module fonctionne via JSI — une interface directe entre JavaScript et C++ qui permet d’appeler les méthodes natives de manière synchrone sans conversion de données.
| Caractéristique | Bridge | Turbo Module |
|---|---|---|
| Type d’appel | Asynchrone | Synchrone et asynchrone |
| Sérialisation | JSON à chaque appel | Objets JSI sans copie |
| Performance | Moyenne | Élevée |
| Typage | Dynamique | Statique (Codegen) |
| Chargement | Tous les modules au démarrage | Paresseux (à la demande) |
Le choix entre Bridge et Turbo Module dépend de la version de React Native. Pour les projets sur React Native 0.72 et antérieur, Bridge reste le mécanisme principal. À partir de React Native 0.73, Metro et la nouvelle architecture sont pris en charge en parallèle, permettant une migration progressive. Une transition complète vers Turbo Module nécessite une mise à jour vers React Native 0.76+ et l’activation de la nouvelle architecture dans la configuration.
Parcourons le cycle complet de création et d’utilisation d’un Native Module via Bridge en prenant l’exemple d’un module de calendrier. Le module créera un événement et retournera son identifiant. Cet exemple couvre la configuration pour les deux plateformes — iOS et Android.
Sur Android, un Native Module est créé comme une classe Java qui étend ReactContextBaseJavaModule. L’annotation @ReactMethod exporte la méthode vers Bridge. Pour Promise, l’interface Promise de com.facebook.react.bridge est utilisée.
public class CalendarModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "CalendarModule";
}
@ReactMethod
public void createCalendarEvent(
String name,
String location,
Promise promise) {
try {
Integer eventId = createCalendarEventNative(name, location);
promise.resolve(eventId);
} catch (Exception e) {
promise.reject("EVENT_ERROR", e.getMessage());
}
}
}
Le module est enregistré via @ReactModule ou manuellement dans le package de l’application. React Native le détecte automatiquement et l’ajoute à Bridge. Après l’enregistrement, le module est accessible depuis JavaScript via NativeModules.
public class CalendarPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return Arrays.asList(
new CalendarModule(reactContext)
);
}
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Il est important de noter que Bridge nécessite un redémarrage de l’application lors de l’ajout de nouveaux modules, car la carte de configuration est construite une seule fois lors de l’initialisation. Cela le distingue de Turbo Module, qui se charge paresseusement et prend en charge le rechargement à chaud des modules sans redémarrage.
Foire aux questions
Bridge utilise toujours une file d’attente asynchrone et une sérialisation JSON, tandis que le transfert direct via JSI fonctionne de manière synchrone et sans copie de données. Bridge crée une latence de sérialisation mais garantit l’isolation des threads.
Non, Bridge ne prend en charge que les appels asynchrones. L’interaction synchrone nécessite la nouvelle architecture avec JSI et Turbo Module. C’est l’une des principales limitations qui a été résolue dans React Native 0.76+.
Bridge prend en charge les types sérialisables en JSON : chaînes, nombres, valeurs booléennes, tableaux, dictionnaires (objets). Les données binaires comme les images doivent être transférées via le système de fichiers ou l’encodage base64.
Pour la mesure, utilisez React DevTools et le profileur React Native. L’onglet Performance montre le nombre de messages dans la file d’attente de Bridge et les latences. Le package react-native-bridge-spy est également disponible pour la surveillance du trafic.
Il est recommandé de passer pour les projets exigeants en performance ou lors de la création de nouvelles applications sur React Native 0.76+. Pour les projets existants, la migration peut être progressive — les deux architectures fonctionnent en parallèle.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi