Native Module en React Native — qué es, cómo crear e integrar

Autor: IT Sectr Publicado: 2026-06-03 Tiempo de lectura: 9 min

Native Module es una clase Java u Objective-C que hace que las API nativas de la plataforma sean accesibles desde JavaScript en React Native. Cada módulo se registra en el Bridge y exporta métodos que se pueden llamar desde código JS como funciones normales. Según Meta, 2024, Native Module sigue siendo la forma principal de integrar código de plataforma en aplicaciones React Native.

Puntos clave

  • Native Module — un puente entre JavaScript y el código nativo de iOS o Android.
  • Registro — el módulo se declara mediante anotaciones de iOS (RCT_EXPORT_MODULE) o Android (@ReactMethod).
  • Tipos de datos — se admiten primitivos, cadenas, arrays, diccionarios y Promise.
  • Uso — desde JS el módulo se accede mediante NativeModules.NombreDelMódulo.
  • Nueva arquitectura — en React Native 0.76+ Native Module puede funcionar como Turbo Module a través de JSI.

¿Qué es un Native Module?

Native Module es un elemento arquitectónico de React Native que permite ejecutar código en el lenguaje de la plataforma (Objective-C/Swift para iOS, Java/Kotlin para Android) y devolver el resultado a JavaScript. Sin un Native Module es imposible acceder a las capacidades nativas del dispositivo — cámara, GPS, acelerómetro, sistema de archivos o Bluetooth.

React Native viene con un conjunto de Native Modules incorporados: CameraRoll, AsyncStorage, Geolocation, NetInfo y otros. Sin embargo, para tareas específicas — integración de SDK de terceros, trabajo con sensores de hardware o procesos en segundo plano — el desarrollador crea módulos personalizados. Según la encuesta State of React Native 2024, el 67% de los desarrolladores utiliza al menos un Native Module personalizado en sus proyectos.

La arquitectura de Native Module depende de la versión de React Native. En la arquitectura clásica (React Native 0.72 y anteriores) el módulo se conecta a través del Bridge y se comunica con JS de forma asíncrona mediante serialización JSON. En la nueva arquitectura (React Native 0.76+) el módulo puede funcionar como Turbo Module, utilizando JSI para acceso síncrono sin serialización.

Creación de un Native Module para iOS

La creación de un Native Module para iOS comienza con la declaración de una clase Objective-C que implementa el protocolo RCTBridgeModule. La macro RCT_EXPORT_MODULE registra el módulo en el Bridge, y RCT_EXPORT_METHOD exporta un método disponible desde JavaScript.

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

El método compressImage recibe una ruta de imagen y calidad de compresión (0.0–1.0), procesa los datos en el lado nativo y devuelve la ruta al archivo comprimido. La ventaja clave es que la compresión se realiza mediante código nativo, que es significativamente más rápido y eficiente en memoria que la operación equivalente en JavaScript.

Para módulos Swift, se usa la anotación @objc antes de la clase y los métodos para que estén disponibles para el runtime de Objective-C con el que trabaja el Bridge. La clase debe heredar de NSObject e implementar RCTBridgeModule.

swift
// ImageCompressor.swift — Módulo Swift Native
@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)
    }
}

Creación de un Native Module para Android

En Android, un Native Module se crea como una clase Java que extiende ReactContextBaseJavaModule. La anotación @ReactMethod exporta el método al Bridge. La interfaz Promise de com.facebook.react.bridge se utiliza para devolver resultados.

java
// ImageCompressorModule.java — Módulo Android Native
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());
        }
    }
}

El método getName() devuelve el nombre del módulo bajo el cual será accesible desde JavaScript. En el ejemplo anterior, el módulo se registra como ImageCompressor. La anotación @ReactMethod indica al Bridge que el método debe ser exportado. Importante: los métodos deben ser void y solo aceptar tipos compatibles con el Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.

Después de crear la clase del módulo, debe registrarse en el paquete de la aplicación. Para ello, se crea una clase que implementa ReactPackage y se añade a la lista de módulos en el método createNativeModules.

java
// ImageCompressorPackage.java — registro del módulo
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();
    }
}

Registro y uso de un Native Module

