Native Module in React Native — cos'è, come creare e integrare

Autore: IT Sectr Pubblicato: 2026-06-03 Tempo di lettura: 9 min

Native Module è una classe Java o Objective-C che rende le API native della piattaforma accessibili da JavaScript in React Native. Ogni modulo viene registrato nel Bridge ed esporta metodi che possono essere chiamati dal codice JS come funzioni normali. Secondo Meta, 2024, Native Module rimane il modo principale per integrare il codice della piattaforma nelle applicazioni React Native.

Punti chiave

  • Native Module — un ponte tra JavaScript e il codice nativo iOS o Android.
  • Registrazione — il modulo viene dichiarato tramite annotazioni iOS (RCT_EXPORT_MODULE) o Android (@ReactMethod).
  • Tipi di dati — sono supportati primitivi, stringhe, array, dizionari e Promise.
  • Utilizzo — da JS il modulo è accessibile tramite NativeModules.NomeModulo.
  • Nuova architettura — in React Native 0.76+ Native Module può funzionare come Turbo Module tramite JSI.

Cos'è un Native Module?

Native Module è un elemento architetturale di React Native che consente di eseguire codice nel linguaggio della piattaforma (Objective-C/Swift per iOS, Java/Kotlin per Android) e restituire il risultato a JavaScript. Senza un Native Module è impossibile accedere alle capacità native del dispositivo — fotocamera, GPS, accelerometro, file system o Bluetooth.

React Native viene fornito con un insieme di Native Module integrati: CameraRoll, AsyncStorage, Geolocation, NetInfo e altri. Tuttavia, per attività specifiche — integrazione di SDK di terze parti, lavoro con sensori hardware o processi in background — lo sviluppatore crea moduli personalizzati. Secondo il sondaggio State of React Native 2024, il 67% degli sviluppatori utilizza almeno un Native Module personalizzato nei propri progetti.

L'architettura di Native Module dipende dalla versione di React Native. Nell'architettura classica (React Native 0.72 e precedenti) il modulo si connette tramite il Bridge e comunica con JS in modo asincrono tramite serializzazione JSON. Nella nuova architettura (React Native 0.76+) il modulo può funzionare come Turbo Module, utilizzando JSI per l'accesso sincrono senza serializzazione.

Creazione di un Native Module per iOS

La creazione di un Native Module per iOS inizia con la dichiarazione di una classe Objective-C che implementa il protocollo RCTBridgeModule. La macro RCT_EXPORT_MODULE registra il modulo nel Bridge, e RCT_EXPORT_METHOD esporta un metodo disponibile da JavaScript.

objective-c
// ImageCompressor.m — Native Module per 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

Il metodo compressImage accetta un percorso immagine e una qualità di compressione (0.0–1.0), elabora i dati sul lato nativo e restituisce il percorso al file compresso. Il vantaggio principale è che la compressione viene eseguita da codice nativo, che è significativamente più veloce ed efficiente in memoria rispetto all'operazione equivalente in JavaScript.

Per i moduli Swift, l'annotazione @objc viene utilizzata prima della classe e dei metodi per renderli disponibili al runtime Objective-C con cui lavora il Bridge. La classe deve ereditare da NSObject e implementare RCTBridgeModule.

swift
// ImageCompressor.swift — Modulo Swift Nativo
@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)
    }
}

Creazione di un Native Module per Android

Su Android, un Native Module viene creato come classe Java che estende ReactContextBaseJavaModule. L'annotazione @ReactMethod esporta il metodo nel Bridge. L'interfaccia Promise di com.facebook.react.bridge viene utilizzata per restituire i risultati.

java
// ImageCompressorModule.java — Native Module per 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());
        }
    }
}

Il metodo getName() restituisce il nome del modulo sotto cui sarà accessibile da JavaScript. Nell'esempio sopra, il modulo è registrato come ImageCompressor. L'annotazione @ReactMethod indica al Bridge che il metodo deve essere esportato. Importante: i metodi devono essere void e accettare solo i tipi supportati dal Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.

Dopo aver creato la classe del modulo, deve essere registrata nel pacchetto dell'applicazione. Per questo, viene creata una classe che implementa ReactPackage e aggiunta all'elenco dei moduli nel metodo createNativeModules.

java
// ImageCompressorPackage.java — registrazione del modulo
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();
    }
}

Registrazione e utilizzo di un Native Module

