1// Copyright 2018-present 650 Industries. All rights reserved.
2
3#import <ExpoModulesCore/EXAppDelegateWrapper.h>
4#import <ExpoModulesCore/EXReactDelegateWrapper+Private.h>
5#import <ExpoModulesCore/Swift.h>
6
7
8@interface EXAppDelegateWrapper()
9
10@property (nonatomic, strong) EXReactDelegateWrapper *reactDelegate;
11
12@end
13
14@implementation EXAppDelegateWrapper {
15  EXExpoAppDelegate *_expoAppDelegate;
16}
17
18// Synthesize window, so the AppDelegate can synthesize it too.
19@synthesize window = _window;
20
21- (instancetype)init
22{
23  if (self = [super init]) {
24    _expoAppDelegate = [[EXExpoAppDelegate alloc] init];
25    _reactDelegate = [[EXReactDelegateWrapper alloc] initWithExpoReactDelegate:_expoAppDelegate.reactDelegate];
26  }
27  return self;
28}
29
30// This needs to be implemented, otherwise forwarding won't be called.
31// When the app starts, `UIApplication` uses it to check beforehand
32// which `UIApplicationDelegate` selectors are implemented.
33- (BOOL)respondsToSelector:(SEL)selector
34{
35  return [super respondsToSelector:selector]
36    || [_expoAppDelegate respondsToSelector:selector];
37}
38
39// Forwards all invocations to `ExpoAppDelegate` object.
40- (id)forwardingTargetForSelector:(SEL)selector
41{
42  return _expoAppDelegate;
43}
44
45#if __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>) || __has_include(<React_RCTAppDelegate/RCTAppDelegate.h>)
46
47- (UIView *)findRootView:(UIApplication *)application
48{
49  UIWindow *mainWindow = application.delegate.window;
50  if (mainWindow == nil) {
51    return nil;
52  }
53  UIViewController *rootViewController = mainWindow.rootViewController;
54  if (rootViewController == nil) {
55    return nil;
56  }
57  UIView *rootView = rootViewController.view;
58  return rootView;
59}
60
61- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
62{
63  UIView *rootView = [self findRootView:application];
64  // Backward compatible with react-native 0.71 running with legacy template,
65  // i.e. still creating bridge, rootView in AppDelegate.mm.
66  // In this case, we don't go through RCTAppDelegate's setup.
67  if (rootView == nil || ![rootView isKindOfClass:[RCTRootView class]]) {
68    [super application:application didFinishLaunchingWithOptions:launchOptions];
69    [_expoAppDelegate application:application didFinishLaunchingWithOptions:launchOptions];
70  }
71  return YES;
72}
73
74- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
75{
76  return [self.reactDelegate createBridgeWithDelegate:delegate launchOptions:launchOptions];
77}
78
79- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
80                          moduleName:(NSString *)moduleName
81                           initProps:(NSDictionary *)initProps
82{
83  BOOL enableFabric = NO;
84#if RN_FABRIC_ENABLED
85  enableFabric = self.fabricEnabled;
86#endif
87
88  return [self.reactDelegate createRootViewWithBridge:bridge
89                                         moduleName:moduleName
90                                    initialProperties:initProps
91                                        fabricEnabled:enableFabric];
92}
93
94- (UIViewController *)createRootViewController
95{
96  return [self.reactDelegate createRootViewController];
97}
98#endif // __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>)
99
100@end
101