From 94e227d0c826f2d6469faf9503937b6bc5ec9b0f Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 17:54:13 -0700 Subject: [PATCH 01/11] Remove dead RCTBridge synthesis from four bridgeless modules Summary: RCTDevMenu, RCTLogBox, RCTRedBox, and RCTBlobManager synthesized the deprecated bridge property but never read it. They use moduleRegistry, bundleManager, and callableJSModules instead. Changelog: [Internal] Differential Revision: D126545276 --- packages/react-native/Libraries/Blob/RCTBlobManager.mm | 1 - packages/react-native/React/CoreModules/RCTDevMenu.mm | 1 - packages/react-native/React/CoreModules/RCTLogBox.mm | 2 -- packages/react-native/React/CoreModules/RCTRedBox.mm | 1 - 4 files changed, 5 deletions(-) diff --git a/packages/react-native/Libraries/Blob/RCTBlobManager.mm b/packages/react-native/Libraries/Blob/RCTBlobManager.mm index 4a29b1f826c9..3699a727028d 100755 --- a/packages/react-native/Libraries/Blob/RCTBlobManager.mm +++ b/packages/react-native/Libraries/Blob/RCTBlobManager.mm @@ -46,7 +46,6 @@ @implementation RCTBlobManager { RCT_EXPORT_MODULE(BlobModule) -@synthesize bridge = _bridge; @synthesize moduleRegistry = _moduleRegistry; @synthesize methodQueue = _methodQueue; diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 883b4ba7f8e1..bd946190df6b 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -119,7 +119,6 @@ @implementation RCTDevMenu { NSMutableArray *_extraMenuItems; } -@synthesize bridge = _bridge; @synthesize moduleRegistry = _moduleRegistry; @synthesize callableJSModules = _callableJSModules; @synthesize bundleManager = _bundleManager; diff --git a/packages/react-native/React/CoreModules/RCTLogBox.mm b/packages/react-native/React/CoreModules/RCTLogBox.mm index 7e8be47170dd..9741dc29c877 100644 --- a/packages/react-native/React/CoreModules/RCTLogBox.mm +++ b/packages/react-native/React/CoreModules/RCTLogBox.mm @@ -25,8 +25,6 @@ @implementation RCTLogBox { __weak id _bridgelessSurfacePresenter; } -@synthesize bridge = _bridge; - RCT_EXPORT_MODULE() + (BOOL)requiresMainQueueSetup diff --git a/packages/react-native/React/CoreModules/RCTRedBox.mm b/packages/react-native/React/CoreModules/RCTRedBox.mm index f2edecee813d..cc1b00688f1e 100644 --- a/packages/react-native/React/CoreModules/RCTRedBox.mm +++ b/packages/react-native/React/CoreModules/RCTRedBox.mm @@ -40,7 +40,6 @@ @implementation RCTRedBox { NSMutableArray *_customButtonHandlers; } -@synthesize bridge = _bridge; @synthesize moduleRegistry = _moduleRegistry; @synthesize bundleManager = _bundleManager; From ff7a25fb0a8429157adf4966c957ae4f58da13ff Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 18:42:29 -0700 Subject: [PATCH 02/11] Remove dead RCTBridge imports from sixteen bridgeless files Summary: Seven implementation files imported the bridge header without referencing any symbol it provides. Nine public headers either imported it redundantly or narrowed it to the module protocol header they actually need. Changelog: [Internal] Differential Revision: D126549484 --- packages/react-native/Libraries/Blob/RCTBlobManager.h | 1 - packages/react-native/Libraries/Blob/RCTFileReaderModule.mm | 1 - packages/react-native/Libraries/Image/RCTImageDataDecoder.h | 2 +- packages/react-native/Libraries/Image/RCTImageLoaderProtocol.h | 1 - packages/react-native/Libraries/Image/RCTImageURLLoader.h | 2 +- .../Libraries/PushNotificationIOS/RCTPushNotificationManager.mm | 1 - packages/react-native/Libraries/Settings/RCTSettingsManager.mm | 1 - packages/react-native/React/CoreModules/RCTActionSheetManager.h | 2 +- .../react-native/React/CoreModules/RCTActionSheetManager.mm | 1 - packages/react-native/React/CoreModules/RCTAppState.mm | 1 - packages/react-native/React/CoreModules/RCTDevLoadingView.mm | 1 - packages/react-native/React/CoreModules/RCTDeviceInfo.h | 2 +- packages/react-native/React/CoreModules/RCTEventDispatcher.h | 1 - packages/react-native/React/CoreModules/RCTLogBox.h | 1 + packages/react-native/React/CoreModules/RCTLogBox.mm | 2 +- packages/react-native/React/CoreModules/RCTLogBoxView.h | 1 - 16 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/react-native/Libraries/Blob/RCTBlobManager.h b/packages/react-native/Libraries/Blob/RCTBlobManager.h index 59659b6ac9ce..100ea51a5df1 100755 --- a/packages/react-native/Libraries/Blob/RCTBlobManager.h +++ b/packages/react-native/Libraries/Blob/RCTBlobManager.h @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -#import #import #import #import diff --git a/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm b/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm index c33e1c05893b..630750684091 100644 --- a/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm +++ b/packages/react-native/Libraries/Blob/RCTFileReaderModule.mm @@ -8,7 +8,6 @@ #import #import -#import #import #import diff --git a/packages/react-native/Libraries/Image/RCTImageDataDecoder.h b/packages/react-native/Libraries/Image/RCTImageDataDecoder.h index 1f52b4a07e7f..b8941897a115 100644 --- a/packages/react-native/Libraries/Image/RCTImageDataDecoder.h +++ b/packages/react-native/Libraries/Image/RCTImageDataDecoder.h @@ -7,7 +7,7 @@ #import -#import +#import #import #import #import diff --git a/packages/react-native/Libraries/Image/RCTImageLoaderProtocol.h b/packages/react-native/Libraries/Image/RCTImageLoaderProtocol.h index 17bc12cc7e37..a93b68f962d7 100644 --- a/packages/react-native/Libraries/Image/RCTImageLoaderProtocol.h +++ b/packages/react-native/Libraries/Image/RCTImageLoaderProtocol.h @@ -7,7 +7,6 @@ #import -#import #import #import #import diff --git a/packages/react-native/Libraries/Image/RCTImageURLLoader.h b/packages/react-native/Libraries/Image/RCTImageURLLoader.h index d0299d3fcd6a..86daffc091c7 100644 --- a/packages/react-native/Libraries/Image/RCTImageURLLoader.h +++ b/packages/react-native/Libraries/Image/RCTImageURLLoader.h @@ -7,7 +7,7 @@ #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/packages/react-native/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm b/packages/react-native/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm index 25c2867c9c85..8731cf6c0cea 100644 --- a/packages/react-native/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm +++ b/packages/react-native/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm @@ -10,7 +10,6 @@ #import #import -#import #import #import diff --git a/packages/react-native/Libraries/Settings/RCTSettingsManager.mm b/packages/react-native/Libraries/Settings/RCTSettingsManager.mm index af0bd521f02e..212ea5a72f04 100644 --- a/packages/react-native/Libraries/Settings/RCTSettingsManager.mm +++ b/packages/react-native/Libraries/Settings/RCTSettingsManager.mm @@ -8,7 +8,6 @@ #import #import -#import #import #import #import diff --git a/packages/react-native/React/CoreModules/RCTActionSheetManager.h b/packages/react-native/React/CoreModules/RCTActionSheetManager.h index 338310b89c08..5ced60a6fe8c 100644 --- a/packages/react-native/React/CoreModules/RCTActionSheetManager.h +++ b/packages/react-native/React/CoreModules/RCTActionSheetManager.h @@ -7,7 +7,7 @@ #import -#import +#import @interface RCTActionSheetManager : NSObject diff --git a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm index 104e0491fc22..d615eca6e8a3 100644 --- a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm +++ b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm @@ -13,7 +13,6 @@ #if !TARGET_OS_TV -#import #import #import #import diff --git a/packages/react-native/React/CoreModules/RCTAppState.mm b/packages/react-native/React/CoreModules/RCTAppState.mm index 7ca35bfefefd..c57bf83b6928 100644 --- a/packages/react-native/React/CoreModules/RCTAppState.mm +++ b/packages/react-native/React/CoreModules/RCTAppState.mm @@ -9,7 +9,6 @@ #import #import -#import #import #import #import diff --git a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm index 100dc3ce064e..9b3620cb9b91 100644 --- a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm +++ b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm @@ -12,7 +12,6 @@ #import #import -#import #import #import #import diff --git a/packages/react-native/React/CoreModules/RCTDeviceInfo.h b/packages/react-native/React/CoreModules/RCTDeviceInfo.h index 66c2d3218552..f3bdd908c7f2 100644 --- a/packages/react-native/React/CoreModules/RCTDeviceInfo.h +++ b/packages/react-native/React/CoreModules/RCTDeviceInfo.h @@ -7,7 +7,7 @@ #import -#import +#import @interface RCTDeviceInfo : NSObject diff --git a/packages/react-native/React/CoreModules/RCTEventDispatcher.h b/packages/react-native/React/CoreModules/RCTEventDispatcher.h index 3b31791ae73d..837c68836280 100644 --- a/packages/react-native/React/CoreModules/RCTEventDispatcher.h +++ b/packages/react-native/React/CoreModules/RCTEventDispatcher.h @@ -7,7 +7,6 @@ #import -#import #import #import /** diff --git a/packages/react-native/React/CoreModules/RCTLogBox.h b/packages/react-native/React/CoreModules/RCTLogBox.h index 17f7f4d98ef8..c42b9811099d 100644 --- a/packages/react-native/React/CoreModules/RCTLogBox.h +++ b/packages/react-native/React/CoreModules/RCTLogBox.h @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +#import #import #import "RCTLogBoxView.h" diff --git a/packages/react-native/React/CoreModules/RCTLogBox.mm b/packages/react-native/React/CoreModules/RCTLogBox.mm index 9741dc29c877..cdadc87c601c 100644 --- a/packages/react-native/React/CoreModules/RCTLogBox.mm +++ b/packages/react-native/React/CoreModules/RCTLogBox.mm @@ -8,8 +8,8 @@ #import "RCTLogBox.h" #import -#import #import +#import #import #import #import diff --git a/packages/react-native/React/CoreModules/RCTLogBoxView.h b/packages/react-native/React/CoreModules/RCTLogBoxView.h index 56d0d7ba84ef..29bf90af5ff5 100644 --- a/packages/react-native/React/CoreModules/RCTLogBoxView.h +++ b/packages/react-native/React/CoreModules/RCTLogBoxView.h @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -#import #import #import #import From e4f4b50a8b1b28a9fbe927131385d927dc33dba7 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 19:17:38 -0700 Subject: [PATCH 03/11] Drop RCTBridge reads from five new-arch-only modules Summary: RCTEventDispatcher routes via _dispatchToJSThread; RCTImageLoader and RCTNetworking require their registry-backed providers; RCTTestModule uses the injected viewRegistry_DEPRECATED; RCTViewManager drops a no-op registry write. Legacy RCTBridge is a stub, so these reads only reached RCTBridgeProxy shims. Differential Revision: D126558187 --- .../Libraries/Image/RCTImageLoader.mm | 19 ++++------------- .../Libraries/Network/RCTNetworking.mm | 5 ++--- .../React/CoreModules/RCTEventDispatcher.mm | 9 +------- .../react-native/React/Views/RCTViewManager.m | 1 - packages/rn-tester/RCTTest/RCTTestModule.mm | 21 +++++-------------- 5 files changed, 12 insertions(+), 43 deletions(-) diff --git a/packages/react-native/Libraries/Image/RCTImageLoader.mm b/packages/react-native/Libraries/Image/RCTImageLoader.mm index db468e7d4d0c..9dab28583942 100644 --- a/packages/react-native/Libraries/Image/RCTImageLoader.mm +++ b/packages/react-native/Libraries/Image/RCTImageLoader.mm @@ -85,7 +85,6 @@ @implementation RCTImageLoader { __weak id _redirectDelegate; } -@synthesize bridge = _bridge; @synthesize moduleRegistry = _moduleRegistry; @synthesize maxConcurrentLoadingTasks = _maxConcurrentLoadingTasks; @synthesize maxConcurrentDecodingTasks = _maxConcurrentDecodingTasks; @@ -134,13 +133,8 @@ - (void)setUp _URLRequestQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLRequestQueue", DISPATCH_QUEUE_SERIAL); - // Get loaders, sorted in reverse priority order (highest priority first) - if (_loadersProvider != nil) { - _loaders = _loadersProvider(self.moduleRegistry); - } else { - RCTAssert(_bridge, @"Trying to find RCTImageURLLoaders and bridge not set."); - _loaders = [_bridge modulesConformingToProtocol:@protocol(RCTImageURLLoader)]; - } + RCTAssert(_loadersProvider != nil, @"Trying to find RCTImageURLLoaders and loaders provider not set."); + _loaders = _loadersProvider(self.moduleRegistry); _loaders = [_loaders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0; @@ -154,13 +148,8 @@ - (void)setUp } }]; - // Get decoders, sorted in reverse priority order (highest priority first) - if (_decodersProvider != nil) { - _decoders = _decodersProvider(self.moduleRegistry); - } else { - RCTAssert(_bridge, @"Trying to find RCTImageDataDecoders and bridge not set."); - _decoders = [_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)]; - } + RCTAssert(_decodersProvider != nil, @"Trying to find RCTImageDataDecoders and decoders provider not set."); + _decoders = _decodersProvider(self.moduleRegistry); _decoders = [_decoders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0; diff --git a/packages/react-native/Libraries/Network/RCTNetworking.mm b/packages/react-native/Libraries/Network/RCTNetworking.mm index 8cfdecd57d5c..95e531d4e49a 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.mm +++ b/packages/react-native/Libraries/Network/RCTNetworking.mm @@ -271,9 +271,8 @@ - (void)invalidate return _handlers; } - NSArray> *newHandlers = _handlersProvider - ? _handlersProvider(self.moduleRegistry) - : [self.bridge modulesConformingToProtocol:@protocol(RCTURLRequestHandler)]; + RCTAssert(_handlersProvider != nil, @"Trying to find RCTURLRequestHandlers and handlers provider not set."); + NSArray> *newHandlers = _handlersProvider(self.moduleRegistry); // Get handlers, sorted in reverse priority order (highest priority first) newHandlers = [newHandlers diff --git a/packages/react-native/React/CoreModules/RCTEventDispatcher.mm b/packages/react-native/React/CoreModules/RCTEventDispatcher.mm index 770c746c0bf5..9f8bb3306f0c 100644 --- a/packages/react-native/React/CoreModules/RCTEventDispatcher.mm +++ b/packages/react-native/React/CoreModules/RCTEventDispatcher.mm @@ -40,7 +40,6 @@ @implementation RCTEventDispatcher { NSRecursiveLock *_observersLock; } -@synthesize bridge = _bridge; @synthesize dispatchToJSThread = _dispatchToJSThread; @synthesize callableJSModules = _callableJSModules; @@ -175,13 +174,7 @@ - (void)sendEvent:(id)event [_eventQueueLock unlock]; if (scheduleEventsDispatch) { - if (_bridge != nullptr) { - [_bridge - dispatchBlock:^{ - [self flushEventsQueue]; - } - queue:RCTJSThread]; - } else if (_dispatchToJSThread != nullptr) { + if (_dispatchToJSThread != nullptr) { _dispatchToJSThread(^{ [self flushEventsQueue]; }); diff --git a/packages/react-native/React/Views/RCTViewManager.m b/packages/react-native/React/Views/RCTViewManager.m index fa1e0bcc95b9..2cb5281e0ee8 100644 --- a/packages/react-native/React/Views/RCTViewManager.m +++ b/packages/react-native/React/Views/RCTViewManager.m @@ -322,7 +322,6 @@ - (void)updateAccessibilityTraitsForRole:(RCTView *)view withDefaultView:(RCTVie RCT_CUSTOM_VIEW_PROPERTY(nativeID, NSString *, RCTView) { view.nativeID = json ? [RCTConvert NSString:json] : defaultView.nativeID; - [_bridge.uiManager setNativeID:view.nativeID forView:view]; } RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTPointerEvents, RCTView) diff --git a/packages/rn-tester/RCTTest/RCTTestModule.mm b/packages/rn-tester/RCTTest/RCTTestModule.mm index fb5e4a0cc148..4276d33dd77f 100644 --- a/packages/rn-tester/RCTTest/RCTTestModule.mm +++ b/packages/rn-tester/RCTTest/RCTTestModule.mm @@ -90,26 +90,16 @@ @implementation RCTTestModule { NSMutableDictionary *_snapshotCounter; } -@synthesize bridge = _bridge; @synthesize moduleRegistry = _moduleRegistry; +@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED; RCT_EXPORT_MODULE() -- (dispatch_queue_t)methodQueue -{ - return _bridge.uiManager.methodQueue; -} - -- (void)setMethodQueue:(dispatch_queue_t)methodQueue -{ - // noop -} - - (void)verifySnapshot:(RCTResponseSenderBlock)callback { RCTAssert(_controller != nil, @"No snapshot controller configured."); - [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + [_viewRegistry_DEPRECATED addUIBlock:^(__unused RCTViewRegistry *viewRegistry) { NSString *testName = NSStringFromSelector(self->_testSelector); if (!self->_snapshotCounter) { self->_snapshotCounter = [NSMutableDictionary new]; @@ -163,10 +153,9 @@ - (void)markTestCompleted - (void)markTestPassed:(BOOL)success { - [_bridge.uiManager - addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary *viewRegistry) { - self->_status = success ? RCTTestStatusPassed : RCTTestStatusFailed; - }]; + [_viewRegistry_DEPRECATED addUIBlock:^(__unused RCTViewRegistry *viewRegistry) { + self->_status = success ? RCTTestStatusPassed : RCTTestStatusFailed; + }]; } - (std::shared_ptr)getTurboModule: From fe32131770eaa1ea0a065f0e27b68d4f055455ce Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:00:40 -0700 Subject: [PATCH 04/11] Add launchOptions and performanceLogger module injection Summary: Extend RCTBridgeModule with optional launchOptions and performanceLogger properties, injected through RCTBridgeModuleDecorator from RCTInstance. This lets TurboModules read launch configuration and perf events without touching the deprecated bridge property. Changelog: [iOS][Added] - Add injectable launchOptions and performanceLogger module APIs Differential Revision: D126567157 --- .../react-native/React/Base/RCTBridgeModule.h | 20 ++++++++++++++ .../React/Base/RCTBridgeModuleDecorator.h | 7 ++++- .../React/Base/RCTBridgeModuleDecorator.m | 26 +++++++++++++++++++ .../platform/ios/ReactCommon/RCTInstance.mm | 4 ++- .../api-snapshots/ReactAppleDebugCxx.api | 6 ++++- .../api-snapshots/ReactAppleFrameworksCxx.api | 6 ++++- .../api-snapshots/ReactAppleNewarchCxx.api | 6 ++++- .../api-snapshots/ReactAppleReleaseCxx.api | 6 ++++- 8 files changed, 75 insertions(+), 6 deletions(-) diff --git a/packages/react-native/React/Base/RCTBridgeModule.h b/packages/react-native/React/Base/RCTBridgeModule.h index 14c479b25bd0..9fc86cdeed25 100644 --- a/packages/react-native/React/Base/RCTBridgeModule.h +++ b/packages/react-native/React/Base/RCTBridgeModule.h @@ -22,6 +22,7 @@ @class RCTModuleRegistry; @class RCTViewRegistry; @class RCTCallableJSModules; +@class RCTPerformanceLogger; /** * The type of a block that is capable of sending a response to a bridged @@ -168,6 +169,25 @@ RCT_EXTERN_C_END */ @property (nonatomic, weak, readwrite) RCTCallableJSModules *callableJSModules; +/** + * The launch options that were used to initialize the React instance. + * Useful for modules that need to read launch-time configuration. + * + * To implement this in your module, just add `@synthesize launchOptions = + * _launchOptions;`. If using Swift, add `@objc var launchOptions: + * NSDictionary!` to your module. + */ +@property (nonatomic, copy, readwrite) NSDictionary *launchOptions; + +/** + * Link to the Performance Logger that logs React Native perf events. + * + * To implement this in your module, just add `@synthesize performanceLogger = + * _performanceLogger;`. If using Swift, add `@objc var performanceLogger: + * RCTPerformanceLogger!` to your module. + */ +@property (nonatomic, strong, readwrite) RCTPerformanceLogger *performanceLogger; + /** * A reference to the RCTBridge. Useful for modules that require access * to bridge features, such as sending events or making JS calls. This diff --git a/packages/react-native/React/Base/RCTBridgeModuleDecorator.h b/packages/react-native/React/Base/RCTBridgeModuleDecorator.h index e7860967d1a7..c641caacbabf 100644 --- a/packages/react-native/React/Base/RCTBridgeModuleDecorator.h +++ b/packages/react-native/React/Base/RCTBridgeModuleDecorator.h @@ -10,6 +10,7 @@ @class RCTBundleManager; @class RCTCallableJSModules; @class RCTModuleRegistry; +@class RCTPerformanceLogger; @class RCTViewRegistry; /** @@ -24,11 +25,15 @@ @property (nonatomic, strong, readonly) RCTModuleRegistry *moduleRegistry; @property (nonatomic, strong, readonly) RCTBundleManager *bundleManager; @property (nonatomic, strong, readonly) RCTCallableJSModules *callableJSModules; +@property (nonatomic, copy, readonly) NSDictionary *launchOptions; +@property (nonatomic, strong, readonly) RCTPerformanceLogger *performanceLogger; - (instancetype)initWithViewRegistry:(RCTViewRegistry *)viewRegistry moduleRegistry:(RCTModuleRegistry *)moduleRegistry bundleManager:(RCTBundleManager *)bundleManager - callableJSModules:(RCTCallableJSModules *)callableJSModules; + callableJSModules:(RCTCallableJSModules *)callableJSModules + launchOptions:(NSDictionary *)launchOptions + performanceLogger:(RCTPerformanceLogger *)performanceLogger; - (void)attachInteropAPIsToModule:(id)bridgeModule; diff --git a/packages/react-native/React/Base/RCTBridgeModuleDecorator.m b/packages/react-native/React/Base/RCTBridgeModuleDecorator.m index 7f8e15417bc2..c278b28911c5 100644 --- a/packages/react-native/React/Base/RCTBridgeModuleDecorator.m +++ b/packages/react-native/React/Base/RCTBridgeModuleDecorator.m @@ -13,12 +13,16 @@ - (instancetype)initWithViewRegistry:(RCTViewRegistry *)viewRegistry moduleRegistry:(RCTModuleRegistry *)moduleRegistry bundleManager:(RCTBundleManager *)bundleManager callableJSModules:(RCTCallableJSModules *)callableJSModules + launchOptions:(NSDictionary *)launchOptions + performanceLogger:(RCTPerformanceLogger *)performanceLogger { if (self = [super init]) { _viewRegistry_DEPRECATED = viewRegistry; _moduleRegistry = moduleRegistry; _bundleManager = bundleManager; _callableJSModules = callableJSModules; + _launchOptions = [launchOptions copy]; + _performanceLogger = performanceLogger; } return self; } @@ -68,6 +72,28 @@ - (void)attachInteropAPIsToModule:(id)bridgeModule if ([bridgeModule respondsToSelector:@selector(setModuleRegistry:)]) { bridgeModule.moduleRegistry = _moduleRegistry; } + + /** + * Attach the launch options to this TurboModule, which allows this TurboModule + * to read the launch-time configuration of the React instance. + * + * Usage: In the TurboModule @implementation, include: + * `@synthesize launchOptions = _launchOptions` + */ + if ([bridgeModule respondsToSelector:@selector(setLaunchOptions:)]) { + bridgeModule.launchOptions = _launchOptions; + } + + /** + * Attach the RCTPerformanceLogger to this TurboModule, which allows this + * TurboModule to read React Native perf events. + * + * Usage: In the TurboModule @implementation, include: + * `@synthesize performanceLogger = _performanceLogger` + */ + if ([bridgeModule respondsToSelector:@selector(setPerformanceLogger:)]) { + bridgeModule.performanceLogger = _performanceLogger; + } } @end diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index 5efe16f73de6..40480593c587 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -129,7 +129,9 @@ - (instancetype)initWithDelegate:(id)delegate _bridgeModuleDecorator = [[RCTBridgeModuleDecorator alloc] initWithViewRegistry:[RCTViewRegistry new] moduleRegistry:moduleRegistry bundleManager:bundleManager - callableJSModules:[RCTCallableJSModules new]]; + callableJSModules:[RCTCallableJSModules new] + launchOptions:launchOptions + performanceLogger:_performanceLogger]; _devMenuConfigurationDecorator = #if RCT_DEV_MENU [[RCTDevMenuConfigurationDecorator alloc] initWithDevMenuConfiguration:devMenuConfiguration]; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index cd7cd6ba81f9..0669fff91c01 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -703,10 +703,12 @@ interface RCTBridge : public NSObject { } interface RCTBridgeModuleDecorator : public NSObject { + public @property (copy, readonly) NSDictionary* launchOptions; public @property (strong, readonly) RCTBundleManager* bundleManager; public @property (strong, readonly) RCTCallableJSModules* callableJSModules; public @property (strong, readonly) RCTModuleRegistry* moduleRegistry; - public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules); + public @property (strong, readonly) RCTPerformanceLogger* performanceLogger; + public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:launchOptions:performanceLogger:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules, NSDictionary* launchOptions, RCTPerformanceLogger* performanceLogger); public virtual void attachInteropAPIsToModule:(id bridgeModule); } @@ -2555,6 +2557,8 @@ protocol RCTBridgeMethod : public NSObject { } protocol RCTBridgeModule : public NSObject { + public @property (copy) NSDictionary* launchOptions; + public @property (strong) RCTPerformanceLogger* performanceLogger; public @property (strong, readonly) dispatch_queue_t methodQueue; public @property (weak) RCTBundleManager* bundleManager; public @property (weak) RCTCallableJSModules* callableJSModules; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api index a21ebf068233..1a5b4a36f5f7 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api @@ -712,10 +712,12 @@ interface RCTBridge : public NSObject { } interface RCTBridgeModuleDecorator : public NSObject { + public @property (copy, readonly) NSDictionary* launchOptions; public @property (strong, readonly) RCTBundleManager* bundleManager; public @property (strong, readonly) RCTCallableJSModules* callableJSModules; public @property (strong, readonly) RCTModuleRegistry* moduleRegistry; - public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules); + public @property (strong, readonly) RCTPerformanceLogger* performanceLogger; + public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:launchOptions:performanceLogger:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules, NSDictionary* launchOptions, RCTPerformanceLogger* performanceLogger); public virtual void attachInteropAPIsToModule:(id bridgeModule); } @@ -2613,6 +2615,8 @@ protocol RCTBridgeMethod : public NSObject { } protocol RCTBridgeModule : public NSObject { + public @property (copy) NSDictionary* launchOptions; + public @property (strong) RCTPerformanceLogger* performanceLogger; public @property (strong, readonly) dispatch_queue_t methodQueue; public @property (weak) RCTBundleManager* bundleManager; public @property (weak) RCTCallableJSModules* callableJSModules; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index aab9559c8f36..ceff567ed3c1 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -703,10 +703,12 @@ interface RCTBridge : public NSObject { } interface RCTBridgeModuleDecorator : public NSObject { + public @property (copy, readonly) NSDictionary* launchOptions; public @property (strong, readonly) RCTBundleManager* bundleManager; public @property (strong, readonly) RCTCallableJSModules* callableJSModules; public @property (strong, readonly) RCTModuleRegistry* moduleRegistry; - public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules); + public @property (strong, readonly) RCTPerformanceLogger* performanceLogger; + public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:launchOptions:performanceLogger:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules, NSDictionary* launchOptions, RCTPerformanceLogger* performanceLogger); public virtual void attachInteropAPIsToModule:(id bridgeModule); } @@ -2547,6 +2549,8 @@ protocol RCTBridgeMethod : public NSObject { } protocol RCTBridgeModule : public NSObject { + public @property (copy) NSDictionary* launchOptions; + public @property (strong) RCTPerformanceLogger* performanceLogger; public @property (strong, readonly) dispatch_queue_t methodQueue; public @property (weak) RCTBundleManager* bundleManager; public @property (weak) RCTCallableJSModules* callableJSModules; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 47e70d959eb1..97204b78b340 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -703,10 +703,12 @@ interface RCTBridge : public NSObject { } interface RCTBridgeModuleDecorator : public NSObject { + public @property (copy, readonly) NSDictionary* launchOptions; public @property (strong, readonly) RCTBundleManager* bundleManager; public @property (strong, readonly) RCTCallableJSModules* callableJSModules; public @property (strong, readonly) RCTModuleRegistry* moduleRegistry; - public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules); + public @property (strong, readonly) RCTPerformanceLogger* performanceLogger; + public virtual instancetype initWithViewRegistry:moduleRegistry:bundleManager:callableJSModules:launchOptions:performanceLogger:(RCTViewRegistry* viewRegistry, RCTModuleRegistry* moduleRegistry, RCTBundleManager* bundleManager, RCTCallableJSModules* callableJSModules, NSDictionary* launchOptions, RCTPerformanceLogger* performanceLogger); public virtual void attachInteropAPIsToModule:(id bridgeModule); } @@ -2555,6 +2557,8 @@ protocol RCTBridgeMethod : public NSObject { } protocol RCTBridgeModule : public NSObject { + public @property (copy) NSDictionary* launchOptions; + public @property (strong) RCTPerformanceLogger* performanceLogger; public @property (strong, readonly) dispatch_queue_t methodQueue; public @property (weak) RCTBundleManager* bundleManager; public @property (weak) RCTCallableJSModules* callableJSModules; From b1e801a577c56ee4175ebf787d9bc1bfdd4389a3 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:00:40 -0700 Subject: [PATCH 05/11] Read launchOptions from injection in RCTLinkingManager Summary: Synthesize the injected launchOptions property and read getInitialURL state from it instead of self.bridge. Drops the last bridge read in this module along with its direct bridge header import. Changelog: [Internal] Differential Revision: D126567470 --- .../Libraries/LinkingIOS/RCTLinkingManager.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm b/packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm index f25ad54a5f4a..76d6f526d9fa 100644 --- a/packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm +++ b/packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm @@ -8,7 +8,6 @@ #import #import -#import #import #import #import @@ -36,6 +35,8 @@ @implementation RCTLinkingManager RCT_EXPORT_MODULE() +@synthesize launchOptions = _launchOptions; + + (void)postNotificationWithURL:(NSURL *)URL { NSDictionary *payload = @{@"url" : URL.absoluteString}; @@ -207,11 +208,10 @@ - (void)canOpenURL:(NSString *)urlString - (void)getInitialURL:(RCTPromiseResolveBlock)resolve reject:(__unused RCTPromiseRejectBlock)reject { NSURL *initialURL = nil; - if (self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey] != nullptr) { - initialURL = self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey]; + if (self.launchOptions[UIApplicationLaunchOptionsURLKey] != nullptr) { + initialURL = self.launchOptions[UIApplicationLaunchOptionsURLKey]; } else { - NSDictionary *userActivityDictionary = - self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]; + NSDictionary *userActivityDictionary = self.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]; if ([userActivityDictionary[UIApplicationLaunchOptionsUserActivityTypeKey] isEqual:NSUserActivityTypeBrowsingWeb]) { initialURL = ((NSUserActivity *)userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]).webpageURL; } From 0e553af76d86bb666e508e82808652abd14da341 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:00:40 -0700 Subject: [PATCH 06/11] Drop RCTBridge from RCTPerfMonitor Summary: Route JS-thread dispatch through the injected dispatchToJSThread block and read the injected performanceLogger. Delete the Views counter, which can only show zero since RCTViewRegistry exposes no enumeration, and reflow the HUD bar. Changelog: [iOS][Removed] - Remove the non-functional Views counter from the PerfMonitor HUD Differential Revision: D126567926 --- .../React/CoreModules/RCTPerfMonitor.mm | 66 +++++++------------ 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/packages/react-native/React/CoreModules/RCTPerfMonitor.mm b/packages/react-native/React/CoreModules/RCTPerfMonitor.mm index c33af88055a0..2bb27c1eaebf 100644 --- a/packages/react-native/React/CoreModules/RCTPerfMonitor.mm +++ b/packages/react-native/React/CoreModules/RCTPerfMonitor.mm @@ -17,8 +17,8 @@ #import -#import -#import +#import +#import #import #import #import @@ -58,8 +58,13 @@ static vm_size_t RCTGetResidentMemorySize(void) return memoryUsageInByte; } -@interface RCTPerfMonitor - : NSObject +@interface RCTPerfMonitor : NSObject < + RCTBridgeModule, + RCTTurboModule, + RCTInvalidating, + RCTJSDispatcherModule, + UITableViewDataSource, + UITableViewDelegate> #if __has_include() @property (nonatomic, strong, readonly) RCTDevMenuItem *devMenuItem; @@ -68,7 +73,6 @@ @interface RCTPerfMonitor @property (nonatomic, strong, readonly) UIView *container; @property (nonatomic, strong, readonly) UILabel *memory; @property (nonatomic, strong, readonly) UILabel *heap; -@property (nonatomic, strong, readonly) UILabel *views; @property (nonatomic, strong, readonly) UITableView *metrics; @property (nonatomic, strong, readonly) RCTFPSGraph *jsGraph; @property (nonatomic, strong, readonly) RCTFPSGraph *uiGraph; @@ -85,7 +89,6 @@ @implementation RCTPerfMonitor { UIView *_container; UILabel *_memory; UILabel *_heap; - UILabel *_views; UILabel *_uiGraphLabel; UILabel *_jsGraphLabel; UITableView *_metrics; @@ -109,8 +112,9 @@ @implementation RCTPerfMonitor { NSArray *_perfLoggerMarks; } -@synthesize bridge = _bridge; +@synthesize dispatchToJSThread = _dispatchToJSThread; @synthesize moduleRegistry = _moduleRegistry; +@synthesize performanceLogger = _performanceLogger; RCT_EXPORT_MODULE() @@ -172,7 +176,7 @@ - (UIView *)container UIEdgeInsets safeInsets = RCTKeyWindow().safeAreaInsets; _container = - [[UIView alloc] initWithFrame:CGRectMake(safeInsets.left, safeInsets.top, 180, RCTPerfMonitorBarHeight)]; + [[UIView alloc] initWithFrame:CGRectMake(safeInsets.left, safeInsets.top, 136, RCTPerfMonitorBarHeight)]; _container.layer.borderWidth = 2; _container.layer.borderColor = [UIColor lightGrayColor].CGColor; [_container addGestureRecognizer:self.gestureRecognizer]; @@ -212,22 +216,10 @@ - (UILabel *)heap return _heap; } -- (UILabel *)views -{ - if (_views == nullptr) { - _views = [[UILabel alloc] initWithFrame:CGRectMake(88, 0, 44, RCTPerfMonitorBarHeight)]; - _views.font = [UIFont systemFontOfSize:12]; - _views.numberOfLines = 3; - _views.textAlignment = NSTextAlignmentCenter; - } - - return _views; -} - - (RCTFPSGraph *)uiGraph { if (_uiGraph == nullptr) { - _uiGraph = [[RCTFPSGraph alloc] initWithFrame:CGRectMake(134, 14, 40, 30) color:[UIColor lightGrayColor]]; + _uiGraph = [[RCTFPSGraph alloc] initWithFrame:CGRectMake(90, 14, 40, 30) color:[UIColor lightGrayColor]]; } return _uiGraph; } @@ -235,7 +227,7 @@ - (RCTFPSGraph *)uiGraph - (RCTFPSGraph *)jsGraph { if (_jsGraph == nullptr) { - _jsGraph = [[RCTFPSGraph alloc] initWithFrame:CGRectMake(178, 14, 40, 30) color:[UIColor lightGrayColor]]; + _jsGraph = [[RCTFPSGraph alloc] initWithFrame:CGRectMake(134, 14, 40, 30) color:[UIColor lightGrayColor]]; } return _jsGraph; } @@ -243,7 +235,7 @@ - (RCTFPSGraph *)jsGraph - (UILabel *)uiGraphLabel { if (_uiGraphLabel == nullptr) { - _uiGraphLabel = [[UILabel alloc] initWithFrame:CGRectMake(134, 3, 40, 10)]; + _uiGraphLabel = [[UILabel alloc] initWithFrame:CGRectMake(90, 3, 40, 10)]; _uiGraphLabel.font = [UIFont systemFontOfSize:11]; _uiGraphLabel.textAlignment = NSTextAlignmentCenter; _uiGraphLabel.text = @"UI"; @@ -255,7 +247,7 @@ - (UILabel *)uiGraphLabel - (UILabel *)jsGraphLabel { if (_jsGraphLabel == nullptr) { - _jsGraphLabel = [[UILabel alloc] initWithFrame:CGRectMake(178, 3, 38, 10)]; + _jsGraphLabel = [[UILabel alloc] initWithFrame:CGRectMake(134, 3, 38, 10)]; _jsGraphLabel.font = [UIFont systemFontOfSize:11]; _jsGraphLabel.textAlignment = NSTextAlignmentCenter; _jsGraphLabel.text = @"JS"; @@ -289,7 +281,6 @@ - (void)show [self.container addSubview:self.memory]; [self.container addSubview:self.heap]; - [self.container addSubview:self.views]; [self.container addSubview:self.uiGraph]; [self.container addSubview:self.uiGraphLabel]; @@ -309,12 +300,12 @@ - (void)show [self.container addSubview:self.jsGraph]; [self.container addSubview:self.jsGraphLabel]; - [_bridge - dispatchBlock:^{ - self->_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(threadUpdate:)]; - [self->_jsDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - } - queue:RCTJSThread]; + if (_dispatchToJSThread != nullptr) { + _dispatchToJSThread(^{ + self->_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(threadUpdate:)]; + [self->_jsDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + }); + } } - (void)hide @@ -415,15 +406,6 @@ - (void)parse:(NSString *)log - (void)updateStats { - NSDictionary *views = [_bridge.uiManager valueForKey:@"viewRegistry"]; - NSUInteger viewCount = views.count; - NSUInteger visibleViewCount = 0; - for (UIView *view in views.allValues) { - if ((view.window != nullptr) || (view.superview.window != nullptr)) { - visibleViewCount++; - } - } - // Ensure the container always stays on top of newly added views if ([_container.superview.subviews lastObject] != _container) { [_container.superview bringSubviewToFront:_container]; @@ -432,8 +414,6 @@ - (void)updateStats double mem = (double)RCTGetResidentMemorySize() / 1024 / 1024; self.memory.text = [NSString stringWithFormat:@"RAM\n%.2lf\nMB", mem]; self.heap.text = [NSString stringWithFormat:@"JSC\n%.2lf\nMB", (double)_heapSize / 1024]; - self.views.text = - [NSString stringWithFormat:@"Views\n%lu\n%lu", (unsigned long)visibleViewCount, (unsigned long)viewCount]; __weak __typeof__(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ @@ -481,7 +461,7 @@ - (void)loadPerformanceLoggerData { NSUInteger i = 0; NSMutableArray *data = [NSMutableArray new]; - RCTPerformanceLogger *performanceLogger = [_bridge performanceLogger]; + RCTPerformanceLogger *performanceLogger = _performanceLogger; NSArray *values = [performanceLogger valuesForTags]; for (NSString *label in LabelsForRCTPerformanceLoggerTags()) { long long value = values[i + 1].longLongValue - values[i].longLongValue; From 480102aa7a3aa5a4d55e45726d7e2b6e61e55f39 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:13:10 -0700 Subject: [PATCH 07/11] Delete dead RCTBridge category implementations Summary: RCTBridge is never instantiated, so its nine per-module category implementations never execute. Delete them and keep the proxy implementations plus all interface declarations, which callers still compile against. Changelog: [Internal] Differential Revision: D126574379 --- .../Libraries/Image/RCTImageLoader.mm | 16 ---------------- .../Libraries/Image/RCTImageStoreManager.mm | 9 --------- .../Libraries/Network/RCTNetworking.mm | 9 --------- .../react-native/React/Base/RCTEventDispatcher.m | 9 --------- .../React/CoreModules/RCTAccessibilityManager.mm | 9 --------- .../react-native/React/CoreModules/RCTDevMenu.mm | 13 ------------- .../React/CoreModules/RCTDevSettings.mm | 15 --------------- .../React/CoreModules/RCTWebSocketModule.mm | 9 --------- .../React/Modules/RCTSurfacePresenterStub.m | 14 -------------- 9 files changed, 103 deletions(-) diff --git a/packages/react-native/Libraries/Image/RCTImageLoader.mm b/packages/react-native/Libraries/Image/RCTImageLoader.mm index 9dab28583942..75362da2dd43 100644 --- a/packages/react-native/Libraries/Image/RCTImageLoader.mm +++ b/packages/react-native/Libraries/Image/RCTImageLoader.mm @@ -1323,22 +1323,6 @@ - (void)queryCache:(NSArray *)uris resolve:(RCTPromiseResolveBlock)resolve rejec } @end -/** - * DEPRECATED!! DO NOT USE - * Instead use `[_bridge moduleForClass:[RCTImageLoader class]]` - */ -@implementation RCTBridge (RCTImageLoader) - -- (RCTImageLoader *)imageLoader -{ - RCTLogWarn( - @"Calling bridge.imageLoader is deprecated and will not work in newer versions of RN. Please update to the " - "moduleForClass API or turboModuleRegistry API."); - return [self moduleForClass:[RCTImageLoader class]]; -} - -@end - @implementation RCTBridgeProxy (RCTImageLoader) - (RCTImageLoader *)imageLoader diff --git a/packages/react-native/Libraries/Image/RCTImageStoreManager.mm b/packages/react-native/Libraries/Image/RCTImageStoreManager.mm index 393034c53d03..76b0ab7ece1f 100644 --- a/packages/react-native/Libraries/Image/RCTImageStoreManager.mm +++ b/packages/react-native/Libraries/Image/RCTImageStoreManager.mm @@ -248,15 +248,6 @@ - (void)getImageForTag:(NSString *)imageTag withBlock:(void (^)(UIImage *image)) @end -@implementation RCTBridge (RCTImageStoreManager) - -- (RCTImageStoreManager *)imageStoreManager -{ - return [self moduleForClass:[RCTImageStoreManager class]]; -} - -@end - @implementation RCTBridgeProxy (RCTImageStoreManager) - (RCTImageStoreManager *)imageStoreManager diff --git a/packages/react-native/Libraries/Network/RCTNetworking.mm b/packages/react-native/Libraries/Network/RCTNetworking.mm index 95e531d4e49a..d9c78b10e685 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.mm +++ b/packages/react-native/Libraries/Network/RCTNetworking.mm @@ -856,15 +856,6 @@ - (void)clearCookies:(RCTResponseSenderBlock)responseSender @end -@implementation RCTBridge (RCTNetworking) - -- (RCTNetworking *)networking -{ - return [self moduleForClass:[RCTNetworking class]]; -} - -@end - @implementation RCTBridgeProxy (RCTNetworking) - (RCTNetworking *)networking diff --git a/packages/react-native/React/Base/RCTEventDispatcher.m b/packages/react-native/React/Base/RCTEventDispatcher.m index d779006e7e90..0c3c8806b6e4 100644 --- a/packages/react-native/React/Base/RCTEventDispatcher.m +++ b/packages/react-native/React/Base/RCTEventDispatcher.m @@ -20,15 +20,6 @@ return eventName; } -@implementation RCTBridge (RCTEventDispatcher) - -- (id)eventDispatcher -{ - return [self moduleForName:@"EventDispatcher" lazilyLoadIfNecessary:YES]; -} - -@end - @implementation RCTBridgeProxy (RCTEventDispatcher) - (id)eventDispatcher diff --git a/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm b/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm index 04726aa4de77..602fc46071ca 100644 --- a/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm +++ b/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm @@ -487,15 +487,6 @@ void RCTAccessibilityManagerSetIsVoiceOverEnabled( @end -@implementation RCTBridge (RCTAccessibilityManager) - -- (RCTAccessibilityManager *)accessibilityManager -{ - return [self moduleForClass:[RCTAccessibilityManager class]]; -} - -@end - @implementation RCTBridgeProxy (RCTAccessibilityManager) - (RCTAccessibilityManager *)accessibilityManager diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index bd946190df6b..695c42e2e0ca 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -616,19 +616,6 @@ + (instancetype)buttonItemWithTitleBlock:(NSString * (^)(void))titleBlock handle #endif -@implementation RCTBridge (RCTDevMenu) - -- (RCTDevMenu *)devMenu -{ -#if RCT_DEV_MENU - return [self moduleForClass:[RCTDevMenu class]]; -#else - return nil; -#endif -} - -@end - @implementation RCTBridgeProxy (RCTDevMenu) - (RCTDevMenu *)devMenu diff --git a/packages/react-native/React/CoreModules/RCTDevSettings.mm b/packages/react-native/React/CoreModules/RCTDevSettings.mm index a204f5620669..13bcd3a3e9dd 100644 --- a/packages/react-native/React/CoreModules/RCTDevSettings.mm +++ b/packages/react-native/React/CoreModules/RCTDevSettings.mm @@ -626,21 +626,6 @@ - (void)addHandler:(id)handler forPackagerMethod:(NSStr #endif // #if RCT_DEV_MENU -@implementation RCTBridge (RCTDevSettings) - -- (RCTDevSettings *)devSettings -{ -#if RCT_REMOTE_PROFILE - return [self moduleForClass:[RCTDevSettings class]]; -#elif RCT_DEV_MENU - return devSettingsMenuEnabled ? [self moduleForClass:[RCTDevSettings class]] : nil; -#else - return nil; -#endif -} - -@end - @implementation RCTBridgeProxy (RCTDevSettings) - (RCTDevSettings *)devSettings diff --git a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm index c588c616d1b7..44f62bd3adcd 100644 --- a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm +++ b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm @@ -288,15 +288,6 @@ - (void)webSocket:(SRWebSocket *)webSocket @end -@implementation RCTBridge (RCTWebSocketModule) - -- (RCTWebSocketModule *)webSocketModule -{ - return [self moduleForClass:[RCTWebSocketModule class]]; -} - -@end - @implementation RCTBridgeProxy (RCTWebSocketModule) - (RCTWebSocketModule *)webSocketModule diff --git a/packages/react-native/React/Modules/RCTSurfacePresenterStub.m b/packages/react-native/React/Modules/RCTSurfacePresenterStub.m index 07524d583ea4..a03450b9a877 100644 --- a/packages/react-native/React/Modules/RCTSurfacePresenterStub.m +++ b/packages/react-native/React/Modules/RCTSurfacePresenterStub.m @@ -7,20 +7,6 @@ #import "RCTSurfacePresenterStub.h" -@implementation RCTBridge (RCTSurfacePresenterStub) - -- (id)surfacePresenter -{ - return objc_getAssociatedObject(self, @selector(surfacePresenter)); -} - -- (void)setSurfacePresenter:(id)surfacePresenter -{ - objc_setAssociatedObject(self, @selector(surfacePresenter), surfacePresenter, OBJC_ASSOCIATION_RETAIN); -} - -@end - @implementation RCTBridgeProxy (RCTSurfacePresenterStub) - (id)surfacePresenter From 81fe0dc39248babff09daf8cf151194db3377897 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:33:51 -0700 Subject: [PATCH 08/11] Remove bridge-mode branches from RCTDevSettings Summary: Delete the always-false _isBridgeMode helper and fold its call sites to the bridgeless paths. Remove the no-op profiling bridge calls with their synchronize cascade, and simplify setExecutorClass to persist locally plus reload. Changelog: [Internal] Differential Revision: D126574662 --- .../React/CoreModules/RCTDevSettings.mm | 92 ++----------------- 1 file changed, 9 insertions(+), 83 deletions(-) diff --git a/packages/react-native/React/CoreModules/RCTDevSettings.mm b/packages/react-native/React/CoreModules/RCTDevSettings.mm index 13bcd3a3e9dd..89a7b0c793e6 100644 --- a/packages/react-native/React/CoreModules/RCTDevSettings.mm +++ b/packages/react-native/React/CoreModules/RCTDevSettings.mm @@ -17,7 +17,6 @@ #import #import #import -#import #import #import #import @@ -165,11 +164,6 @@ + (BOOL)requiresMainQueueSetup return NO; } -- (BOOL)_isBridgeMode -{ - return [self.bridge isKindOfClass:[RCTBridge class]]; -} - - (instancetype)initWithDataSource:(id)dataSource { if (self = [super init]) { @@ -221,36 +215,9 @@ - (void)initialize #endif #if RCT_ENABLE_INSPECTOR - if ([self _isBridgeMode]) { - // We need this dispatch to the main thread because the bridge is not yet - // finished with its initialisation. By the time it relinquishes control of - // the main thread, this operation can be performed. - __weak __typeof(self) weakSelf = self; - dispatch_async(dispatch_get_main_queue(), ^{ - __typeof(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } - id dispatchBlock = ^{ - __typeof(self) strongSelf2 = weakSelf; - if (!strongSelf2) { - return; - } - NSURL *url = strongSelf2.bundleManager.bundleURL; - [RCTInspectorDevServerHelper connectWithBundleURL:url]; - }; - [strongSelf.bridge dispatchBlock:dispatchBlock queue:RCTJSThread]; - }); - } else { - NSURL *url = self.bundleManager.bundleURL; - [RCTInspectorDevServerHelper connectWithBundleURL:url]; - } + NSURL *url = self.bundleManager.bundleURL; + [RCTInspectorDevServerHelper connectWithBundleURL:url]; #endif - - __weak __typeof(self) weakSelf = self; - dispatch_async(dispatch_get_main_queue(), ^{ - [weakSelf _synchronizeAllSettings]; - }); } - (dispatch_queue_t)methodQueue @@ -295,11 +262,7 @@ - (void)setIsShakeGestureEnabled:(BOOL)isShakeGestureEnabled - (BOOL)isDeviceDebuggingAvailable { #if RCT_ENABLE_INSPECTOR - if ([self _isBridgeMode]) { - return self.bridge.isInspectable; - } else { - return self.isInspectable; - } + return self.isInspectable; #else return false; #endif // RCT_ENABLE_INSPECTOR @@ -341,7 +304,6 @@ - (BOOL)isShakeToShowDevMenuEnabled - (void)setProfilingEnabled:(BOOL)enabled { [self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingProfilingEnabled]; - [self _profilingSettingDidChange]; } - (BOOL)isProfilingEnabled @@ -349,25 +311,6 @@ - (BOOL)isProfilingEnabled return [[self settingForKey:kRCTDevSettingProfilingEnabled] boolValue]; } -- (void)_profilingSettingDidChange -{ - BOOL enabled = self.isProfilingEnabled; - if (self.isHotLoadingAvailable && enabled != RCTProfileIsProfiling()) { - if (enabled) { - [self.bridge startProfiling]; - } else { - __weak __typeof(self) weakSelf = self; - [self.bridge stopProfiling:^(NSData *logData) { - __typeof(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } - RCTProfileSendResult(strongSelf.bridge, @"systrace", logData); - }]; - } - } -} - - (void)setHotLoadingEnabled:(BOOL)enabled { if (self.isHotLoadingEnabled != enabled) { @@ -430,17 +373,12 @@ - (BOOL)isPerfMonitorShown - (void)setExecutorClass:(Class)executorClass { - _executorClass = executorClass; - if (self.bridge.executorClass != executorClass) { - // TODO (6929129): we can remove this special case test once we have better - // support for custom executors in the dev menu. But right now this is - // needed to prevent overriding a custom executor with the default if a - // custom executor has been set directly on the bridge - if (executorClass == Nil) { - return; - } - - self.bridge.executorClass = executorClass; + if (executorClass == Nil) { + _executorClass = Nil; + return; + } + if (_executorClass != executorClass) { + _executorClass = executorClass; RCTTriggerReloadCommandListeners(@"Custom executor class reset"); } } @@ -505,15 +443,6 @@ - (void)openDebugger #pragma mark - Internal -/** - * Query the data source for all possible settings and make sure we're doing the right - * thing for the state of each setting. - */ -- (void)_synchronizeAllSettings -{ - [self _profilingSettingDidChange]; -} - - (void)jsLoaded:(NSNotification *)notification { // In bridge mode, the bridge that sent the notif must be the same as the one stored in this module. @@ -530,9 +459,6 @@ - (void)jsLoaded:(NSNotification *)notification if (!strongSelf) { return; } - // update state again after the bridge has finished loading - [strongSelf _synchronizeAllSettings]; - // Inspector can only be shown after JS has loaded if ([strongSelf isElementInspectorShown]) { #pragma clang diagnostic push From 559bc5dc897a9770818d31520bd375054e3fd154 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:33:51 -0700 Subject: [PATCH 09/11] Remove bridge mode from RCTComponentData Summary: RCTComponentData always runs bridgeless, so delete the always-false isBridgeMode helper, merge the manager properties into one strong reference, and use the injected event dispatcher directly. Changelog: [Internal] Differential Revision: D126575276 --- .../react-native/React/Views/RCTComponentData.h | 8 +++----- .../React/Views/RCTComponentData.mm | 17 +++-------------- .../api-snapshots/ReactAppleDebugCxx.api | 3 +-- .../api-snapshots/ReactAppleFrameworksCxx.api | 3 +-- .../api-snapshots/ReactAppleNewarchCxx.api | 3 +-- .../api-snapshots/ReactAppleReleaseCxx.api | 3 +-- 6 files changed, 10 insertions(+), 27 deletions(-) diff --git a/packages/react-native/React/Views/RCTComponentData.h b/packages/react-native/React/Views/RCTComponentData.h index 1dd119778350..9c8d5e1c4c10 100644 --- a/packages/react-native/React/Views/RCTComponentData.h +++ b/packages/react-native/React/Views/RCTComponentData.h @@ -22,13 +22,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) Class managerClass; @property (nonatomic, copy, readonly) NSString *name; -@property (nonatomic, weak, readonly) RCTViewManager *manager; /* - * When running React Native with the bridge, view managers are retained by the - * bridge. When running in bridgeless mode, allocate and retain view managers - * in this class. + * The view manager for this component. In bridgeless mode, view managers + * are allocated and retained by this class. */ -@property (nonatomic, strong, readonly) RCTViewManager *bridgelessViewManager; +@property (nonatomic, strong, readonly) RCTViewManager *manager; - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge diff --git a/packages/react-native/React/Views/RCTComponentData.mm b/packages/react-native/React/Views/RCTComponentData.mm index 6004e4e7c646..c857b4021478 100644 --- a/packages/react-native/React/Views/RCTComponentData.mm +++ b/packages/react-native/React/Views/RCTComponentData.mm @@ -44,7 +44,6 @@ @implementation RCTComponentData { } @synthesize manager = _manager; -@synthesize bridgelessViewManager = _bridgelessViewManager; - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge @@ -62,21 +61,12 @@ - (instancetype)initWithManagerClass:(Class)managerClass return self; } -- (BOOL)isBridgeMode -{ - // If we are in bridge mode, the bridge is RCTBridge - // If we are bridgeless, the bridge is RCTBridgeProxy - return [_bridge isKindOfClass:[RCTBridge class]]; -} - - (RCTViewManager *)manager { - if ((_manager == nullptr) && [self isBridgeMode]) { + if (_manager == nullptr) { _manager = [_bridge moduleForClass:_managerClass]; - } else if ((_manager == nullptr) && (_bridgelessViewManager == nullptr)) { - _bridgelessViewManager = [_bridge moduleForClass:_managerClass]; } - return (_manager != nullptr) ? _manager : _bridgelessViewManager; + return _manager; } RCT_NOT_IMPLEMENTED(-(instancetype)init) @@ -272,8 +262,7 @@ - (RCTPropBlock)createPropBlock:(NSString *)name isShadowView:(BOOL)isShadowView type == NSSelectorFromString(@"RCTDirectEventBlock:") || type == NSSelectorFromString(@"RCTCapturingEventBlock:")) { // Special case for event handlers - setterBlock = createEventSetter( - name, setter, self.eventInterceptor, [self isBridgeMode] ? _bridge.eventDispatcher : _eventDispatcher); + setterBlock = createEventSetter(name, setter, self.eventInterceptor, _eventDispatcher); } else { // Ordinary property handlers NSMethodSignature *typeSignature = [[RCTConvert class] methodSignatureForSelector:type]; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 0669fff91c01..cb7d563100f5 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -805,8 +805,7 @@ interface RCTComponentData : public NSObject { public @property (assign, readonly) Class managerClass; public @property (copy) void(^eventInterceptor)(NSString* eventName, NSDictionary* event, NSNumber* reactTag); public @property (copy, readonly) NSString* name; - public @property (strong, readonly) RCTViewManager* bridgelessViewManager; - public @property (weak, readonly) RCTViewManager* manager; + public @property (strong, readonly) RCTViewManager* manager; public virtual NSDictionary* viewConfig(); public virtual RCTShadowView* createShadowViewWithTag:(NSNumber* tag); public virtual UIView* createViewWithTag:rootTag:(_Nullable NSNumber* tag, _Nullable NSNumber* rootTag); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api index 1a5b4a36f5f7..dea9919075b2 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api @@ -814,8 +814,7 @@ interface RCTComponentData : public NSObject { public @property (assign, readonly) Class managerClass; public @property (copy) void(^eventInterceptor)(NSString* eventName, NSDictionary* event, NSNumber* reactTag); public @property (copy, readonly) NSString* name; - public @property (strong, readonly) RCTViewManager* bridgelessViewManager; - public @property (weak, readonly) RCTViewManager* manager; + public @property (strong, readonly) RCTViewManager* manager; public virtual NSDictionary* viewConfig(); public virtual RCTShadowView* createShadowViewWithTag:(NSNumber* tag); public virtual UIView* createViewWithTag:rootTag:(_Nullable NSNumber* tag, _Nullable NSNumber* rootTag); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index ceff567ed3c1..0bf2f8d72a21 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -805,8 +805,7 @@ interface RCTComponentData : public NSObject { public @property (assign, readonly) Class managerClass; public @property (copy) void(^eventInterceptor)(NSString* eventName, NSDictionary* event, NSNumber* reactTag); public @property (copy, readonly) NSString* name; - public @property (strong, readonly) RCTViewManager* bridgelessViewManager; - public @property (weak, readonly) RCTViewManager* manager; + public @property (strong, readonly) RCTViewManager* manager; public virtual NSDictionary* viewConfig(); public virtual RCTShadowView* createShadowViewWithTag:(NSNumber* tag); public virtual UIView* createViewWithTag:rootTag:(_Nullable NSNumber* tag, _Nullable NSNumber* rootTag); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 97204b78b340..2d56020237d1 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -805,8 +805,7 @@ interface RCTComponentData : public NSObject { public @property (assign, readonly) Class managerClass; public @property (copy) void(^eventInterceptor)(NSString* eventName, NSDictionary* event, NSNumber* reactTag); public @property (copy, readonly) NSString* name; - public @property (strong, readonly) RCTViewManager* bridgelessViewManager; - public @property (weak, readonly) RCTViewManager* manager; + public @property (strong, readonly) RCTViewManager* manager; public virtual NSDictionary* viewConfig(); public virtual RCTShadowView* createShadowViewWithTag:(NSNumber* tag); public virtual UIView* createViewWithTag:rootTag:(_Nullable NSNumber* tag, _Nullable NSNumber* rootTag); From 3c8a48e9bc8de5562a4153ff89c3d9047e6832dc Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:33:51 -0700 Subject: [PATCH 10/11] Remove bridge mode from view manager interop Summary: The interop layer only ever receives a bridge proxy, so delete the unused bridge ivar, init parameter, and bridge-only command paths. Keep the bridgeless flows and the proxy injection that legacy managers rely on. Changelog: [Internal] Differential Revision: D126575534 --- ...cyViewManagerInteropComponentDescriptor.mm | 24 ++------ .../RCTLegacyViewManagerInteropCoordinator.h | 1 - .../RCTLegacyViewManagerInteropCoordinator.mm | 56 ++----------------- 3 files changed, 12 insertions(+), 69 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.mm b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.mm index 0d58bd5d2eea..6d5c8ec8410f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.mm +++ b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.mm @@ -75,7 +75,7 @@ static Class getViewManagerFromComponentName(const std::string &componentName) return nil; } -static Class getViewManagerClass(const std::string &componentName, RCTBridge *bridge, RCTBridgeProxy *bridgeProxy) +static Class getViewManagerClass(const std::string &componentName, RCTBridgeProxy *bridgeProxy) { Class viewManager = getViewManagerFromComponentName(componentName); if (viewManager != nil) { @@ -90,11 +90,7 @@ static Class getViewManagerClass(const std::string &componentName, RCTBridge *br } } } else { - // If all the heuristics fail, let's try to retrieve the view manager from the bridge/bridgeProxy - if (bridge != nil) { - return [[bridge moduleForName:RCTNSStringFromString(componentName)] class]; - } - + // If all the heuristics fail, let's try to retrieve the view manager from the bridge proxy if (bridgeProxy != nil) { return [[bridgeProxy moduleForName:RCTNSStringFromString(componentName) lazilyLoadIfNecessary:YES] class]; } @@ -107,12 +103,6 @@ static Class getViewManagerClass(const std::string &componentName, RCTBridge *br const std::shared_ptr &contextContainer, const ComponentDescriptor::Flavor &flavor) { - auto optionalBridge = contextContainer->find>("Bridge"); - RCTBridge *bridge; - if (optionalBridge) { - bridge = unwrapManagedObjectWeakly(optionalBridge.value()); - } - RCTBridgeProxy *bridgeProxy; auto optionalBridgeProxy = contextContainer->find>("RCTBridgeProxy"); if (optionalBridgeProxy) { @@ -120,7 +110,7 @@ static Class getViewManagerClass(const std::string &componentName, RCTBridge *br } auto componentName = *std::static_pointer_cast(flavor); - Class viewManagerClass = getViewManagerClass(componentName, bridge, bridgeProxy); + Class viewManagerClass = getViewManagerClass(componentName, bridgeProxy); assert(viewManagerClass); auto optionalEventDispatcher = contextContainer->find>("RCTEventDispatcher"); @@ -135,13 +125,11 @@ static Class getViewManagerClass(const std::string &componentName, RCTBridge *br bridgeModuleDecorator = unwrapManagedObject(optionalModuleDecorator.value()); } - RCTComponentData *componentData = - [[RCTComponentData alloc] initWithManagerClass:viewManagerClass - bridge:bridge != nil ? bridge : (RCTBridge *)bridgeProxy - eventDispatcher:eventDispatcher]; + RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:viewManagerClass + bridge:(RCTBridge *)bridgeProxy + eventDispatcher:eventDispatcher]; return wrapManagedObject([[RCTLegacyViewManagerInteropCoordinator alloc] initWithComponentData:componentData - bridge:bridge bridgeProxy:bridgeProxy bridgelessInteropData:bridgeModuleDecorator]); } diff --git a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h index 86eceb49a5f3..435671c52494 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h +++ b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h @@ -25,7 +25,6 @@ typedef void (^InterceptorBlock)(std::string eventName, folly::dynamic &&event); @interface RCTLegacyViewManagerInteropCoordinator : NSObject - (instancetype)initWithComponentData:(RCTComponentData *)componentData - bridge:(nullable RCTBridge *)bridge bridgeProxy:(nullable RCTBridgeProxy *)bridgeProxy bridgelessInteropData:(RCTBridgeModuleDecorator *)bridgelessInteropData; diff --git a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm index 1057a57a5073..b57f8a4ba48e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm +++ b/packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm @@ -28,7 +28,6 @@ @implementation RCTLegacyViewManagerInteropCoordinator { RCTComponentData *_componentData; - __weak RCTBridge *_bridge; __weak RCTBridgeModuleDecorator *_bridgelessInteropData; __weak RCTBridgeProxy *_bridgeProxy; @@ -47,23 +46,14 @@ @implementation RCTLegacyViewManagerInteropCoordinator { } - (instancetype)initWithComponentData:(RCTComponentData *)componentData - bridge:(nullable RCTBridge *)bridge bridgeProxy:(nullable RCTBridgeProxy *)bridgeProxy bridgelessInteropData:(RCTBridgeModuleDecorator *)bridgelessInteropData { if (self = [super init]) { _componentData = componentData; - _bridge = bridge; _bridgelessInteropData = bridgelessInteropData; _bridgeProxy = bridgeProxy; - if (bridgelessInteropData) { - // During bridge mode, RCTBridgeModules will be decorated with these APIs by the bridge. - RCTAssert( - _bridge == nil, - @"RCTLegacyViewManagerInteropCoordinator should not be initialized with RCTBridgeModuleDecorator in bridge mode."); - } - _eventInterceptors = [NSMutableDictionary new]; __weak __typeof(self) weakSelf = self; @@ -119,7 +109,6 @@ - (void)handleCommand:(NSString *)commandName { Class managerClass = _componentData.managerClass; [self _lookupModuleMethodsIfNecessary]; - RCTModuleData *moduleData = [_bridge.batchedBridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)]; id method; // We can't use `[NSString intValue]` as "0" is a valid command, @@ -129,9 +118,9 @@ - (void)handleCommand:(NSString *)commandName NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; if ([commandName isKindOfClass:[NSNumber class]] || [formatter numberFromString:commandName] != NULL) { - method = moduleData ? moduleData.methods[[commandName intValue]] : _moduleMethods[[commandName intValue]]; + method = _moduleMethods[[commandName intValue]]; } else if ([commandName isKindOfClass:[NSString class]]) { - method = moduleData ? moduleData.methodsByName[commandName] : _moduleMethodsByName[commandName]; + method = _moduleMethodsByName[commandName]; if (method == nil) { RCTLogError(@"No command found with name \"%@\"", commandName); } @@ -142,26 +131,6 @@ - (void)handleCommand:(NSString *)commandName NSArray *newArgs = [@[ [NSNumber numberWithInteger:tag] ] arrayByAddingObjectsFromArray:args]; - if (_bridge) { - [self _handleCommandsOnBridge:method withArgs:newArgs]; - } else { - [self _handleCommandsOnBridgeless:method withArgs:newArgs]; - } -} - -#pragma mark - Private -- (void)_handleCommandsOnBridge:(id)method withArgs:(NSArray *)newArgs -{ - [_bridge.batchedBridge - dispatchBlock:^{ - [method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs]; - [self->_bridge.uiManager setNeedsLayout]; - } - queue:RCTGetUIManagerQueue()]; -} - -- (void)_handleCommandsOnBridgeless:(id)method withArgs:(NSArray *)newArgs -{ RCTViewManager *componentViewManager = self->_componentData.manager; [componentViewManager setValue:_bridgeProxy forKey:@"bridge"]; @@ -171,30 +140,17 @@ - (void)_handleCommandsOnBridgeless:(id)method withArgs:(NSArra }]; } -- (void)_addUIBlock:(RCTViewManagerUIBlock)block -{ - if (_bridge) { - [self _addUIBlockOnBridge:block]; - } else { - [self->_bridgeProxy.uiManager addUIBlock:block]; - } -} +#pragma mark - Private -- (void)_addUIBlockOnBridge:(RCTViewManagerUIBlock)block +- (void)_addUIBlock:(RCTViewManagerUIBlock)block { - __weak __typeof__(self) weakSelf = self; - [_bridge.batchedBridge - dispatchBlock:^{ - __typeof__(self) strongSelf = weakSelf; - [strongSelf->_bridge.uiManager addUIBlock:block]; - } - queue:RCTGetUIManagerQueue()]; + [self->_bridgeProxy.uiManager addUIBlock:block]; } // This is copy-pasta from RCTModuleData. - (void)_lookupModuleMethodsIfNecessary { - if (!_bridge && !_moduleMethods) { + if (!_moduleMethods) { _moduleMethods = [NSMutableArray new]; _moduleMethodsByName = [NSMutableDictionary new]; From dbd5dacb74b8d942f044113702a8d807b946a197 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 20 Oct 2026 21:35:59 -0700 Subject: [PATCH 11/11] Remove write-only bridge from sample legacy modules (#59261) Summary: Pull Request resolved: https://github.com/react/react-native/pull/59261 RCTSampleLegacyModule on iOS and macOS stored a bridge that nothing reads. Delete the ivar and setter from both sample files. Changelog: [Internal] Differential Revision: D126575656 --- .../platform/ios/ReactCommon/RCTSampleLegacyModule.mm | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleLegacyModule.mm b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleLegacyModule.mm index f6788d1db746..c283f6d7f6a5 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleLegacyModule.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleLegacyModule.mm @@ -7,9 +7,7 @@ #import "RCTSampleLegacyModule.h" -@implementation RCTSampleLegacyModule { - RCTBridge *_bridge; -} +@implementation RCTSampleLegacyModule // Backward-compatible export RCT_EXPORT_MODULE() @@ -20,11 +18,6 @@ + (BOOL)requiresMainQueueSetup return YES; } -- (void)setBridge:(RCTBridge *)bridge -{ - _bridge = bridge; -} - - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue();