mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Make the Fabric Interop layer work in Bridgeless (#40732)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c40fc313ca
commit
9c5ceeaf99
@@ -351,6 +351,11 @@ using namespace facebook;
|
||||
return (RCTUIManager *)_uiManagerProxy;
|
||||
}
|
||||
|
||||
- (RCTBridgeProxy *)object
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* NSProxy setup
|
||||
*/
|
||||
@@ -387,12 +392,14 @@ using namespace facebook;
|
||||
|
||||
@implementation RCTUIManagerProxy {
|
||||
RCTViewRegistry *_viewRegistry;
|
||||
NSMutableDictionary<NSNumber *, UIView *> *_legacyViewRegistry;
|
||||
}
|
||||
- (instancetype)initWithViewRegistry:(RCTViewRegistry *)viewRegistry
|
||||
{
|
||||
self = [super self];
|
||||
if (self) {
|
||||
_viewRegistry = viewRegistry;
|
||||
_legacyViewRegistry = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -404,20 +411,21 @@ using namespace facebook;
|
||||
{
|
||||
[self logWarning:@"Please migrate to RCTViewRegistry: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
|
||||
cmd:_cmd];
|
||||
return [_viewRegistry viewForReactTag:reactTag];
|
||||
return [_viewRegistry viewForReactTag:reactTag] ? [_viewRegistry viewForReactTag:reactTag]
|
||||
: [_legacyViewRegistry objectForKey:reactTag];
|
||||
}
|
||||
|
||||
- (void)addUIBlock:(RCTViewManagerUIBlock)block
|
||||
{
|
||||
[self
|
||||
logWarning:
|
||||
@"This method isn't implemented faithfully: the viewRegistry passed to RCTViewManagerUIBlock is nil. Please migrate to RCTViewRegistry: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
|
||||
@"This method isn't implemented faithfully. Please migrate to RCTViewRegistry if possible: @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED."
|
||||
cmd:_cmd];
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
RCTExecuteOnMainQueue(^{
|
||||
__typeof(self) strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
block((RCTUIManager *)strongSelf, nil);
|
||||
block((RCTUIManager *)strongSelf, strongSelf->_legacyViewRegistry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTBridgeProxy.h>
|
||||
#import <React/RCTInvalidating.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTViewManager.h>
|
||||
@@ -173,6 +174,12 @@ RCT_EXTERN NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplier
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBridgeProxy (RCTUIManager)
|
||||
|
||||
@property (nonatomic, readonly) RCTUIManager *uiManager;
|
||||
|
||||
@end
|
||||
|
||||
RCT_EXTERN NSMutableDictionary<NSString *, id> *RCTModuleConstantsForDestructuredComponent(
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,
|
||||
|
||||
@@ -71,7 +71,7 @@ static SEL selectorForType(NSString *type)
|
||||
object:nil
|
||||
userInfo:@{@"module" : _bridgelessViewManager}];
|
||||
}
|
||||
return _manager ?: _bridgelessViewManager;
|
||||
return _manager ? _manager : _bridgelessViewManager;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||
|
||||
+8
@@ -8,6 +8,7 @@
|
||||
#include "LegacyViewManagerInteropComponentDescriptor.h"
|
||||
#include <React/RCTBridge.h>
|
||||
#include <React/RCTBridgeModuleDecorator.h>
|
||||
#include <React/RCTBridgeProxy.h>
|
||||
#include <React/RCTComponentData.h>
|
||||
#include <React/RCTEventDispatcher.h>
|
||||
#include <React/RCTModuleData.h>
|
||||
@@ -86,6 +87,12 @@ static const std::shared_ptr<void> constructCoordinator(
|
||||
bridge = unwrapManagedObjectWeakly(optionalBridge.value());
|
||||
}
|
||||
|
||||
RCTBridgeProxy *bridgeProxy;
|
||||
auto optionalBridgeProxy = contextContainer->find<std::shared_ptr<void>>("RCTBridgeProxy");
|
||||
if (optionalBridgeProxy) {
|
||||
bridgeProxy = unwrapManagedObjectWeakly(optionalBridgeProxy.value());
|
||||
}
|
||||
|
||||
auto optionalEventDispatcher = contextContainer->find<std::shared_ptr<void>>("RCTEventDispatcher");
|
||||
RCTEventDispatcher *eventDispatcher;
|
||||
if (optionalEventDispatcher) {
|
||||
@@ -104,6 +111,7 @@ static const std::shared_ptr<void> constructCoordinator(
|
||||
return wrapManagedObject([[RCTLegacyViewManagerInteropCoordinator alloc]
|
||||
initWithComponentData:componentData
|
||||
bridge:bridge
|
||||
bridgeProxy:bridgeProxy
|
||||
bridgelessInteropData:bridgeModuleDecorator]);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -14,13 +14,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RCTComponentData;
|
||||
@class RCTBridge;
|
||||
@class RCTBridgeProxy;
|
||||
|
||||
typedef void (^InterceptorBlock)(std::string eventName, folly::dynamic event);
|
||||
|
||||
@interface RCTLegacyViewManagerInteropCoordinator : NSObject
|
||||
|
||||
- (instancetype)initWithComponentData:(RCTComponentData *)componentData
|
||||
bridge:(RCTBridge *)bridge
|
||||
bridge:(nullable RCTBridge *)bridge
|
||||
bridgeProxy:(nullable RCTBridgeProxy *)bridgeProxy
|
||||
bridgelessInteropData:(RCTBridgeModuleDecorator *)bridgelessInteropData;
|
||||
|
||||
- (UIView *)createPaperViewWithTag:(NSInteger)tag;
|
||||
|
||||
+42
-10
@@ -8,6 +8,7 @@
|
||||
#include "RCTLegacyViewManagerInteropCoordinator.h"
|
||||
#include <React/RCTBridge+Private.h>
|
||||
#include <React/RCTBridgeMethod.h>
|
||||
#include <React/RCTBridgeProxy.h>
|
||||
#include <React/RCTComponentData.h>
|
||||
#include <React/RCTEventDispatcherProtocol.h>
|
||||
#include <React/RCTFollyConvert.h>
|
||||
@@ -16,6 +17,7 @@
|
||||
#include <React/RCTUIManager.h>
|
||||
#include <React/RCTUIManagerUtils.h>
|
||||
#include <React/RCTUtils.h>
|
||||
#include <React/RCTViewManager.h>
|
||||
#include <folly/json.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
@@ -25,6 +27,8 @@ using namespace facebook::react;
|
||||
RCTComponentData *_componentData;
|
||||
__weak RCTBridge *_bridge;
|
||||
__weak RCTBridgeModuleDecorator *_bridgelessInteropData;
|
||||
__weak RCTBridgeProxy *_bridgeProxy;
|
||||
|
||||
/*
|
||||
Each instance of `RCTLegacyViewManagerInteropComponentView` registers a block to which events are dispatched.
|
||||
This is the container that maps unretained UIView pointer to a block to which the event is dispatched.
|
||||
@@ -40,13 +44,16 @@ using namespace facebook::react;
|
||||
}
|
||||
|
||||
- (instancetype)initWithComponentData:(RCTComponentData *)componentData
|
||||
bridge:(RCTBridge *)bridge
|
||||
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(
|
||||
@@ -62,7 +69,9 @@ using namespace facebook::react;
|
||||
if (strongSelf) {
|
||||
InterceptorBlock block = [strongSelf->_eventInterceptors objectForKey:reactTag];
|
||||
if (block) {
|
||||
block(std::string([RCTNormalizeInputEventName(eventName) UTF8String]), convertIdToFollyDynamic(event ?: @{}));
|
||||
block(
|
||||
std::string([RCTNormalizeInputEventName(eventName) UTF8String]),
|
||||
convertIdToFollyDynamic(event ? event : @{}));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -131,15 +140,9 @@ using namespace facebook::react;
|
||||
NSArray *newArgs = [@[ [NSNumber numberWithInteger:tag] ] arrayByAddingObjectsFromArray:args];
|
||||
|
||||
if (_bridge) {
|
||||
[_bridge.batchedBridge
|
||||
dispatchBlock:^{
|
||||
[method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs];
|
||||
[self->_bridge.uiManager setNeedsLayout];
|
||||
}
|
||||
queue:RCTGetUIManagerQueue()];
|
||||
[self _handleCommandsOnBridge:method withArgs:newArgs];
|
||||
} else {
|
||||
// TODO T86826778 - Figure out which queue this should be dispatched to.
|
||||
[method invokeWithBridge:nil module:self->_componentData.manager arguments:newArgs];
|
||||
[self _handleCommandsOnBridgeless:method withArgs:newArgs];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +172,37 @@ using namespace facebook::react;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
- (void)_handleCommandsOnBridge:(id<RCTBridgeMethod>)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<RCTBridgeMethod>)method withArgs:(NSArray *)newArgs
|
||||
{
|
||||
RCTViewManager *componentViewManager = self->_componentData.manager;
|
||||
[componentViewManager setValue:_bridgeProxy forKey:@"bridge"];
|
||||
|
||||
[self->_bridgeProxy.uiManager
|
||||
addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
[method invokeWithBridge:nil module:componentViewManager arguments:newArgs];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_addUIBlock:(RCTViewManagerUIBlock)block
|
||||
{
|
||||
if (_bridge) {
|
||||
[self _addUIBlockOnBridge:block];
|
||||
} else {
|
||||
[self->_bridgeProxy.uiManager addUIBlock:block];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_addUIBlockOnBridge:(RCTViewManagerUIBlock)block
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[_bridge.batchedBridge
|
||||
|
||||
+17
-17
@@ -227,24 +227,23 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags)
|
||||
RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor();
|
||||
timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);
|
||||
|
||||
RCTBridgeProxy *bridgeProxy = RCTTurboModuleInteropEnabled() && RCTTurboModuleInteropBridgeProxyEnabled()
|
||||
? [[RCTBridgeProxy alloc] initWithViewRegistry:_bridgeModuleDecorator.viewRegistry_DEPRECATED
|
||||
moduleRegistry:_bridgeModuleDecorator.moduleRegistry
|
||||
bundleManager:_bridgeModuleDecorator.bundleManager
|
||||
callableJSModules:_bridgeModuleDecorator.callableJSModules
|
||||
dispatchToJSThread:^(dispatch_block_t block) {
|
||||
__strong __typeof(self) strongSelf = weakSelf;
|
||||
if (strongSelf && strongSelf->_valid) {
|
||||
strongSelf->_reactInstance->getBufferedRuntimeExecutor()([=](jsi::Runtime &runtime) { block(); });
|
||||
}
|
||||
RCTBridgeProxy *bridgeProxy =
|
||||
[[RCTBridgeProxy alloc] initWithViewRegistry:_bridgeModuleDecorator.viewRegistry_DEPRECATED
|
||||
moduleRegistry:_bridgeModuleDecorator.moduleRegistry
|
||||
bundleManager:_bridgeModuleDecorator.bundleManager
|
||||
callableJSModules:_bridgeModuleDecorator.callableJSModules
|
||||
dispatchToJSThread:^(dispatch_block_t block) {
|
||||
__strong __typeof(self) strongSelf = weakSelf;
|
||||
if (strongSelf && strongSelf->_valid) {
|
||||
strongSelf->_reactInstance->getBufferedRuntimeExecutor()([=](jsi::Runtime &runtime) { block(); });
|
||||
}
|
||||
registerSegmentWithId:^(NSNumber *segmentId, NSString *path) {
|
||||
__strong __typeof(self) strongSelf = weakSelf;
|
||||
if (strongSelf && strongSelf->_valid) {
|
||||
[strongSelf registerSegmentWithId:segmentId path:path];
|
||||
}
|
||||
}]
|
||||
: nil;
|
||||
}
|
||||
registerSegmentWithId:^(NSNumber *segmentId, NSString *path) {
|
||||
__strong __typeof(self) strongSelf = weakSelf;
|
||||
if (strongSelf && strongSelf->_valid) {
|
||||
[strongSelf registerSegmentWithId:segmentId path:path];
|
||||
}
|
||||
}];
|
||||
|
||||
// Set up TurboModules
|
||||
_turboModuleManager = [[RCTTurboModuleManager alloc]
|
||||
@@ -269,6 +268,7 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags)
|
||||
facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTEventDispatcher"]));
|
||||
contextContainer->insert("RCTBridgeModuleDecorator", facebook::react::wrapManagedObject(_bridgeModuleDecorator));
|
||||
contextContainer->insert("RuntimeScheduler", std::weak_ptr<RuntimeScheduler>(_reactInstance->getRuntimeScheduler()));
|
||||
contextContainer->insert("RCTBridgeProxy", facebook::react::wrapManagedObject(bridgeProxy));
|
||||
|
||||
_surfacePresenter = [[RCTSurfacePresenter alloc]
|
||||
initWithContextContainer:contextContainer
|
||||
|
||||
Reference in New Issue
Block a user