React NativeのNative Module — 概要、作成方法、統合方法

著者: IT Sectr 公開日: 2026-06-03 読了時間: 9 分

Native Moduleは、JavaまたはObjective-Cのクラスで、React NativeのJavaScriptからプラットフォームのネイティブAPIにアクセスできるようにします。各モジュールは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のアーキテクチャ要素であり、プラットフォーム言語(iOSの場合はObjective-C/Swift、Androidの場合はJava/Kotlin)でコードを実行し、結果をJavaScriptに返すことを可能にします。Native Moduleなしでは、デバイスのネイティブ機能(カメラ、GPS、加速度計、ファイルシステム、Bluetooth)にアクセスすることはできません。

React Nativeには組み込みのNative Moduleが用意されています:CameraRollAsyncStorageGeolocationNetInfoなどです。ただし、特定のタスク(サードパーティSDKの統合、ハードウェアセンサーの操作、バックグラウンド処理)には、開発者がカスタムモジュールを作成します。State of React Native 2024の調査によると、67%の開発者がプロジェクトで少なくとも1つのカスタムNative Moduleを使用しています。

Native ModuleのアーキテクチャはReact Nativeのバージョンによって異なります。従来のアーキテクチャ(React Native 0.72以前)では、モジュールはBridgeを介して接続し、JSONシリアライゼーションを介してJSと非同期に通信します。新しいアーキテクチャ(React Native 0.76+)では、モジュールはシリアライゼーションなしで同期アクセスのためにJSIを使用するTurbo Moduleとして動作できます。

iOS用Native Moduleの作成

iOS用のNative Moduleの作成は、RCTBridgeModuleプロトコルを実装するObjective-Cクラスの宣言から始まります。RCT_EXPORT_MODULEマクロはモジュールをBridgeに登録し、RCT_EXPORT_METHODはJavaScriptから利用可能なメソッドをエクスポートします。

objective-c
// ImageCompressor.m — iOS用Native Module
@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アノテーションを使用して、Bridgeが動作するObjective-Cランタイムからアクセスできるようにします。クラスは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)
    }
}

Android用Native Moduleの作成

Androidでは、Native ModuleはReactContextBaseJavaModuleを拡張するJavaクラスとして作成されます。@ReactMethodアノテーションはメソッドをBridgeにエクスポートします。結果を返すには、com.facebook.react.bridgeのPromiseインターフェースが使用されます。

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は、Androidの場合はgetName()、iOSの場合はRCT_EXPORT_MODULEで指定されたモジュール名を自動的に使用します。

js
// JavaScriptからNative Moduleを使用
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 NativeバージョンReact Native 0.73+

React Native 0.72以前の既存プロジェクトでは、従来のNative Moduleが引き続き主要な選択肢です。新しいプロジェクトでは、特にネイティブメソッドの頻繁な呼び出しで高いパフォーマンスが必要な場合、Turbo Moduleが推奨されます。React Nativeの段階的なアップデートに伴い、コミュニティは新しいアーキテクチャへの完全な移行に向かっています。

よくある質問

Native ModuleでPromiseの代わりにコールバックを渡せますか?

はい、Bridgeはコールバックをサポートしています。Promiseの代わりに、iOSではRCTResponseSenderBlockコールバック関数、AndroidではCallbackを使用できます。ただし、Promiseは現代的な標準と見なされており、新しいモジュールには推奨されます。

XcodeやAndroid StudioでNative Moduleをデバッグするには?

Native Moduleは通常のネイティブコードと同様にデバッグされます — XcodeまたはAndroid Studioでブレークポイントを設定します。iOSの場合はReact Nativeを使用したビルドスキーム、Androidの場合はDebug構成を使用します。エントリポイントはJSから呼び出されたメソッドです。

Native Moduleがサポートしないデータ型は?

Bridgeを介したNative Moduleは、バイナリデータ(NSData/byte[])、カスタムオブジェクト、関数をサポートしていません。画像の場合は、ファイルパスまたはbase64文字列を使用します。JSIを介したTurbo Moduleはこれらの制限の一部を解除します。

React Nativeを更新する際にNative Moduleを書き直す必要がありますか?

通常は不要です — Native Module APIは安定しており、下位互換性があります。新しいアーキテクチャ(Turbo Module)に移行する際、モジュールはデコレータを通じて適応されますが、既存のコードは引き続き動作します。

Native ModuleからJavaScriptにイベントを送信するには?

iOSではRCTEventEmitter、AndroidではDeviceEventEmitterを使用します。モジュールがイベントを送信し、JS側がreact-nativeのNativeEventEmitterを介して購読します。これはストリーミングデータやセンサーイベントに便利です。

まとめ

  • Native Module — React NativeのJavaScriptからネイティブAPIにアクセスできるようにするJava/Objective-Cクラス。
  • 登録 — iOSはRCT_EXPORT_MODULE、Androidは@ReactMethodと共にReactContextBaseJavaModuleを使用。
  • 呼び出し — JSからモジュールにはNativeModules.Moduleでアクセスし、Promiseとコールバックをサポート。
  • データ型 — BridgeはJSON互換の型(文字列、数値、配列、辞書)のみを転送。
  • パフォーマンス — 従来のNative Moduleは非同期性とシリアライゼーションのためTurbo Moduleに劣る。
  • 移行 — React Native 0.76+にアップグレードする際、モジュールはロジックを書き換えずにTurbo Moduleとして動作可能。
  • 用途 — Native Moduleはカメラ、Bluetooth、ファイルシステム、SDK統合に不可欠。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください