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