Skip to content

Commit 9c5ceea

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Make the Fabric Interop layer work in Bridgeless (#40732)
Summary: Pull Request resolved: #40732 This change allows the Fabric Interop Layer to work in bridgeless mode. Given that the legacy components requires a Bridge to send events and use commands, this change simulates a bridge when it doesn't exists (i.e.: we are in bridgeless mode). In order to make it work, we had to simulate a few elements from the Bridge and the UIManager. ## Changelog: [iOS][Fixed] - Make the Fabric interop layer works in bridgeless mode. ## Facebook: As an alternative approach, we could have created a `protocol RCTBridging`, have the `RCTBridge` conform to that protocol, and create a new type for it. Practically this would have been much more cumbersome: 1. The [RCTBridge](https://www.internalfb.com/code/fbsource/[916531b9bf7a9943036807f7563c925b4c3e0101]/xplat/js/react-native-github/packages/react-native/React/Base/RCTBridge.h?lines=87-238) interface is quite big. All the props and method should be part of the protocol. 2. Extensions declared on RCTBridge would not have worked. For example, [`RCTBridge (RCTUIManager)`](https://www.internalfb.com/code/fbsource/[916531b9bf7a9943036807f7563c925b4c3e0101]/xplat/js/react-native-github/packages/react-native/React/Modules/RCTUIManager.h?lines=170-174). 3. It would require a major overhaul of the APIs, returning `id<RCTBridging>` in place of **every** function that takes/return an instance of `RCTBridge *`. Clearly, not a feasible way to go. Reviewed By: RSNara Differential Revision: D50079929 fbshipit-source-id: 77d4370e9043c8e06b676bff3987511c042b0f9c
1 parent c40fc31 commit 9c5ceea

File tree

7 files changed

+89
-32
lines changed

7 files changed

+89
-32
lines changed

packages/react-native/React/Base/RCTBridgeProxy.mm

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ - (RCTUIManager *)uiManager
351351
return (RCTUIManager *)_uiManagerProxy;
352352
}
353353

354+
- (RCTBridgeProxy *)object
355+
{
356+
return self;
357+
}
358+
354359
/**
355360
* NSProxy setup
356361
*/
@@ -387,12 +392,14 @@ - (void)logError:(NSString *)message cmd:(SEL)cmd
387392

388393
@implementation RCTUIManagerProxy {
389394
RCTViewRegistry *_viewRegistry;
395+
NSMutableDictionary<NSNumber *, UIView *> *_legacyViewRegistry;
390396
}
391397
- (instancetype)initWithViewRegistry:(RCTViewRegistry *)viewRegistry
392398
{
393399
self = [super self];
394400
if (self) {
395401
_viewRegistry = viewRegistry;
402+
_legacyViewRegistry = [NSMutableDictionary new];
396403
}
397404
return self;
398405
}
@@ -404,20 +411,21 @@ - (UIView *)viewForReactTag:(NSNumber *)reactTag
404411
{
405412
[self logWarning:@"Please migrate to RCTViewRegistry: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
406413
cmd:_cmd];
407-
return [_viewRegistry viewForReactTag:reactTag];
414+
return [_viewRegistry viewForReactTag:reactTag] ? [_viewRegistry viewForReactTag:reactTag]
415+
: [_legacyViewRegistry objectForKey:reactTag];
408416
}
409417

410418
- (void)addUIBlock:(RCTViewManagerUIBlock)block
411419
{
412420
[self
413421
logWarning:
414-
@"This method isn't implemented faithfully: the viewRegistry passed to RCTViewManagerUIBlock is nil. Please migrate to RCTViewRegistry: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
422+
@"This method isn't implemented faithfully. Please migrate to RCTViewRegistry if possible: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
415423
cmd:_cmd];
416424
__weak __typeof(self) weakSelf = self;
417425
RCTExecuteOnMainQueue(^{
418426
__typeof(self) strongSelf = weakSelf;
419427
if (strongSelf) {
420-
block((RCTUIManager *)strongSelf, nil);
428+
block((RCTUIManager *)strongSelf, strongSelf->_legacyViewRegistry);
421429
}
422430
});
423431
}

