From db9c9eacac301c4a684130413423eab50bbb1d72 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Tue, 2 Jan 2024 04:53:38 -0800 Subject: [PATCH] Add function to customise RootView in Bridgeless (#42088) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/42088 This change adds an extra function to customise the RootView in both Bridge and Bridgeless mode. To nudge users in a migration, we also add a warning message for next version that should push our users to migrate away from the old implementation to the new one. *The Warning is shown ONLY when the user do customise the rootView*. For users which were not customising the Root View, the warning will not appear. The documentation of the new method plus the warning should guide the users toward the right migration path. ## Changelog [iOS][Added] - Added the customiseRootView method which is called in both bridge and bridgeless. Added also a warning for 0.74 with instructions on how to migrate. Reviewed By: cortinico Differential Revision: D52442598 fbshipit-source-id: 8b99b67f4741ee61989a8659a3d74c1eba27bc5b --- .../Libraries/AppDelegate/RCTAppDelegate.h | 21 +++++++++++++++++ .../Libraries/AppDelegate/RCTAppDelegate.mm | 23 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h index f6a35caf3f0cb3..2c8ce3fa363669 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h @@ -11,6 +11,7 @@ @class RCTBridge; @protocol RCTBridgeDelegate; @protocol RCTComponentViewProtocol; +@class RCTRootView; @class RCTSurfacePresenterBridgeAdapter; /** @@ -86,6 +87,26 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initProps:(NSDictionary *)initProps; +/** + * This method can be used to customize the rootView that is passed to React Native. + * A typical example is to override this method in the AppDelegate to change the background color. + * To achieve this, add in your `AppDelegate.mm`: + * ``` + * - (void)customizeRootView:(RCTRootView *)rootView + * { + * rootView.backgroundColor = [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) { + * if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleDark) { + * return [UIColor blackColor]; + * } else { + * return [UIColor whiteColor]; + * } + * }]; + * } + * ``` + * + * @parameter: rootView - The root view to customize. + */ +- (void)customizeRootView:(RCTRootView *)rootView; /** * It creates the RootViewController. diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm index 65c48ff28d2290..4cecb740a3f23a 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm @@ -7,6 +7,7 @@ #import "RCTAppDelegate.h" #import +#import #import #import #import @@ -117,6 +118,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( } rootView = [self createRootViewWithBridge:self.bridge moduleName:self.moduleName initProps:initProps]; } + [self customizeRootView:(RCTRootView *)rootView]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [self createRootViewController]; [self setRootView:rootView toRootViewController:rootViewController]; @@ -144,10 +146,16 @@ - (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOp return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions]; } +- (void)customizeRootView:(RCTRootView *)rootView +{ + // Override point for customization after application launch. +} + - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initProps:(NSDictionary *)initProps { + [self _logWarnIfCreateRootViewWithBridgeIsOverridden]; BOOL enableFabric = self.fabricEnabled; UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); @@ -156,6 +164,21 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge return rootView; } +// TODO T173939093 - Remove _logWarnIfCreateRootViewWithBridgeIsOverridden after 0.74 is cut +- (void)_logWarnIfCreateRootViewWithBridgeIsOverridden +{ + SEL selector = @selector(createRootViewWithBridge:moduleName:initProps:); + IMP baseClassImp = method_getImplementation(class_getInstanceMethod([RCTAppDelegate class], selector)); + IMP currentClassImp = method_getImplementation(class_getInstanceMethod([self class], selector)); + if (currentClassImp != baseClassImp) { + NSString *warnMessage = + @"If you are using the `createRootViewWithBridge` to customize the root view appearence," + "for example to set the backgroundColor, please migrate to `customiseView` method.\n" + "The `createRootViewWithBridge` method is not invoked in bridgeless."; + RCTLogWarn(@"%@", warnMessage); + } +} + - (UIViewController *)createRootViewController { return [UIViewController new];