From 37e5fa3a6ce2445b17d56dd6fd22fbda926537ef Mon Sep 17 00:00:00 2001 From: Paige Sun Date: Tue, 29 Mar 2022 18:40:19 -0700 Subject: [PATCH] Refactor: Migrate Logbox surface initialization to Fabric when available, in Bridge and Bridgeless modes Summary: Changelog: [iOS][Internal] Refactor: Migrate Logbox surface initialization to Fabric when available, in Bridge and Bridgeless modes # Why This diff main purpose is to add `RCTErrorNewArchitectureValidation(RCTNotAllowedInAppWideFabric)` in `RCTSurface`, to ensure Paper surfaces are never created in FBiOS. # The Situation Before this diff, in Bridged Fabric, `[RCTLogbox show]` initializes a Paper `RCTSurface`, [using `[RCTLogBoxView initWithWindow]`](https://github.com/facebook/react-native/blob/main/React/CoreModules/RCTLogBoxView.mm#L46)) In this diff, in Bridged and Bridgeless Fabric, `[RCTLogbox show]` initializes a Fabric `RCTFabricSurface`. Before this diff, in Bridgeless Fabric, RCTLogBox posts a "CreateLogBoxSurface" notification to RCTInstance. In this diff, the notification hack is replaced by the same `RCTFabricSurface` initialization above. Behavior is the same. Reviewed By: RSNara Differential Revision: D35177311 fbshipit-source-id: 6de418af8a01f914c9a806bb8d74915015f9087a --- React/Base/Surface/RCTSurface.mm | 1 + .../RCTSurfaceHostingView.mm | 1 - React/CoreModules/RCTLogBox.mm | 23 +++++++++++++------ React/CoreModules/RCTLogBoxView.h | 3 +++ React/CoreModules/RCTLogBoxView.mm | 18 +++++++++++++++ React/Fabric/RCTSurfacePresenter.h | 6 +++++ React/Fabric/RCTSurfacePresenter.mm | 8 +++++++ React/Modules/RCTSurfacePresenterStub.h | 4 ++++ 8 files changed, 56 insertions(+), 8 deletions(-) diff --git a/React/Base/Surface/RCTSurface.mm b/React/Base/Surface/RCTSurface.mm index 18798ec588f..be2baef1d5b 100644 --- a/React/Base/Surface/RCTSurface.mm +++ b/React/Base/Surface/RCTSurface.mm @@ -64,6 +64,7 @@ moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties { + RCTErrorNewArchitectureValidation(RCTNotAllowedInAppWideFabric, @"RCTSurface", nil); RCTAssert(bridge.valid, @"Valid bridge is required to instantiate `RCTSurface`."); if (self = [super init]) { diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 9dbfad6548d..8fd40462a23 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -6,7 +6,6 @@ */ #import "RCTSurfaceHostingView.h" - #import "RCTConstants.h" #import "RCTDefines.h" #import "RCTSurface.h" diff --git a/React/CoreModules/RCTLogBox.mm b/React/CoreModules/RCTLogBox.mm index 78a30635dc5..ae368819c9a 100644 --- a/React/CoreModules/RCTLogBox.mm +++ b/React/CoreModules/RCTLogBox.mm @@ -13,7 +13,6 @@ #import #import #import - #import "CoreModulesPlugins.h" #if RCT_DEV_MENU @@ -23,6 +22,7 @@ @implementation RCTLogBox { RCTLogBoxView *_view; + __weak id _bridgelessSurfacePresenter; } @synthesize bridge = _bridge; @@ -34,6 +34,11 @@ RCT_EXPORT_MODULE() return YES; } +- (void)setSurfacePresenter:(id)surfacePresenter +{ + _bridgelessSurfacePresenter = surfacePresenter; +} + RCT_EXPORT_METHOD(show) { if (RCTRedBoxGetEnabled()) { @@ -49,15 +54,19 @@ RCT_EXPORT_METHOD(show) return; } - if (strongSelf->_bridge) { - if (strongSelf->_bridge.valid) { + if (strongSelf->_bridgelessSurfacePresenter) { + strongSelf->_view = [[RCTLogBoxView alloc] initWithFrame:RCTKeyWindow().frame + surfacePresenter:strongSelf->_bridgelessSurfacePresenter]; + } else if (strongSelf->_bridge && strongSelf->_bridge.valid) { + if (strongSelf->_bridge.surfacePresenter) { + strongSelf->_view = [[RCTLogBoxView alloc] initWithFrame:RCTKeyWindow().frame + surfacePresenter:strongSelf->_bridge.surfacePresenter]; + } else { strongSelf->_view = [[RCTLogBoxView alloc] initWithWindow:RCTKeyWindow() bridge:strongSelf->_bridge]; - [strongSelf->_view show]; } - } else { - NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:strongSelf, @"logbox", nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"CreateLogBoxSurface" object:nil userInfo:userInfo]; } + + [strongSelf->_view show]; }); } } diff --git a/React/CoreModules/RCTLogBoxView.h b/React/CoreModules/RCTLogBoxView.h index 1495fbaed8c..130ced4015c 100644 --- a/React/CoreModules/RCTLogBoxView.h +++ b/React/CoreModules/RCTLogBoxView.h @@ -6,6 +6,7 @@ */ #import +#import #import #import @@ -15,6 +16,8 @@ - (void)createRootViewController:(UIView *)view; +- (instancetype)initWithFrame:(CGRect)frame surfacePresenter:(id)surfacePresenter; + - (instancetype)initWithWindow:(UIWindow *)window bridge:(RCTBridge *)bridge; - (void)show; diff --git a/React/CoreModules/RCTLogBoxView.mm b/React/CoreModules/RCTLogBoxView.mm index 8cf4f4e7e6e..f27b6e06942 100644 --- a/React/CoreModules/RCTLogBoxView.mm +++ b/React/CoreModules/RCTLogBoxView.mm @@ -9,6 +9,7 @@ #import #import +#import @implementation RCTLogBoxView { RCTSurface *_surface; @@ -32,8 +33,25 @@ self.rootViewController = _rootViewController; } +- (instancetype)initWithFrame:(CGRect)frame surfacePresenter:(id)surfacePresenter +{ + if (self = [super initWithFrame:frame]) { + id surface = [surfacePresenter createFabricSurfaceForModuleName:@"LogBox" + initialProperties:@{}]; + [surface start]; + RCTSurfaceHostingView *rootView = [[RCTSurfaceHostingView alloc] + initWithSurface:surface + sizeMeasureMode:RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact]; + + [self createRootViewController:rootView]; + } + return self; +} + - (instancetype)initWithWindow:(UIWindow *)window bridge:(RCTBridge *)bridge { + RCTErrorNewArchitectureValidation(RCTNotAllowedInAppWideFabric, @"RCTLogBoxView", nil); + if (@available(iOS 13.0, *)) { self = [super initWithWindowScene:window.windowScene]; } else { diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h index 62d87be045e..d9a56ac31cc 100644 --- a/React/Fabric/RCTSurfacePresenter.h +++ b/React/Fabric/RCTSurfacePresenter.h @@ -54,6 +54,12 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) RCTMountingManager *mountingManager; +/* + * Allow callers to initialize a new fabric surface without adding Fabric as a Buck dependency. + */ +- (id)createFabricSurfaceForModuleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties; + - (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag; - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 9088701a0be..dd7a1bd0fb5 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -173,6 +173,14 @@ static BackgroundExecutor RCTGetBackgroundExecutor() return [_surfaceRegistry surfaceForRootTag:rootTag]; } +- (id)createFabricSurfaceForModuleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties +{ + return [[RCTFabricSurface alloc] initWithSurfacePresenter:self + moduleName:moduleName + initialProperties:initialProperties]; +} + - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag { UIView *componentView = diff --git a/React/Modules/RCTSurfacePresenterStub.h b/React/Modules/RCTSurfacePresenterStub.h index 9ffc2813120..70510c18127 100644 --- a/React/Modules/RCTSurfacePresenterStub.h +++ b/React/Modules/RCTSurfacePresenterStub.h @@ -9,6 +9,8 @@ #import +@protocol RCTSurfaceProtocol; + NS_ASSUME_NONNULL_BEGIN // TODO: Eventually this should go away and files should just include RCTSurfacePresenter.h, but @@ -26,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN @protocol RCTSurfacePresenterStub +- (id)createFabricSurfaceForModuleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties; - (nullable UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag; - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; - (void)addObserver:(id)observer;