Native Module în React Native — ce este, cum se creează și se integrează

Autor: IT Sectr Publicat: 2026-06-03 Timp de citire: 9 min

Native Module este o clasă Java sau Objective-C care face API-urile native ale platformei accesibile din JavaScript în React Native. Fiecare modul se înregistrează în Bridge și exportă metode care pot fi apelate din codul JS ca funcții obișnuite. Potrivit Meta, 2024, Native Module rămâne principala modalitate de integrare a codului platformei în aplicațiile React Native.

Principalele puncte

  • Native Module — puntea între JavaScript și codul nativ iOS sau Android.
  • Înregistrare — modulul se declară prin adnotări iOS (RCT_EXPORT_MODULE) sau Android (@ReactMethod).
  • Tipuri de date — sunt suportate primitive, șiruri, tablouri, dicționare și Promise.
  • Utilizare — din JS modulul este accesibil prin NativeModules.NumeModul.
  • Arhitectură nouă — în React Native 0.76+ Native Module poate funcționa ca Turbo Module prin JSI.

Ce este Native Module?

Native Module este un element arhitectural React Native care permite executarea codului în limbajul platformei (Objective-C/Swift pentru iOS, Java/Kotlin pentru Android) și returnarea rezultatului în JavaScript. Fără Native Module este imposibil accesul la capacitățile native ale dispozitivului — cameră, GPS, accelerometru, sistem de fișiere sau Bluetooth.

React Native vine cu un set de module Native Module încorporate: CameraRoll, AsyncStorage, Geolocation, NetInfo și altele. Însă pentru sarcini specifice — integrarea unui SDK terț, lucrul cu senzori hardware sau procese de fundal — dezvoltatorul își creează propriile module. Conform sondajului State of React Native 2024, 67% dintre dezvoltatori folosesc cel puțin un Native Module personalizat în proiectele lor.

Arhitectura Native Module depinde de versiunea React Native. În arhitectura clasică (React Native 0.72 și mai vechi) modulul se conectează prin Bridge și comunică cu JS asincron prin serializare JSON. În arhitectura nouă (React Native 0.76+) modulul poate funcționa ca Turbo Module, folosind JSI pentru acces sincron fără serializare.

Crearea Native Module pentru iOS

Crearea Native Module pentru iOS începe cu declararea unei clase Objective-C care implementează protocolul RCTBridgeModule. Macro-ul RCT_EXPORT_MODULE înregistrează modulul în Bridge, iar RCT_EXPORT_METHOD exportă o metodă accesibilă din JavaScript.

objective-c
// ImageCompressor.m — Native Module pentru iOS
@interface ImageCompressor () RCT_EXPORT_MODULE()
@end

@implementation ImageCompressor

RCT_EXPORT_METHOD(compressImage:(NSString *)imagePath
                  quality:(NSNumber *)quality
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    NSData *compressedData = [UIImageJPEGRepresentation(image, quality.floatValue)];
    NSString *outputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"compressed.jpg"];
    [compressedData writeToFile:outputPath atomically:YES];
    resolve(outputPath);
}

@end

Metoda compressImage primește calea către imagine și calitatea compresiei (0.0–1.0), procesează datele pe partea nativă și returnează calea către fișierul comprimat. Avantajul cheie — compresia se execută cu cod nativ, ceea ce este semnificativ mai rapid și mai eficient din punct de vedere al memoriei decât o operație similară în JavaScript.

Pentru modulele Swift se folosește adnotarea @objc înaintea clasei și metodelor pentru a fi accesibile runtime-ului Objective-C cu care lucrează Bridge. Clasa trebuie să moștenească NSObject și să implementeze RCTBridgeModule.

swift
// ImageCompressor.swift — Native Module Swift
@objc(ImageCompressor)
class ImageCompressor: NSObject {

    @objc
    func compressImage(
        _ imagePath: String,
        quality: Float,
        resolver: @escaping RCTPromiseResolveBlock,
        rejecter: @escaping RCTPromiseRejectBlock
    ) {
        guard let image = UIImage(contentsOfFile: imagePath) else {
            rejecter("FILE_ERROR", "Cannot load image", nil)
            return
        }
        guard let data = image.jpegData(compressionQuality: CGFloat(quality)) else {
            rejecter("COMPRESS_ERROR", "Compression failed", nil)
            return
        }
        let outputPath = NSTemporaryDirectory() + "compressed.jpg"
        try? data.write(to: URL(fileURLWithPath: outputPath))
        resolver(outputPath)
    }
}

Crearea Native Module pentru Android

Pe Android Native Module se creează ca o clasă Java care moștenește ReactContextBaseJavaModule. Adnotarea @ReactMethod exportă metoda în Bridge. Pentru returnarea rezultatului se folosește interfața Promise din com.facebook.react.bridge.

java
// ImageCompressorModule.java — Native Module Android
public class ImageCompressorModule
    extends ReactContextBaseJavaModule {

    @Override
    public String getName() {
        return "ImageCompressor";
    }

    @ReactMethod
    public void compressImage(
            String imagePath,
            Float quality,
            Promise promise) {
        try {
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            File outputFile = new File(
                ReactNative.getApplicationContext()
                    .getCacheDir(), "compressed.jpg");
            FileOutputStream fos = new FileOutputStream(outputFile);
            bitmap.compress(
                Bitmap.CompressFormat.JPEG,
                (int)(quality * 100), fos);
            fos.close();
            promise.resolve(outputFile.getAbsolutePath());
        } catch (Exception e) {
            promise.reject("COMPRESS_ERROR", e.getMessage());
        }
    }
}

