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 за 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 — регистрация на модул
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 — добавяне на пакет към 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
// Използване на Native Module от 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('Компресирано:', result);
    return result;
  } catch (error) {
    console.error('Компресията неуспешна:', error);
    throw error;
  }
}

Native Module срещу 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също