Skip to content

Commit

Permalink
Create RCTAppDelegate to simplify New Architecture Setup (#34384)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #34384

This Diff aims to create a RCTAppDelegate library to offer a subclass which automates some operations required to set up the new architecture.

## Changelog
[iOS][Added] - Added the RCTAppDelegate library

Reviewed By: cortinico

Differential Revision: D38580424

fbshipit-source-id: 38f6c4b8ff2790a2ce9e23d385b36307701cffb7
  • Loading branch information
Riccardo Cipolleschi authored and facebook-github-bot committed Aug 15, 2022
1 parent 0e316ec commit 7cc2d1a
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
*/

#import <UIKit/UIKit.h>
#import <React/RCTBridge.h>
#import <React/RCTBridgeDelegate.h>

#if RCT_NEW_ARCH_ENABLED
// When the new architecture is enabled, the RCTAppDelegate imports some additional headers
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>


#endif

/**
Expand All @@ -31,6 +36,8 @@
object.
*
* Overridable methods (New Architecture):
* - (BOOL)concurrentRootEnabled
* - (NSDictionary *)prepareInitialProps
* - (Class)getModuleClassFromName:(const char *)name
* - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
Expand All @@ -39,19 +46,29 @@
(const facebook::react::ObjCTurboModule::InitParams &)params
* - (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
*/
@interface RCTAppDelegate : UIResponder <UIApplicationDelegate>
@interface RCTAppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>

/// The window object, used to render the UViewControllers
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) RCTBridge *bridge;
@property (nonatomic, strong) NSString *moduleName;

@end

#if RCT_NEW_ARCH_ENABLED
/// Extension that makes the RCTAppDelegate conform to New Architecture delegates
@interface RCTAppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate>
@interface RCTAppDelegate () <RCTTurboModuleManagerDelegate, RCTCxxBridgeDelegate>

/// The TurboModule manager
@property (nonatomic, strong) RCTTurboModuleManager *turboModuleManager;
@property (nonatomic, strong) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;

/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled;

@end
#endif
129 changes: 129 additions & 0 deletions Libraries/AppDelegate/RCTAppDelegate.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RCTAppDelegate.h"
#import <React/RCTAppSetupUtils.h>
#import <React/RCTRootView.h>

#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <react/config/ReactNativeConfig.h>

static NSString *const kRNConcurrentRoot = @"concurrentRoot";

@interface RCTAppDelegate () {
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end

#endif

@implementation RCTAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);

if (!self.bridge) {
self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
}
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge contextContainer:_contextContainer];
self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter;
#endif

NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(self.bridge, self.moduleName, initProps);

if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
[NSException
raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented"
format:@"Subclasses must implement a valid sourceURLForBridge method"
];
return nil;
}

- (BOOL)concurrentRootEnabled
{
[NSException
raise:@"concurrentRootEnabled not implemented"
format:@"Subclasses must implement a valid concurrentRootEnabled method"
];
return true;
}

- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];

#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif

return initProps;
}

#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate

- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}

#pragma mark RCTTurboModuleManagerDelegate

- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}

#endif

@end
57 changes: 57 additions & 0 deletions Libraries/AppDelegate/React-RCTAppDelegate.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

require "json"

package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
version = package['version']

source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end

folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32'

new_arch_enabled_flag="RCT_NEW_ARCH_ENABLED"
is_new_arch_enabled = ENV[new_arch_enabled_flag] == "1"
other_cflags = "$(inherited) -DRN_FABRIC_ENABLED " + folly_flags + (is_new_arch_enabled ? " -D"+"RCT_NEW_ARCH_ENABLED" : "")

Pod::Spec.new do |s|
s.name = "React-RCTAppDelegate"
s.version = version
s.summary = "An utility library to simplify common operations for the New Architecture"
s.homepage = "https://reactnative.dev/"
s.documentation_url = "https://reactnative.dev/docs/actionsheetios"
s.license = package["license"]
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "12.4" }
s.source = source
s.source_files = "**/*.{c,h,m,mm,S,cpp}"

# This guard prevent to install the dependencies when we run `pod install` in the old architecture.
s.compiler_flags = other_cflags
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Headers/Private/React-Core\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\" \"${PODS_ROOT}/Headers/Public/FlipperKit\" \"$(PODS_ROOT)/Headers/Public/ReactCommon\" \"$(PODS_ROOT)/Headers/Public/React-RCTFabric\"",
"OTHER_CPLUSPLUSFLAGS" => other_cflags,
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
}
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""}

s.dependency "React-Core"
s.dependency "RCT-Folly"
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "ReactCommon/turbomodule/core"

if is_new_arch_enabled
s.dependency "React-RCTFabric"
s.dependency "React-graphics"
end
end
55 changes: 0 additions & 55 deletions React/AppSetup/RCTAppDelegate.mm

This file was deleted.

4 changes: 2 additions & 2 deletions packages/rn-tester/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if USE_FRAMEWORKS
use_frameworks!
end

def pods(options = {}, use_flipper: false)
def pods(options = {}, use_flipper: !IN_CI && !USE_FRAMEWORKS)
project 'RNTesterPods.xcodeproj'

fabric_enabled = true
Expand Down Expand Up @@ -53,7 +53,7 @@ def pods(options = {}, use_flipper: false)
end

target 'RNTester' do
pods({}, :use_flipper => !IN_CI && !USE_FRAMEWORKS)
pods()
end

target 'RNTesterUnitTests' do
Expand Down
12 changes: 11 additions & 1 deletion packages/rn-tester/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,12 @@ PODS:
- React-Core/RCTAnimationHeaders (= 1000.0.0)
- React-jsi (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTAppDelegate (1000.0.0):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React-Core
- ReactCommon/turbomodule/core
- React-RCTBlob (1000.0.0):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 1000.0.0)
Expand Down Expand Up @@ -771,6 +777,7 @@ DEPENDENCIES:
- React-perflogger (from `../../ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../../Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../../Libraries/NativeAnimation`)
- React-RCTAppDelegate (from `../../Libraries/AppDelegate`)
- React-RCTBlob (from `../../Libraries/Blob`)
- React-RCTFabric (from `../../React`)
- React-RCTImage (from `../../Libraries/Image`)
Expand Down Expand Up @@ -855,6 +862,8 @@ EXTERNAL SOURCES:
:path: "../../Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../../Libraries/NativeAnimation"
React-RCTAppDelegate:
:path: "../../Libraries/AppDelegate"
React-RCTBlob:
:path: "../../Libraries/Blob"
React-RCTFabric:
Expand Down Expand Up @@ -924,6 +933,7 @@ SPEC CHECKSUMS:
React-perflogger: c4fdd48988c2d3047186fc1bc1772d634cfca2ea
React-RCTActionSheet: 166fd1df85ac10219466b45d12a5884d3eaceac1
React-RCTAnimation: d6127046c6bb44bd3e67b7503c4ad7f91131b58e
React-RCTAppDelegate: 475ca9b80e26c1c4aed93ce04363092fa78cf788
React-RCTBlob: 68675c89ebe6edf310dddd0774ba07b685f090a9
React-RCTFabric: a98a6effece6719669b8c6b4d2c33fb0edddc613
React-RCTImage: 6de9f0f4402af859849e97cc73a56a52f400f4c9
Expand All @@ -942,6 +952,6 @@ SPEC CHECKSUMS:
Yoga: 1b1a12ff3d86a10565ea7cbe057d42f5e5fb2a07
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a

PODFILE CHECKSUM: 54d9bd86f3c8151531bd4da1d3ba2e2e1f9a6ca9
PODFILE CHECKSUM: c3d82494e47e0adce02921f2ed9dba2427f0a9ff

COCOAPODS: 1.11.3
Loading

0 comments on commit 7cc2d1a

Please sign in to comment.