packages/react-native/React/Modules/RCTUIManager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#import <React/RCTBridge.h>
1111
#import <React/RCTBridgeModule.h>
12+
#import <React/RCTBridgeProxy.h>
1213
#import <React/RCTInvalidating.h>
1314
#import <React/RCTRootView.h>
1415
#import <React/RCTViewManager.h>
@@ -173,6 +174,12 @@ RCT_EXTERN NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplier
173174

174175
@end
175176

177+
@interface RCTBridgeProxy (RCTUIManager)
178+
179+
@property (nonatomic, readonly) RCTUIManager *uiManager;
180+
181+
@end
182+
176183
RCT_EXTERN NSMutableDictionary<NSString *, id> *RCTModuleConstantsForDestructuredComponent(
177184
NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
178185
NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,

packages/react-native/React/Views/RCTComponentData.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ - (RCTViewManager *)manager
7171
object:nil
7272
userInfo:@{@"module" : _bridgelessViewManager}];
7373
}
74-
return _manager ?: _bridgelessViewManager;
74+
return _manager ? _manager : _bridgelessViewManager;
7575
}
7676

7777
RCT_NOT_IMPLEMENTED(-(instancetype)init)

packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.mm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "LegacyViewManagerInteropComponentDescriptor.h"
99
#include <React/RCTBridge.h>
1010
#include <React/RCTBridgeModuleDecorator.h>
11+
#include <React/RCTBridgeProxy.h>
1112
#include <React/RCTComponentData.h>
1213
#include <React/RCTEventDispatcher.h>
1314
#include <React/RCTModuleData.h>
@@ -86,6 +87,12 @@ static Class getViewManagerFromComponentName(const std::string &componentName)
8687
bridge = unwrapManagedObjectWeakly(optionalBridge.value());
8788
}
8889

90+
RCTBridgeProxy *bridgeProxy;
91+
auto optionalBridgeProxy = contextContainer->find<std::shared_ptr<void>>("RCTBridgeProxy");
92+
if (optionalBridgeProxy) {
93+
bridgeProxy = unwrapManagedObjectWeakly(optionalBridgeProxy.value());
94+
}
95+
8996
auto optionalEventDispatcher = contextContainer->find<std::shared_ptr<void>>("RCTEventDispatcher");
9097
RCTEventDispatcher *eventDispatcher;
9198
if (optionalEventDispatcher) {
@@ -104,6 +111,7 @@ static Class getViewManagerFromComponentName(const std::string &componentName)
104111
return wrapManagedObject([[RCTLegacyViewManagerInteropCoordinator alloc]
105112
initWithComponentData:componentData
106113
bridge:bridge
114+
bridgeProxy:bridgeProxy
107115
bridgelessInteropData:bridgeModuleDecorator]);
108116
}
109117

packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ NS_ASSUME_NONNULL_BEGIN
1414

1515
@class RCTComponentData;
1616
@class RCTBridge;
17+
@class RCTBridgeProxy;
1718

1819
typedef void (^InterceptorBlock)(std::string eventName, folly::dynamic event);
1920

2021
@interface RCTLegacyViewManagerInteropCoordinator : NSObject
2122

2223
- (instancetype)initWithComponentData:(RCTComponentData *)componentData
23-
bridge:(RCTBridge *)bridge
24+
bridge:(nullable RCTBridge *)bridge
25+
bridgeProxy:(nullable RCTBridgeProxy *)bridgeProxy
2426
bridgelessInteropData:(RCTBridgeModuleDecorator *)bridgelessInteropData;
2527

2628
- (UIView *)createPaperViewWithTag:(NSInteger)tag;

packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "RCTLegacyViewManagerInteropCoordinator.h"
99
#include <React/RCTBridge+Private.h>
1010
#include <React/RCTBridgeMethod.h>
11+
#include <React/RCTBridgeProxy.h>
1112
#include <React/RCTComponentData.h>
1213
#include <React/RCTEventDispatcherProtocol.h>
1314
#include <React/RCTFollyConvert.h>
@@ -16,6 +17,7 @@
1617
#include <React/RCTUIManager.h>
1718
#include <React/RCTUIManagerUtils.h>
1819
#include <React/RCTUtils.h>
20+
#include <React/RCTViewManager.h>
1921
#include <folly/json.h>
2022
#include <objc/runtime.h>
2123

@@ -25,6 +27,8 @@ @implementation RCTLegacyViewManagerInteropCoordinator {
2527
RCTComponentData *_componentData;
2628
__weak RCTBridge *_bridge;
2729
__weak RCTBridgeModuleDecorator *_bridgelessInteropData;
30+
__weak RCTBridgeProxy *_bridgeProxy;
31+
2832
/*
2933
Each instance of `RCTLegacyViewManagerInteropComponentView` registers a block to which events are dispatched.
3034
This is the container that maps unretained UIView pointer to a block to which the event is dispatched.
@@ -40,13 +44,16 @@ @implementation RCTLegacyViewManagerInteropCoordinator {
4044
}
4145

4246
- (instancetype)initWithComponentData:(RCTComponentData *)componentData
43-
bridge:(RCTBridge *)bridge
47+
bridge:(nullable RCTBridge *)bridge
48+
bridgeProxy:(nullable RCTBridgeProxy *)bridgeProxy
4449
bridgelessInteropData:(RCTBridgeModuleDecorator *)bridgelessInteropData;
4550
{
4651
if (self = [super init]) {
4752
_componentData = componentData;
4853
_bridge = bridge;
4954
_bridgelessInteropData = bridgelessInteropData;
55+
_bridgeProxy = bridgeProxy;
56+
5057
if (bridgelessInteropData) {
5158
// During bridge mode, RCTBridgeModules will be decorated with these APIs by the bridge.
5259
RCTAssert(
@@ -62,7 +69,9 @@ - (instancetype)initWithComponentData:(RCTComponentData *)componentData
6269
if (strongSelf) {
6370
InterceptorBlock block = [strongSelf->_eventInterceptors objectForKey:reactTag];
6471
if (block) {
65-
block(std::string([RCTNormalizeInputEventName(eventName) UTF8String]), convertIdToFollyDynamic(event ?: @{}));
72+
block(
73+
std::string([RCTNormalizeInputEventName(eventName) UTF8String]),
74+
convertIdToFollyDynamic(event ? event : @{}));
6675
}
6776
}
6877
};
@@ -131,15 +140,9 @@ - (void)handleCommand:(NSString *)commandName
131140
NSArray *newArgs = [@[ [NSNumber numberWithInteger:tag] ] arrayByAddingObjectsFromArray:args];
132141

133142
if (_bridge) {
134-
[_bridge.batchedBridge
135-
dispatchBlock:^{
136-
[method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs];
137-
[self->_bridge.uiManager setNeedsLayout];
138-
}
139-
queue:RCTGetUIManagerQueue()];
143+
[self _handleCommandsOnBridge:method withArgs:newArgs];
140144
} else {
141-
// TODO T86826778 - Figure out which queue this should be dispatched to.
142-
[method invokeWithBridge:nil module:self->_componentData.manager arguments:newArgs];
145+
[self _handleCommandsOnBridgeless:method withArgs:newArgs];
143146
}
144147
}
145148

@@ -169,8 +172,37 @@ - (void)removeViewFromRegistryWithTag:(NSInteger)tag
169172
}
170173

171174
#pragma mark - Private
175+
- (void)_handleCommandsOnBridge:(id<RCTBridgeMethod>)method withArgs:(NSArray *)newArgs
176+
{
177+
[_bridge.batchedBridge
178+
dispatchBlock:^{
179+
[method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs];
180+
[self->_bridge.uiManager setNeedsLayout];
181+
}
182+
queue:RCTGetUIManagerQueue()];
183+
}
184+
185+
- (void)_handleCommandsOnBridgeless:(id<RCTBridgeMethod>)method withArgs:(NSArray *)newArgs
186+
{
187+
RCTViewManager *componentViewManager = self->_componentData.manager;
188+
[componentViewManager setValue:_bridgeProxy forKey:@"bridge"];
189+
190+
[self->_bridgeProxy.uiManager
191+
addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
192+
[method invokeWithBridge:nil module:componentViewManager arguments:newArgs];
193+
}];
194+
}
172195

173196
- (void)_addUIBlock:(RCTViewManagerUIBlock)block
197+
{
198+
if (_bridge) {
199+
[self _addUIBlockOnBridge:block];
200+
} else {
201+
[self->_bridgeProxy.uiManager addUIBlock:block];
202+
}
203+
}
204+
205+
- (void)_addUIBlockOnBridge:(RCTViewManagerUIBlock)block
174206
{
175207
__weak __typeof__(self) weakSelf = self;
176208
[_bridge.batchedBridge

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -227,24 +227,23 @@ - (void)_start
227227
RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor();
228228
timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);
229229

230-
RCTBridgeProxy *bridgeProxy = RCTTurboModuleInteropEnabled() && RCTTurboModuleInteropBridgeProxyEnabled()
231-
? [[RCTBridgeProxy alloc] initWithViewRegistry:_bridgeModuleDecorator.viewRegistry_DEPRECATED
232-
moduleRegistry:_bridgeModuleDecorator.moduleRegistry
233-
bundleManager:_bridgeModuleDecorator.bundleManager
234-
callableJSModules:_bridgeModuleDecorator.callableJSModules
235-
dispatchToJSThread:^(dispatch_block_t block) {
236-
__strong __typeof(self) strongSelf = weakSelf;
237-
if (strongSelf && strongSelf->_valid) {
238-
strongSelf->_reactInstance->getBufferedRuntimeExecutor()([=](jsi::Runtime &runtime) { block(); });
239-
}
230+
RCTBridgeProxy *bridgeProxy =
231+
[[RCTBridgeProxy alloc] initWithViewRegistry:_bridgeModuleDecorator.viewRegistry_DEPRECATED
232+
moduleRegistry:_bridgeModuleDecorator.moduleRegistry
233+
bundleManager:_bridgeModuleDecorator.bundleManager
234+
callableJSModules:_bridgeModuleDecorator.callableJSModules
235+
dispatchToJSThread:^(dispatch_block_t block) {
236+
__strong __typeof(self) strongSelf = weakSelf;
237+
if (strongSelf && strongSelf->_valid) {
238+
strongSelf->_reactInstance->getBufferedRuntimeExecutor()([=](jsi::Runtime &runtime) { block(); });
240239
}
241-
registerSegmentWithId:^(NSNumber *segmentId, NSString *path) {
242-
__strong __typeof(self) strongSelf = weakSelf;
243-
if (strongSelf && strongSelf->_valid) {
244-
[strongSelf registerSegmentWithId:segmentId path:path];
245-
}
246-
}]
247-
: nil;
240+
}
241+
registerSegmentWithId:^(NSNumber *segmentId, NSString *path) {
242+
__strong __typeof(self) strongSelf = weakSelf;
243+
if (strongSelf && strongSelf->_valid) {
244+
[strongSelf registerSegmentWithId:segmentId path:path];
245+
}
246+
}];
248247

249248
// Set up TurboModules
250249
_turboModuleManager = [[RCTTurboModuleManager alloc]
@@ -269,6 +268,7 @@ - (void)_start
269268
facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTEventDispatcher"]));
270269
contextContainer->insert("RCTBridgeModuleDecorator", facebook::react::wrapManagedObject(_bridgeModuleDecorator));
271270
contextContainer->insert("RuntimeScheduler", std::weak_ptr<RuntimeScheduler>(_reactInstance->getRuntimeScheduler()));
271+
contextContainer->insert("RCTBridgeProxy", facebook::react::wrapManagedObject(bridgeProxy));
272272

273273
_surfacePresenter = [[RCTSurfacePresenter alloc]
274274
initWithContextContainer:contextContainer

0 commit comments

Comments
 (0)