React NativeでのBridge — 定義、仕組み、相互作用

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

BridgeはReact Nativeのアーキテクチャコンポーネントであり、JavaScriptスレッドとiOS・Androidのネイティブ環境の間の非同期コミュニケーションを提供します。これはキューを経由してシリアライズされたJSONメッセージを送信し、JSコードからネイティブAPIを呼び出すことを可能にします。Meta, 2024によると、Bridgeは現存のアプリケーションの基盤として残っていますが、JSIベースの新アーキテクチャに比べてパフォーマンスで遅れをとっています。

メインポイント

  • BridgeはReact NativeにおけるJavaScriptとネイティブコードの間の非同期コミュニケーションチャネルです。
  • シリアライゼーション — 送信前にすべてのデータがJSONに変換され、オーバーヘッドが発生します。
  • 非同期性 — メッセージはキューを経由して送信されるため、JSはネイティブスレッドをブロックしません。
  • 制約 — Bridgeはシリアライゼーションコストのため、頻繁な小さな呼び出しには不適しています。
  • 置き換え — 新しいReact Nativeアーキテクチャでは、BridgeはJSIとTurbo Moduleに置き換えられます。

React NativeでのBridgeとは?

BridgeはReact Nativeの重要なアーキテクチャ要素であり、アプリケーションのビジネスロジックが実行されるJavaScriptスレッドと、ネイティブのiOS・Androidスレッドの間で、双方向の非同期コミュニケーションを提供します。2015年のReact Nativeリリース以来、BridgeはJSコードがプラットフォームAPI—カメラ、地理位置情報、ファイルシステム、通知、その他のネイティブ機能—と相互作用する唯一の方法です。

Bridgeアーキテクチャはメッセージキューの原理に基づいています。JavaScriptコードがネイティブメソッドを呼ぶと、リクエストはJSON文字列にシリアライズされ、キューに入れられ、非同期的にネイティブ側に送信されます。ネイティブコードがリクエストを処理し、対応する操作を実行し、結果を同じキューを経由してJSスレッドに戻します。React Conf 2021でのMetaの報告によると、平均的なアプリでは秒間に最大10,000のメッセージがBridgeを通過しています。

