From 51fe999f093100d3ed8270f2e1d6888e04c4e00a Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 22 Oct 2026 12:36:53 -0700 Subject: [PATCH 1/5] Read launchOptions from injection in RCTLinkingManager (#59259) 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] Reviewed By: shwanton 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 7d0b976a4db8c282bc0391e9232c0fc3ae5a60f1 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 22 Oct 2026 12:36:53 -0700 Subject: [PATCH 2/5] Drop RCTBridge from RCTPerfMonitor (#59258) 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 Reviewed By: shwanton 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 6fc784c7c7ea61b5bd5302ff68d7ef867a051459 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 22 Oct 2026 12:36:53 -0700 Subject: [PATCH 3/5] Remove bridge-mode branches from RCTDevSettings (#59260) 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] Reviewed By: shwanton 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 a204f5620669..abe2897dec27 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 11345d5b81c6a6052d464a7e49c6d2b2f843071a Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 22 Oct 2026 12:36:53 -0700 Subject: [PATCH 4/5] Remove bridge mode from RCTComponentData (#59264) 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] Reviewed By: shwanton 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..e5c22a19c474 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, nullable) 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 ee23d0f2486d..863038207ad0 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 ee06e6c718ee..dece37c06a37 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 d0c4951f53b5..3e9a7b4744fc 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 c4461a00ca94..a692b6489f17 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 a86b4e6bc6fcacb3c1ce5bd3eb6ce70a245537ff Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 22 Oct 2026 12:36:53 -0700 Subject: [PATCH 5/5] Remove bridge mode from view manager interop (#59262) 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] Reviewed By: shwanton Differential Revision: D126575534 --- ...cyViewManagerInteropComponentDescriptor.mm | 24 ++------ .../RCTLegacyViewManagerInteropCoordinator.h | 1 - .../RCTLegacyViewManagerInteropCoordinator.mm | 57 ++----------------- 3 files changed, 12 insertions(+), 70 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..1bfe6677c629 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; @@ -117,9 +107,7 @@ - (void)handleCommand:(NSString *)commandName reactTag:(NSInteger)tag paperView:(nonnull UIView *)paperView { - 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 +117,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 +130,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 +139,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];