Bridge — este o componentă arhitecturală React Native care asigură comunicarea asincronă între firul JavaScript și mediul nativ iOS și Android. Acesta transmite mesaje JSON serializate printr-o coadă, permițând apelarea API-urilor native din codul JS. Potrivit Meta, 2024, Bridge rămâne baza aplicațiilor existente, deși este inferior ca performanță noii arhitecturi bazate pe JSI.
Principalele puncte
Bridge (Pod) — este un element arhitectural cheie al React Native care asigură comunicarea bidirecțională asincronă între firul JavaScript, unde se execută logica de afaceri a aplicației, și firele native iOS și Android. De la lansarea React Native în 2015, Bridge a rămas singura modalitate de interacțiune a codului JS cu API-urile platformei — cameră, geolocație, sistem de fișiere, notificări și alte capabilități native.
Arhitectura Bridge se bazează pe principiul cozii de mesaje (message queue). Când codul JavaScript apelează o metodă nativă, cererea este serializată într-un șir JSON, plasată într-o coadă și trimisă asincron către partea nativă. Codul nativ procesează cererea, execută operația corespunzătoare și trimite rezultatul înapoi prin aceeași coadă către firul JS. Potrivit raportului Meta la React Conf 2021, prin Bridge trec până la 10.000 de mesaje pe secundă într-o aplicație obișnuită.
Principalele fire implicate în funcționarea Bridge: JavaScript Thread (executarea codului JS), Native Thread (executarea operațiilor native) și Shadow Thread (calcularea layout-ului cu ajutorul Yoga). Fiecare fir funcționează independent, ceea ce asigură receptivitatea interfeței — animațiile native nu sunt blocate de calculele JS.
Bridge utilizează trei mecanisme cheie pentru comunicare: MessageQueue, serializarea JSON și gruparea mesajelor. MessageQueue este o componentă internă React Native care gestionează coada de apeluri între JS și partea nativă. Fiecare apel al unei metode native este plasat în coadă, serializat și trimis în loturi pentru optimizarea performanței.
MessageQueue funcționează pe principiul grupării: apelurile metodelor native se acumulează și sunt trimise ca un singur grup (batch) la fiecare 5–15 milisecunde. Aceasta reduce overhead-ul de serializare, deoarece mai multe apeluri sunt împachetate într-un singur pachet JSON. Pe partea nativă, mesajele sunt deserializate și distribuite modulelor corespunzătoare.
Modulele native sunt înregistrate automat prin macro-uri sau adnotări. Pe iOS se utilizează macro-ul RCT_EXPORT_MODULE, pe Android — adnotarea @ReactMethod. React Native scanează modulele înregistrate la pornirea aplicației și construiește o hartă JSON de configurare a tuturor metodelor disponibile. Această hartă este transmisă în mediul JS, iar JavaScript află ce metode pot fi apelate.
Datele parcurg următorul drum: JavaScript apelează NativeModules.CalendarModule.createCalendarEvent(). Metoda este serializată într-un mesaj JSON cu identificatorul modulului, numele metodei și argumentele. Mesajul ajunge în coada MessageQueue. Pe firul nativ, mesajul este deserializat și transmis modulului corespunzător. Rezultatul execuției este serializat înapoi și trimis în firul JS ca Promise sau callback.
// Apelul modulului nativ din JavaScript prin Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Eveniment creat cu id:', eventId);
})
.catch(error => {
console.error('Eșuat:', error);
});
Pe partea nativă iOS, modulul arată ca o clasă Objective-C cu macro-ul RCT_EXPORT_MODULE. Metoda este exportată cu macro-ul RCT_EXPORT_METHOD, iar React Native o înregistrează automat în Bridge. Argumentele sunt transmise după poziție și trebuie să corespundă tipurilor JSON suportate: NSString, NSNumber, NSArray, NSDictionary, BOOL.
// Înregistrarea modulului nativ iOS în 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 are o serie de limitări fundamentale de performanță. Principala dintre ele este asincronitatea obligatorie și serializarea. Fiecare apel al unei metode native transformă datele într-un șir JSON, ceea ce adaugă întârziere și consumă memorie. Pentru operații cu volume mari de date, cum ar fi procesarea imaginilor sau lucrul cu video, aceasta devine un blocaj.
Serializarea și deserializarea JSON ocupă timp de procesor și memorie. Fiecare mesaj trebuie transformat într-un șir pe partea JS, transmis prin pod și analizat pe partea nativă. Potrivit testelor Callstack (2022), serializarea unui array de 10.000 de numere prin Bridge durează aproximativ 30–50 de milisecunde, ceea ce este inacceptabil pentru apeluri de înaltă frecvență.
Bridge nu este optimizat pentru transmiterea datelor binare mari. Fotografiile, fișierele audio și fluxurile video necesită abordări alternative — de exemplu, scrierea fișierului pe disc și transmiterea căii sub formă de șir. Aceasta creează un overhead suplimentar pentru citirea și scrierea sistemului de fișiere.
Conștientizarea acestor limitări a condus echipa Meta la dezvoltarea noii arhitecturi React Native, în care Bridge este înlocuit cu JSI (JavaScript Interface) și Turbo Module. JSI permite apelarea directă a metodelor native fără serializare, eliminând principalul dezavantaj al Bridge.
Comparația dintre Bridge și Turbo Module arată diferențe fundamentale în abordările arhitecturale. Bridge utilizează o coadă de mesaje asincronă cu serializare JSON, în timp ce Turbo Module funcționează prin JSI — o interfață directă între JavaScript și C++ care permite apelarea sincronă a metodelor native fără transformarea datelor.
| Caracteristică | Bridge | Turbo Module |
|---|---|---|
| Tipul apelului | Asincron | Sincron și asincron |
| Serializare | JSON la fiecare apel | Obiecte JSI fără copiere |
| Performanță | Medie | Ridicată |
| Tipizare | Dinamică | Statică (Codegen) |
| Încărcare | Toate modulele la pornire | Leneșă (la cerere) |
Alegerea între Bridge și Turbo Module depinde de versiunea React Native. Pentru proiectele pe React Native 0.72 și mai vechi, Bridge rămâne mecanismul principal. Începând cu React Native 0.73, Metro și noua arhitectură sunt suportate în paralel, permițând migrarea treptată. Trecerea completă la Turbo Module necesită actualizarea la React Native 0.76+ și activarea noii arhitecturi în configurație.
Să analizăm ciclul complet de creare și utilizare a unui Native Module prin Bridge pe exemplul unui modul pentru lucrul cu calendarul. Modulul va crea un eveniment și va returna identificatorul acestuia. Acest exemplu acoperă configurarea pentru ambele platforme — iOS și Android.
Pe Android, Native Module este creat ca o clasă Java care moștenește ReactContextBaseJavaModule. Adnotarea @ReactMethod exportă metoda în Bridge. Pentru Promise se utilizează interfața Promise din com.facebook.react.bridge.
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());
}
}
}
Modulul este înregistrat prin @ReactModule sau manual în pachetul aplicației. React Native îl detectează automat și îl adaugă în Bridge. După înregistrare, modulul este accesibil din JavaScript prin 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();
}
}
Este important de menționat că Bridge necesită repornirea aplicației la adăugarea de noi module, deoarece harta de configurare se construiește o singură dată la inițializare. Aceasta îl diferențiază de Turbo Module, care se încarcă leneș și suportă reîncărcarea la cald a modulelor fără repornire.
Întrebări frecvente
Bridge utilizează întotdeauna o coadă asincronă și serializare JSON, în timp ce transmiterea directă prin JSI funcționează sincron și fără copierea datelor. Bridge creează o întârziere pentru serializare, dar asigură izolarea firelor.
Nu, Bridge suportă doar apeluri asincrone. Pentru interacțiunea sincronă este necesară noua arhitectură cu JSI și Turbo Module. Aceasta este una dintre limitările cheie care a fost rezolvată în React Native 0.76+.
Bridge suportă tipuri serializabile în JSON: șiruri de caractere, numere, valori booleene, array-uri, dicționare (obiecte). Datele binare, cum ar fi imaginile, trebuie transmise prin sistemul de fișiere sau codificare base64.
Pentru măsurare, utilizați React DevTools și profiler-ul React Native. Fila Performance arată numărul de mesaje din coada Bridge și întârzierile. De asemenea, este disponibil pachetul react-native-bridge-spy pentru monitorizarea traficului.
Se recomandă trecerea pentru proiecte care necesită performanță ridicată sau la crearea de noi aplicații pe React Native 0.76+. Pentru proiectele existente, migrarea poate fi treptată — ambele arhitecturi funcționează în paralel.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și