Dopo aver creato i moduli per entrambe le piattaforme, devono essere registrati in React Native. Per Android, il pacchetto viene aggiunto in MainApplication.java nel metodo getPackages(). Per iOS, il modulo viene registrato automaticamente tramite la macro RCT_EXPORT_MODULE, ma è possibile utilizzare anche la registrazione manuale in AppDelegate.mm.

java
// MainApplication.java — aggiunta pacchetto a 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;
        }
    };
}

Dopo la registrazione, il modulo diventa disponibile in JavaScript tramite NativeModules. React Native utilizza automaticamente il nome del modulo specificato in getName() per Android o RCT_EXPORT_MODULE per iOS.

js
// Utilizzo di Native Module da 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('Compresso:', result);
    return result;
  } catch (error) {
    console.error('Compressione fallita:', error);
    throw error;
  }
}

Native Module vs Turbo Module: confronto

Il confronto tra il Native Module classico e Turbo Module aiuta a capire quale approccio scegliere per un nuovo progetto. Entrambi i meccanismi forniscono accesso al codice nativo, ma differiscono fondamentalmente per architettura e prestazioni.

CaratteristicaNative Module (Bridge)Turbo Module (JSI)
ComunicazioneAsincrona tramite JSONSincrona tramite JSI
SerializzazioneJSON ad ogni chiamataSenza copia dei dati
TipizzazioneManuale, senza generazioneAutomatica tramite Codegen
CaricamentoAll'inizializzazione dell'applicazioneCaricamento differito (lazy load)
CompatibilitàTutte le versioni di React NativeReact Native 0.73+

Per i progetti esistenti su React Native 0.72 e precedenti, i Native Module classici rimangono la scelta principale. Per i nuovi progetti, si consiglia Turbo Module, specialmente se sono richieste prestazioni elevate per chiamate frequenti a metodi nativi. Con l'aggiornamento graduale di React Native, la comunità si sta muovendo verso una transizione completa alla nuova architettura.

Domande frequenti

Si può passare un callback invece di una Promise in un Native Module?

, il Bridge supporta i callback. Invece di Promise, si possono usare funzioni callback RCTResponseSenderBlock in iOS e Callback in Android. Tuttavia, Promise è considerato lo standard moderno ed è raccomandato per i nuovi moduli.

Come si esegue il debug di un Native Module in Xcode o Android Studio?

Un Native Module viene eseguito il debug come codice nativo normale — impostare punti di interruzione in Xcode o Android Studio. Per iOS, utilizzare lo schema di build con React Native; per Android, utilizzare la configurazione Debug. Il punto di ingresso sono i metodi chiamati da JS.

Quali tipi di dati Native Module NON supporta?

Native Module tramite Bridge non supporta dati binari (NSData/byte[]), oggetti personalizzati e funzioni. Per le immagini, utilizzare un percorso file o una stringa base64. Turbo Module tramite JSI rimuove alcune di queste limitazioni.

È necessario riscrivere un Native Module quando si aggiorna React Native?

Di solito no — l'API Native Module è stabile e retrocompatibile. Durante la transizione alla nuova architettura (Turbo Module), il modulo viene adattato tramite decoratori, ma il codice esistente continua a funzionare.

Come inviare un evento da un Native Module a JavaScript?

Utilizzare RCTEventEmitter in iOS o DeviceEventEmitter in Android. Il modulo invia un evento e il lato JS si iscrive tramite NativeEventEmitter di react-native. Questo è utile per dati in streaming ed eventi dei sensori.

Riepilogo

  • Native Module — una classe Java/Objective-C che rende le API native accessibili da JavaScript in React Native.
  • Registrazione — iOS usa RCT_EXPORT_MODULE, Android usa ReactContextBaseJavaModule con @ReactMethod.
  • Invocazione — da JS il modulo è accessibile tramite NativeModules.Module e supporta Promise e callback.
  • Tipi di dati — il Bridge trasferisce solo tipi compatibili JSON: stringhe, numeri, array, dizionari.
  • Prestazioni — il Native Module classico è inferiore a Turbo Module a causa di asincronicità e serializzazione.
  • Migrazione — quando si passa a React Native 0.76+ il modulo può funzionare come Turbo Module senza riscrivere la logica.
  • Applicazione — Native Module è indispensabile per fotocamera, Bluetooth, file system e integrazione SDK.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche