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 می‌تواند از طریق JSI به عنوان Turbo Module کار کند.

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 — Native Module Swift
@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 در مقابل 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، جامعه به سمت انتقال کامل به معماری جدید حرکت می‌کند.

سؤالات متداول

آیا می‌توان به جای Promise در Native Module callback ارسال کرد؟

بله، 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 بخشی از این محدودیت‌ها را برطرف می‌کند.

آیا هنگام به‌روزرسانی React Native باید Native Module را بازنویسی کرد؟

معمولاً خیر — 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 از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید