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];