Metoda getName() returnează numele modulului sub care va fi accesibil din JavaScript. În exemplul dat modulul se înregistrează ca ImageCompressor. Adnotarea @ReactMethod indică Bridge-ului că metoda trebuie exportată. Important: metodele trebuie să fie void și să accepte doar tipuri suportate de Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.

După crearea clasei, modulul trebuie înregistrat în pachetul aplicației. Pentru aceasta se creează o clasă care implementează ReactPackage și se adaugă la lista de module în metoda createNativeModules.

java
// ImageCompressorPackage.java — înregistrare modul
public class ImageCompressorPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        return Arrays.asList(
            new ImageCompressorModule(reactContext)
        );
    }

    @Override
    public List<ViewManager> createViewManagers(
            ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

Înregistrarea și utilizarea Native Module

După crearea modulelor pentru ambele platforme, acestea trebuie înregistrate în React Native. Pentru Android pachetul se adaugă în MainApplication.java în metoda getPackages(). Pentru iOS modulul se înregistrează automat prin macro-ul RCT_EXPORT_MODULE, dar se poate folosi și înregistrarea manuală în fișierul AppDelegate.mm.

java
// MainApplication.java — adăugarea pachetului la React Native
import com.yourapp.nativemodules.ImageCompressorPackage;

public class MainApplication extends Application
    implements ReactApplication {

    private final ReactNativeHost mReactNativeHost =
        new ReactNativeHost(this) {

        @Override
        protected List<ReactPackage> getPackages() {
            List<ReactPackage> packages =
                new PackageList(this).getPackages();
            packages.add(new ImageCompressorPackage());
            return packages;
        }
    };
}

După înregistrare, modulul devine accesibil în JavaScript prin NativeModules. React Native înlocuiește automat numele modulului specificat în getName() pentru Android sau în RCT_EXPORT_MODULE pentru iOS.

js
// Utilizarea Native Module din JavaScript
import { NativeModules } from 'react-native';
import { Platform } from 'react-native';

const ImageCompressor = NativeModules.ImageCompressor;

async function compressPhoto(uri: string) {
  try {
    const result = await ImageCompressor.compressImage(
      uri.replace('file://', ''), 0.8
    );
    console.log('Comprimat:', result);
    return result;
  } catch (error) {
    console.error('Comprimare eșuată:', error);
    throw error;
  }
}

Native Module vs Turbo Module: comparație

Comparația Native Module clasic și Turbo Module ajută să înțelegeți ce abordare să alegeți pentru un proiect nou. Ambele mecanisme oferă acces la codul nativ, dar diferă fundamental prin arhitectură și performanță.

CaracteristicăNative Module (Bridge)Turbo Module (JSI)
ComunicareAsincronă prin JSONSincronă prin JSI
SerializareJSON la fiecare apelFără copierea datelor
TipizareManuală, fără generareAutomată prin Codegen
ÎncărcareLa inițializarea aplicațieiÎntârziată (lazy load)
CompatibilitateToate versiunile React NativeReact Native 0.73+

Pentru proiectele existente pe React Native 0.72 și mai vechi, Native Module clasic rămâne alegerea principală. Pentru proiecte noi se recomandă utilizarea Turbo Module, mai ales dacă este necesară performanță ridicată la apeluri frecvente ale metodelor native. Odată cu actualizarea treptată a React Native, comunitatea se îndreaptă către tranziția completă la noua arhitectură.

Întrebări frecvente

Se poate transmite callback în loc de Promise în Native Module?

Da, Bridge suportă callback. În loc de Promise se pot folosi funcțiile de apel invers RCTResponseSenderBlock în iOS și Callback în Android. Totuși, Promise este considerat standardul modern și este recomandat pentru modulele noi.

Cum se depanează Native Module în Xcode sau Android Studio?

Native Module se depanează ca orice cod nativ — setați puncte de întrerupere în Xcode sau Android Studio. Pentru iOS folosiți schema de build cu React Native, pentru Android — configurația Debug. Punctul de intrare — metodele apelate din JS.

Ce tipuri de date NU suportă Native Module?

Native Module prin Bridge nu suportă date binare (NSData/byte[]), obiecte personalizate și funcții. Pentru transmiterea imaginilor folosiți calea către fișier sau șirul base64. Turbo Module prin JSI elimină o parte din aceste limitări.

Trebuie rescris Native Module la actualizarea React Native?

De obicei nu — Native Module API este stabil și compatibil retroactiv. La trecerea la noua arhitectură (Turbo Module) modulul se adaptează prin decoratori, dar codul existent continuă să funcționeze.

Cum se trimite un eveniment din Native Module în JavaScript?

Folosiți RCTEventEmitter în iOS sau DeviceEventEmitter în Android. Modulul trimite evenimentul, iar partea JS se abonează prin NativeEventEmitter din react-native. Acest lucru este util pentru date în flux și evenimente ale senzorilor.

Rezumat

  • Native Module — clasă Java/Objective-C care face API-urile native accesibile din JavaScript în React Native.
  • Înregistrare — iOS folosește RCT_EXPORT_MODULE, Android — ReactContextBaseJavaModule cu @ReactMethod.
  • Apelare — din JS modulul este accesibil prin NativeModules.Modul și suportă Promise și callback.
  • Tipuri de date — Bridge transmite doar tipuri compatibile JSON: șiruri, numere, tablouri, dicționare.
  • Performanță — Native Module clasic este inferior Turbo Module din cauza asincronității și serializării.
  • Migrare — la trecerea la React Native 0.76+ modulul poate funcționa ca Turbo Module fără rescrierea logicii.
  • Aplicație — Native Module este indispensabil pentru cameră, Bluetooth, sistem de fișiere și integrare SDK.

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.

Discutați proiectul

Citiți și