Native Module в React Native — что это, как создавать и интегрировать

Автор: IT Sectr Опубликовано: 2026-06-03 Время чтения: 9 мин

Native Module — это Java или Objective-C класс, который делает нативные API платформы доступными из JavaScript в React Native. Каждый модуль регистрируется в Bridge и экспортирует методы, которые можно вызывать из JS-кода как обычные функции. По данным Meta, 2024, Native Module остаётся основным способом интеграции платформенного кода в React Native-приложения.

Главное

  • Native Module — мост между JavaScript и нативным кодом iOS или Android.
  • Регистрация — модуль объявляется через аннотации iOS (RCT_EXPORT_MODULE) или Android (@ReactMethod).
  • Типы данных — поддерживаются примитивы, строки, массивы, словари и Promise.
  • Использование — из JS модуль доступен через NativeModules.ИмяМодуля.
  • Новая архитектура — в React Native 0.76+ Native Module может работать как Turbo Module через JSI.

Что такое Native Module?

Native Module — это архитектурный элемент React Native, который позволяет выполнять код на языке платформы (Objective-C/Swift для iOS, Java/Kotlin для Android) и возвращать результат в JavaScript. Без Native Module невозможно получить доступ к нативным возможностям устройства — камере, GPS, акселерометру, файловой системе или Bluetooth.

React Native поставляется с набором встроенных Native Module: CameraRoll, AsyncStorage, Geolocation, NetInfo и другие. Однако для специфических задач — интеграция стороннего SDK, работа с аппаратными датчиками или фоновые процессы — разработчик создаёт собственные модули. По данным опроса State of React Native 2024, 67% разработчиков используют как минимум один кастомный Native Module в своих проектах.

Архитектура Native Module зависит от версии React Native. В классической архитектуре (React Native 0.72 и старше) модуль подключается через Bridge и общается с JS асинхронно через JSON-сериализацию. В новой архитектуре (React Native 0.76+) модуль может работать как Turbo Module, используя JSI для синхронного доступа без сериализации.

Создание Native Module для iOS

Создание Native Module для iOS начинается с объявления Objective-C класса, который реализует протокол RCTBridgeModule. Макрос RCT_EXPORT_MODULE регистрирует модуль в Bridge, а RCT_EXPORT_METHOD экспортирует метод, доступный из JavaScript.

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

Метод compressImage принимает путь к изображению и качество сжатия (0.0–1.0), обрабатывает данные на нативной стороне и возвращает путь к сжатому файлу. Ключевое преимущество — сжатие выполняется нативным кодом, что значительно быстрее и эффективнее по памяти, чем аналогичная операция на JavaScript.

Для Swift-модулей используется аннотация @objc перед классом и методами, чтобы они были доступны Objective-C рантайму, с которым работает Bridge. При этом класс должен наследовать NSObject и реализовывать RCTBridgeModule.

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

Создание Native Module для Android

На Android Native Module создаётся как Java-класс, наследующий ReactContextBaseJavaModule. Аннотация @ReactMethod экспортирует метод в Bridge. Для возврата результата используется интерфейс Promise из com.facebook.react.bridge.

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

Метод getName() возвращает имя модуля, под которым он будет доступен из JavaScript. В приведённом примере модуль регистрируется как ImageCompressor. Аннотация @ReactMethod указывает Bridge, что метод должен быть экспортирован. Важно: методы должны быть void и принимать только типы, поддерживаемые Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.

После создания класса модуль необходимо зарегистрировать в пакете приложения. Для этого создаётся класс, реализующий ReactPackage, и добавляется в список модулей в методе createNativeModules.

java
// ImageCompressorPackage.java — module registration
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();
    }
}

Регистрация и использование Native Module

После создания модулей для обеих платформ их необходимо зарегистрировать в React Native. Для Android пакет добавляется в MainApplication.java в метод getPackages(). Для iOS модуль автоматически регистрируется через макрос RCT_EXPORT_MODULE, но можно использовать и ручную регистрацию в файле AppDelegate.mm.

java
// MainApplication.java — adding package to 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;
        }
    };
}

После регистрации модуль становится доступным в JavaScript через NativeModules. React Native автоматически подставляет имя модуля, указанное в getName() для Android или в RCT_EXPORT_MODULE для iOS.

js
// Using Native Module from 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('Compressed:', result);
    return result;
  } catch (error) {
    console.error('Compression failed:', error);
    throw error;
  }
}

Native Module vs Turbo Module: сравнение

Сравнение классического Native Module и Turbo Module помогает понять, какой подход выбрать для нового проекта. Оба механизма предоставляют доступ к нативному коду, но принципиально различаются по архитектуре и производительности.

ХарактеристикаNative Module (Bridge)Turbo Module (JSI)
КоммуникацияАсинхронная через JSONСинхронная через JSI
СериализацияJSON на каждый вызовБез копирования данных
ТипизацияРучная, без генерацииАвто через Codegen
ЗагрузкаПри инициализации приложенияЛенивая (lazy load)
СовместимостьВсе версии React NativeReact Native 0.73+

Для существующих проектов на React Native 0.72 и старше классические Native Module остаются основным выбором. Для новых проектов рекомендуется использовать Turbo Module, особенно если требуется высокая производительность при частых вызовах нативных методов. С постепенным обновлением React Native сообщество движется к полному переходу на новую архитектуру.

Часто задаваемые вопросы

Можно ли передавать callback вместо Promise в Native Module?

Да, Bridge поддерживает callback. Вместо Promise можно использовать функции обратного вызова RCTResponseSenderBlock в iOS и Callback в Android. Однако Promise считается современным стандартом и рекомендуется для новых модулей.

Как отладить Native Module в Xcode или Android Studio?

Native Module отлаживается как обычный нативный код — установите брейкпоинты в Xcode или Android Studio. Для iOS используйте схему сборки с React Native, для Android — Debug-конфигурацию. Точка входа — методы, вызванные из JS.

Какие типы данных НЕ поддерживает Native Module?

Native Module через Bridge не поддерживает бинарные данные (NSData/byte[]), пользовательские объекты и функции. Для передачи изображений используйте путь к файлу или base64-строку. Turbo Module через JSI снимает часть этих ограничений.

Нужно ли переписывать Native Module при обновлении React Native?

Обычно нет — Native Module API стабилен и обратно совместим. При переходе на новую архитектуру (Turbo Module) модуль адаптируется через декораторы, но существующий код продолжает работать.

Как отправить событие из Native Module в JavaScript?

Используйте RCTEventEmitter в iOS или DeviceEventEmitter в Android. Модуль отправляет событие, а JS-сторона подписывается через NativeEventEmitter из react-native. Это полезно для потоковых данных и событий датчиков.

Итоги

  • Native Module — Java/Objective-C класс, который делает нативные API доступными из JavaScript в React Native.
  • Регистрация — iOS использует RCT_EXPORT_MODULE, Android — ReactContextBaseJavaModule с @ReactMethod.
  • Вызов — из JS модуль доступен через NativeModules.Модуль и поддерживает Promise и callback.
  • Типы данных — Bridge передаёт только JSON-совместимые типы: строки, числа, массивы, словари.
  • Производительность — классический Native Module уступает Turbo Module из-за асинхронности и сериализации.
  • Миграция — при переходе на React Native 0.76+ модуль может работать как Turbo Module без переписывания логики.
  • Применение — Native Module незаменим для камеры, Bluetooth, файловой системы и интеграции SDK.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также