1// Copyright 2015-present 650 Industries. All rights reserved.
2
3#import <EXDevMenu/DevMenuRCTBridge.h>
4
5// The search path for the Swift generated headers are different
6// between use_frameworks and non_use_frameworks mode.
7#if __has_include(<EXDevMenuInterface/EXDevMenuInterface-Swift.h>)
8#import <EXDevMenuInterface/EXDevMenuInterface-Swift.h>
9#else
10#import <EXDevMenuInterface-Swift.h>
11#endif
12#if __has_include(<ExpoModulesCore/ExpoModulesCore-Swift.h>)
13#import <ExpoModulesCore/ExpoModulesCore-Swift.h>
14#else
15#import <ExpoModulesCore-Swift.h>
16#endif
17#if __has_include(<EXDevMenu/EXDevMenu-Swift.h>)
18#import <EXDevMenu/EXDevMenu-Swift.h>
19#else
20#import <EXDevMenu-Swift.h>
21#endif
22#import <RCTCxxBridge+Private.h>
23
24#import <React/RCTPerformanceLogger.h>
25#import <React/RCTDevSettings.h>
26#import <React/RCTBridge+Private.h>
27#import <React/RCTDevMenu.h>
28#import <React/RCTCxxBridgeDelegate.h>
29#import <React/RCTJSIExecutorRuntimeInstaller.h>
30#import <React/RCTRuntimeExecutorFromBridge.h>
31#if __has_include(<React_RCTAppDelegate/RCTAppSetupUtils.h>)
32// for importing the header from framework, the dash will be transformed to underscore
33#import <React_RCTAppDelegate/RCTAppSetupUtils.h>
34#else
35#import <React-RCTAppDelegate/RCTAppSetupUtils.h>
36#endif
37#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
38#if __has_include(<reacthermes/HermesExecutorFactory.h>)
39#import <reacthermes/HermesExecutorFactory.h>
40#endif
41
42
43
44@implementation DevMenuRCTCxxBridge
45
46- (instancetype)initWithParentBridge:(RCTBridge *)bridge
47{
48  if ((self = [super initWithParentBridge:bridge])) {
49    RCTBridge *appBridge = DevMenuManager.shared.currentBridge;
50    // reset the singleton `RCTBridge.currentBridge` to app bridge instance
51    RCTBridge.currentBridge = appBridge != nil ? appBridge.batchedBridge : nil;
52  }
53  return self;
54}
55
56/**
57 * Theoretically, we could overwrite the `RCTDevSettings` module by exporting our version through the bridge.
58 * However, this won't work with the js remote debugging. For some reason, the RN needs to initialized remote tools very early. So it always uses the default module to do it.
59 * When we export our module, it won't be used in the initialized phase. So the dev-menu will start with remote debug support.
60 */
61- (RCTDevSettings *)devSettings
62{
63  // uncomment below to enable fast refresh for development builds of DevMenu
64  //  return super.devSettings;
65  return nil;
66}
67
68- (RCTDevMenu *)devMenu
69{
70  return nil;
71}
72
73- (NSArray<Class> *)filterModuleList:(NSArray<Class> *)modules
74{
75  NSArray<NSString *> *allowedModules = @[@"RCT", @"ExpoBridgeModule", @"EXNativeModulesProxy", @"EXReactNativeEventEmitter"];
76  NSArray<Class> *filteredModuleList = [modules filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable clazz, NSDictionary<NSString *,id> * _Nullable bindings) {
77    NSString* clazzName = NSStringFromClass(clazz);
78
79    if ([clazz conformsToProtocol:@protocol(EXDevExtensionProtocol)]) {
80      return true;
81    }
82
83    for (NSString *allowedModule in allowedModules) {
84      if ([clazzName hasPrefix:allowedModule]) {
85        return true;
86      }
87    }
88    return false;
89  }]];
90
91  return filteredModuleList;
92}
93
94- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<Class> *)modules
95                               withDispatchGroup:(dispatch_group_t)dispatchGroup
96                                lazilyDiscovered:(BOOL)lazilyDiscovered
97{
98  NSArray<Class> *filteredModuleList = [self filterModuleList: modules];
99  return [super _initializeModules:filteredModuleList withDispatchGroup:dispatchGroup lazilyDiscovered:lazilyDiscovered];
100}
101
102@end
103
104@implementation DevMenuRCTBridge
105
106- (Class)bridgeClass
107{
108  return [DevMenuRCTCxxBridge class];
109}
110
111#pragma clang diagnostic push
112#pragma clang diagnostic ignored "-Wdeprecated-implementations"
113// This method is still used so we need to override it even if it's deprecated
114- (void)reloadWithReason:(NSString *)reason {}
115#pragma clang diagnostic pop
116
117@end
118
119@interface DevClientAppDelegate (DevMenuRCTAppDelegate)
120
121#ifdef __cplusplus
122- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge;
123#endif
124@end
125
126@implementation DevMenuRCTAppDelegate
127
128
129- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
130{
131  return [[DevMenuRCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions];
132}
133
134#pragma mark - RCTCxxBridgeDelegate
135- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
136{
137    std::unique_ptr<facebook::react::JSExecutorFactory> executorFactory  = [super jsExecutorFactoryForBridge:bridge];
138
139    #if __has_include(<reacthermes/HermesExecutorFactory.h>)
140        auto rawExecutorFactory = executorFactory.get();
141        auto hermesExecFactory = dynamic_cast<facebook::react::HermesExecutorFactory*>(rawExecutorFactory);
142        if (hermesExecFactory != nullptr) {
143            hermesExecFactory->setEnableDebugger(false);
144        }
145    #endif
146
147    return executorFactory;
148}
149
150@end
151