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