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#if __has_include(<React_RCTAppDelegate/RCTAppSetupUtils.h>)
31// for importing the header from framework, the dash will be transformed to underscore
32#import <React_RCTAppDelegate/RCTAppSetupUtils.h>
33#else
34#import <React-RCTAppDelegate/RCTAppSetupUtils.h>
35#endif
36#if __has_include(<reacthermes/HermesExecutorFactory.h>)
37#import <reacthermes/HermesExecutorFactory.h>
38#endif
39
40
41
42@implementation DevMenuRCTCxxBridge
43
44- (instancetype)initWithParentBridge:(RCTBridge *)bridge
45{
46  if ((self = [super initWithParentBridge:bridge])) {
47    RCTBridge *appBridge = DevMenuManager.shared.currentBridge;
48    // reset the singleton `RCTBridge.currentBridge` to app bridge instance
49    RCTBridge.currentBridge = appBridge != nil ? appBridge.batchedBridge : nil;
50  }
51  return self;
52}
53
54/**
55 * Theoretically, we could overwrite the `RCTDevSettings` module by exporting our version through the bridge.
56 * 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.
57 * When we export our module, it won't be used in the initialized phase. So the dev-menu will start with remote debug support.
58 */
59- (RCTDevSettings *)devSettings
60{
61  // uncomment below to enable fast refresh for development builds of DevMenu
62  //  return super.devSettings;
63  return nil;
64}
65
66- (RCTDevMenu *)devMenu
67{
68  return nil;
69}
70
71- (NSArray<Class> *)filterModuleList:(NSArray<Class> *)modules
72{
73  NSArray<NSString *> *allowedModules = @[@"RCT", @"ExpoBridgeModule", @"EXNativeModulesProxy", @"EXReactNativeEventEmitter"];
74  NSArray<Class> *filteredModuleList = [modules filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable clazz, NSDictionary<NSString *,id> * _Nullable bindings) {
75    NSString* clazzName = NSStringFromClass(clazz);
76
77    if ([clazz conformsToProtocol:@protocol(EXDevExtensionProtocol)]) {
78      return true;
79    }
80
81    for (NSString *allowedModule in allowedModules) {
82      if ([clazzName hasPrefix:allowedModule]) {
83        return true;
84      }
85    }
86    return false;
87  }]];
88
89  return filteredModuleList;
90}
91
92- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<Class> *)modules
93                               withDispatchGroup:(dispatch_group_t)dispatchGroup
94                                lazilyDiscovered:(BOOL)lazilyDiscovered
95{
96  NSArray<Class> *filteredModuleList = [self filterModuleList: modules];
97  return [super _initializeModules:filteredModuleList withDispatchGroup:dispatchGroup lazilyDiscovered:lazilyDiscovered];
98}
99
100@end
101
102@implementation DevMenuRCTBridge
103
104- (Class)bridgeClass
105{
106  return [DevMenuRCTCxxBridge class];
107}
108
109#pragma clang diagnostic push
110#pragma clang diagnostic ignored "-Wdeprecated-implementations"
111// This method is still used so we need to override it even if it's deprecated
112- (void)reloadWithReason:(NSString *)reason {}
113#pragma clang diagnostic pop
114
115@end
116
117@interface DevClientAppDelegate (DevMenuRCTAppDelegate)
118
119#ifdef __cplusplus
120- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge;
121#endif
122@end
123
124@implementation DevMenuRCTAppDelegate
125
126
127- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
128{
129  return [[DevMenuRCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions];
130}
131
132#pragma mark - RCTCxxBridgeDelegate
133- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
134{
135    std::unique_ptr<facebook::react::JSExecutorFactory> executorFactory  = [super jsExecutorFactoryForBridge:bridge];
136
137    #if __has_include(<reacthermes/HermesExecutorFactory.h>)
138        auto rawExecutorFactory = executorFactory.get();
139        auto hermesExecFactory = dynamic_cast<facebook::react::HermesExecutorFactory*>(rawExecutorFactory);
140        if (hermesExecFactory != nullptr) {
141            hermesExecFactory->setEnableDebugger(false);
142        }
143    #endif
144
145    return executorFactory;
146}
147
148@end
149