Bridgeの動作に関わる主なスレッドは、JavaScript Thread(JSコードの実行、Native Thread(ネイティブ操作の実行、Shadow Thread(Yogaを使用したレイアウト計算です。それぞれのスレッドは独立して動作するため、UIのレスポンシブなす—ネイティブアニメーションがJSの計算でブロックされることはありません。

Bridgeアーキテクチャの仕組み

Bridgeはコミュニケーションに3つの主要なメカニズムを使用します: MessageQueue、JSONシリアライゼーション、メッセージのバッチ化。MessageQueueはReact Nativeの内部コンポーネントで、JSとネイティブ側の間の呼出しキューを管理します。各ネイティブメソッドの呼出しはキューに入れられ、シリアライズされ、パフォーマンス最適化のためにバッチで送信されます。

MessageQueueとシリアライゼーション

MessageQueueはバッチ化の原理で動作します: ネイティブメソッドの呼出しが蓄積され、5–15ミリ秒ごとに単一のグループ(バッチ)として送信されます。これにより、複数の呼出しが1つのJSONパッケージにぱっくされるため、シリアライゼーションのオーバーヘッドが減少します。ネイティブ側では、メッセージはデシリアライズされ、対応するモジュールに分配されます。

モジュールの登録

ネイティブモジュールは、マクロまたは注釈を通じて自動的に登録されます。iOSはRCT_EXPORT_MODULEマクロを使用し、Androidは@ReactMethod注釈を使用します。React Nativeはアプリケーション起動時に登録されたモジュールをスキャンし、利用可能なすべてのメソッドの構成JSONマップを構築します。このマップはJS環境に渡され、JavaScriptはどのメソッドが呼べるかを学びます。

データフロー

データは次のパスを従います: JavaScriptがNativeModules.CalendarModule.createCalendarEvent()を呼び出します。メソッドは、モジュール識別子、メソッド名、引数を含むJSONメッセージにシリアライズされます。メッセージはMessageQueueに入ります。ネイティブスレッドで、メッセージはデシリアライズされ、対応するモジュールに渡されます。実行結果はシリアライズされて戻され、PromiseまたはcallbackとしてJSスレッドに送信されます。

js
            // JavaScriptからBridgeを経由したネイティブモジュール呼び出し
import { NativeModules } from 'react-native';

const CalendarModule = NativeModules.CalendarModule;

CalendarModule.createCalendarEvent('Test Event', 'Office')
  .then(eventId => {
    console.log('次のIDでイベントが作成されました:', eventId);
  })
  .catch(error => {
    console.error('失敗しました:', error);
  });

ネイティブのiOS側では、モジュールはRCT_EXPORT_MODULEマクロを持つObjective-Cクラスとして表されます。メソッドはRCT_EXPORT_METHODマクロでエクスポートされ、React Nativeが自動的にBridgeに登録します。引数は位置で渡され、サポートされるJSON型(NSString、NSNumber、NSArray、NSDictionary、BOOL)に対応する必要があります。

objective-c
            // BridgeでのiOSネイティブモジュール登録
@interface CalendarModule () RCT_EXPORT_MODULE()
@end

@implementation CalendarModule

RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name
                  location:(NSString *)location
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  NSNumber *eventId = createEvent(name, location);
  resolve(eventId);
}

@end

Bridgeの制約と問題点

Bridgeにはいくつかの根本的なパフォーマンス制約があります。主なものは、強制的な非同期性とシリアライゼーションです。ネイティブメソッドの呼び出しごとにデータがJSON文字列に変換され、レンタンシの増加とメモリ消費を引き起こします。画像処理や動画処理など、大量のデータを扱う操作では、これがボトルネックとなります。

シリアライゼーションコスト

JSONのシリアライゼーションとデシリアライゼーションは、CPUタイムとメモリを消費します。各メッセージはJS側で文字列に変換され、ブリッジを経由して伝送され、ネイティブ側で解析される必要があります。Callstackのテスト(2022)によると、Bridgeを経由して10,000の数値からなる配列をシリアライズするのに約30–50ミリ秒かかり、高頻度の呼び出しには不可能です。

メッセージサイズの制約

Bridgeは大きなバイナリデータの転送には最適化されていません。写真、音声ファイル、動画ストリームには代替アプローチが必要です—例えば、ファイルをディスクに書き出し、パスを文字列として渡す方法です。これにより、ファイルシステムの読み出しと書き込みに追加のオーバーヘッドが生じます。

  • 非同期性 — Bridgeは同期呼び出しをサポートしないため、即時答えが必要なシナリオが複雑になります。
  • メモリ — 各メッセージは処理されるまでキューに格納されるため、メモリ消費が増加する可能性があります。
  • デバッグ — Bridgeでのメッセージ追跡は、呼出しチェーンがスレッド間で切れるため困難です。

これらの制約の認識により、Metaチームは新たなReact Nativeアーキテクチャを開発し、BridgeをJSI(JavaScript Interface)とTurbo Moduleに置き換えました。JSIは、シリアライゼーションなしで直接ネイティブメソッドを呼ぶことを可能にし、Bridgeの主な缺点を解消します。

BridgeとTurbo Moduleの比較

BridgeとTurbo Moduleの比較は、アーキテクチャアプローチの根本的な違いを示しています。BridgeはJSONシリアライゼーションを伴う非同期メッセージキューを使用するの対し、Turbo ModuleはJSIを通して動作します—JavaScriptとC++の間の直接インタフェースで、データ変換なしにネイティブメソッドを同期的に呼ぶことができます。

特徴BridgeTurbo Module
呼び出しの種類非同期同期および非同期
シリアライゼーション呼び出しごとにJSONコピー不要のJSIオブジェクト
パフォーマンス中程度高い
型付け動的静的 (Codegen)
ロード起動時にすべてのモジュール懒動的 (オンデマンド)

BridgeとTurbo Moduleの選択は、React Nativeのバージョンに依存します。React Native 0.72以前のプロジェクトでは、Bridgeが主なメカニズムとなります。React Native 0.73よりも、Metroと新アーキテクチャが並行サポートされ、段階的な移行が可能になります。Turbo Moduleへの完全な移行には、React Native 0.76+へのアップグレードと、構成で新アーキテクチャの有効化が必要です。

Bridgeを経由したNative Moduleの設定例

カレンダーモジュールを例に、Bridgeを経由したNative Moduleの作成から使用までの完全なサイクルを見ていきます。このモジュールはイベントを作成し、その識別子を戻します。この例は、iOSとAndroidの両プラットフォームの設定をカバーしています。

Androidモジュール

Androidでは、Native ModuleはReactContextBaseJavaModuleを継承するJavaクラスとして作成されます。@ReactMethod注釈がメソッドをBridgeにエクスポートします。Promiseには、com.facebook.react.bridgeからのPromiseインタフェースが使用されます。

java
public class CalendarModule extends ReactContextBaseJavaModule {

    @Override
    public String getName() {
        return "CalendarModule";
    }

    @ReactMethod
    public void createCalendarEvent(
            String name,
            String location,
            Promise promise) {
        try {
            Integer eventId = createCalendarEventNative(name, location);
            promise.resolve(eventId);
        } catch (Exception e) {
            promise.reject("EVENT_ERROR", e.getMessage());
        }
    }
}

登録と使用

モジュールは@ReactModuleを通じて、またはアプリケーションパッケージ内で手動で登録されます。React Nativeが自動的に検出してBridgeに追加します。登録後、モジュールはNativeModulesを経由してJavaScriptからアクセス可能になります。

java
public class CalendarPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        return Arrays.asList(
            new CalendarModule(reactContext)
        );
    }

    @Override
    public List<ViewManager> createViewManagers(
            ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

新しいモジュールを追加する際、Bridgeはアプリの再起動が必要であることに注意してください。構成マップは初期化時に4回構築されるからです。これが、懒動的にロードされ、再起動なしでモジュールのホットリロードをサポートするTurbo Moduleとの違いです。

よくある質問

Bridgeは直接データ伝送とどう違いますか?

Bridgeは常に非同期キューとJSONシリアライゼーションを使用するの対し、JSIを経由する直接伝送は同期的に、データコピーなしで動作します。Bridgeはシリアライゼーションレンタンシはありますが、スレッドの精熶を確保します。

Bridgeを経由してメソッドを同期的に呼ぶことはできますか?

いいえ、Bridgeは非同期呼び出しのみをサポートしています。同期相互作用には、JSIとTurbo Moduleを使用した新しいアーキテクチャが必要です。これはReact Native 0.76+で解決された主な制約の一つです。

Bridgeはどのようなデータ型をサポートしていますか?

BridgeはJSONにシリアライズ可能な型をサポートしています: 文字列、数値、ブール値、配列、辞書(オブジェクト)。画像のようなバイナリデータは、ファイルシステムまたはbase64エンコードを経由して伝送する必要があります。

Bridgeのパフォーマンスを測る方法は?

測定には、React DevToolsとReact Nativeプロファイラを使用します。Performanceタブでは、Bridgeキュー内のメッセージ数とレンタンシが表示されます。トラフィック監視にはreact-native-bridge-spyパッケージも利用可能です。

いつBridgeからTurbo Moduleに移行すべきですか?

パフォーマンスが問題となるプロジェクトや、React Native 0.76+で新規アプリを作成する場合は、移行を推奨します。既存プロジェクトの場合、移行は段階的に行うことができます—両アーキテクチャは並行動作します。

まとめ

  • BridgeはJSONシリアライゼーションに基づく、JavaScriptとネイティブのReact Nativeコードの間の非同期コミュニケーション機構です。
  • MessageQueueはメッセージキューを管理し、呼出しをバッチにまとめてオーバーヘッドを削減します。
  • シリアライゼーションは、Bridgeを経由して大きなデータ配列を伝送する際に30–50ミリ秒の遅延を生じます。
  • 制約には、同期呼出しがないことと、頻繁なメッセージによる高いメモリ消費が含まれます。
  • 新アーキテクチャはBridgeをJSIとTurbo Moduleに置き換え、シリアライゼーションなしの直接アクセスを提供します。
  • 互換性 — BridgeはReact Native 0.72+まで動作し続け、0.73+では両アーキテクチャの並行動作が可能です。
  • 選択 — 新規プロジェクトには新アーキテクチャが推奨され、既存プロジェクトは段階的に移行します。

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

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

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

こちらもお読みください