Después de crear los módulos para ambas plataformas, deben registrarse en React Native. Para Android, el paquete se añade en MainApplication.java en el método getPackages(). Para iOS, el módulo se registra automáticamente mediante la macro RCT_EXPORT_MODULE, pero también se puede usar el registro manual en AppDelegate.mm.

java
// MainApplication.java — agregando paquete 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;
        }
    };
}

Después del registro, el módulo está disponible en JavaScript a través de NativeModules. React Native utiliza automáticamente el nombre del módulo especificado en getName() para Android o RCT_EXPORT_MODULE para iOS.

js
// Usando Native Module desde 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('Comprimido:', result);
    return result;
  } catch (error) {
    console.error('Error de compresión:', error);
    throw error;
  }
}

Native Module vs Turbo Module: comparación

La comparación del Native Module clásico con Turbo Module ayuda a entender qué enfoque elegir para un nuevo proyecto. Ambos mecanismos proporcionan acceso al código nativo, pero difieren fundamentalmente en arquitectura y rendimiento.

CaracterísticaNative Module (Bridge)Turbo Module (JSI)
ComunicaciónAsíncrona mediante JSONSíncrona mediante JSI
SerializaciónJSON en cada llamadaSin copia de datos
TipadoManual, sin generaciónAutomático mediante Codegen
CargaEn la inicialización de la aplicaciónCarga diferida (lazy load)
CompatibilidadTodas las versiones de React NativeReact Native 0.73+

Para proyectos existentes en React Native 0.72 y anteriores, los Native Modules clásicos siguen siendo la opción principal. Para nuevos proyectos, se recomienda Turbo Module, especialmente si se requiere alto rendimiento en llamadas frecuentes a métodos nativos. Con la actualización gradual de React Native, la comunidad avanza hacia una transición completa a la nueva arquitectura.

Preguntas frecuentes

¿Se puede pasar un callback en lugar de Promise en un Native Module?

, el Bridge admite callbacks. En lugar de Promise, se pueden usar funciones callback RCTResponseSenderBlock en iOS y Callback en Android. Sin embargo, Promise se considera el estándar moderno y se recomienda para nuevos módulos.

¿Cómo depurar un Native Module en Xcode o Android Studio?

Un Native Module se depura como código nativo normal — establezca puntos de interrupción en Xcode o Android Studio. Para iOS, use el esquema de compilación con React Native; para Android, use la configuración Debug. El punto de entrada son los métodos llamados desde JS.

¿Qué tipos de datos NO admite Native Module?

Native Module a través del Bridge no admite datos binarios (NSData/byte[]), objetos personalizados ni funciones. Para imágenes, use una ruta de archivo o cadena base64. Turbo Module mediante JSI elimina algunas de estas limitaciones.

¿Es necesario reescribir un Native Module al actualizar React Native?

Generalmente no — la API de Native Module es estable y compatible con versiones anteriores. Al hacer la transición a la nueva arquitectura (Turbo Module), el módulo se adapta mediante decoradores, pero el código existente sigue funcionando.

¿Cómo enviar un evento desde un Native Module a JavaScript?

Use RCTEventEmitter en iOS o DeviceEventEmitter en Android. El módulo envía un evento y la parte JS se suscribe mediante NativeEventEmitter de react-native. Esto es útil para datos en streaming y eventos de sensores.

Resumen

  • Native Module — una clase Java/Objective-C que hace que las API nativas sean accesibles desde JavaScript en React Native.
  • Registro — iOS usa RCT_EXPORT_MODULE, Android usa ReactContextBaseJavaModule con @ReactMethod.
  • Invocación — desde JS el módulo se accede mediante NativeModules.Module y admite Promise y callback.
  • Tipos de datos — el Bridge solo transfiere tipos compatibles con JSON: cadenas, números, arrays, diccionarios.
  • Rendimiento — el Native Module clásico es inferior al Turbo Module debido a la asincronía y serialización.
  • Migración — al actualizar a React Native 0.76+ el módulo puede funcionar como Turbo Module sin reescribir la lógica.
  • Aplicación — Native Module es indispensable para cámara, Bluetooth, sistema de archivos e integración de SDK.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también