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 — 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());
        }
    }
}

Метод 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 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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