1 // Copyright 2023-present 650 Industries. All rights reserved. 2 3 import React 4 import ExpoModulesCore 5 import EXManifests 6 7 /** 8 Manages the React Native app opened in Expo Go. As opposed to ``EXReactAppManager`` and ``EXHomeAppManager``, 9 this manager is versioned and used by them under the hood like an adapter. 10 */ 11 @objc(EXVersionManager) 12 final class VersionManager: EXVersionManagerObjC { 13 var appContext: AppContext? 14 var legacyModulesProxy: LegacyNativeModulesProxy? 15 var legacyModuleRegistry: EXModuleRegistry? 16 17 let params: [AnyHashable: Any] 18 19 let manifest: Manifest 20 21 @objc 22 override init( 23 params: [AnyHashable: Any], 24 manifest: Manifest, 25 fatalHandler: @escaping (Error?) -> Void, 26 logFunction: @escaping RCTLogFunction, 27 logThreshold: RCTLogLevel 28 ) { 29 self.params = params 30 self.manifest = manifest 31 32 configureReact( 33 enableTurboModules: manifest.experiments()?["turboModules"] as? Bool ?? false, 34 fatalHandler: fatalHandler, 35 logFunction: logFunction, 36 logThreshold: logThreshold 37 ) 38 super.init(params: params, manifest: manifest, fatalHandler: fatalHandler, logFunction: logFunction, logThreshold: logThreshold) 39 } 40 41 /** 42 Invalidates the app context when the bridge is about to be rebuilt. 43 */ 44 override func invalidate() { 45 appContext = nil 46 super.invalidate() 47 } 48 49 /** 50 Returns a list of bridge modules to register when the bridge initializes. 51 */ 52 @objc 53 override func extraModules(forBridge bridge: Any) -> [Any] { 54 // Ideally if we don't initialize the app context here, but unfortunately there is no better place in bridge lifecycle 55 // that would work well for us (especially properly invalidating existing app context on reload). 56 let legacyModuleRegistry = createLegacyModuleRegistry(params: params, manifest: manifest) 57 let legacyModulesProxy = LegacyNativeModulesProxy(customModuleRegistry: legacyModuleRegistry) 58 let appContext = AppContext(legacyModulesProxy: legacyModulesProxy, legacyModuleRegistry: legacyModuleRegistry) 59 60 self.appContext = appContext 61 self.legacyModuleRegistry = legacyModuleRegistry 62 self.legacyModulesProxy = legacyModulesProxy 63 64 let modules: [Any] = [ 65 EXAppState(), 66 EXDisabledDevLoadingView(), 67 EXStatusBarManager(), 68 69 // Adding EXNativeModulesProxy with the custom moduleRegistry. 70 legacyModulesProxy, 71 72 // Adding the way to access the module registry from RCTBridgeModules. 73 EXModuleRegistryHolderReactModule(moduleRegistry: legacyModuleRegistry), 74 75 // When ExpoBridgeModule is initialized by RN, it automatically creates the app context. 76 // In Expo Go, it has to use already created app context. 77 ExpoBridgeModule(appContext: appContext) 78 ] 79 80 // Register additional Expo modules, specific to Expo Go. 81 registerExpoModules() 82 83 return modules + super.extraModules(forBridge: bridge) 84 } 85 86 /** 87 Registers Expo modules that are not generated in ``ExpoModulesProvider``, but are necessary for Expo Go apps. 88 */ 89 private func registerExpoModules() { 90 appContext?.moduleRegistry.register(moduleType: ExpoGoModule.self) 91 } 92 } 93 94 /** 95 Configures some React Native global options. 96 */ 97 private func configureReact( 98 enableTurboModules: Bool, 99 fatalHandler: @escaping (Error?) -> Void, 100 logFunction: @escaping RCTLogFunction, 101 logThreshold: RCTLogLevel 102 ) { 103 RCTEnableTurboModule(enableTurboModules) 104 RCTSetFatalHandler(fatalHandler) 105 RCTSetLogThreshold(logThreshold) 106 RCTSetLogFunction(logFunction) 107 } 108 109 /** 110 Creates a module registry for legacy Expo modules. 111 */ 112 private func createLegacyModuleRegistry(params: [AnyHashable: Any], manifest: Manifest) -> EXModuleRegistry { 113 guard let singletonModules = params["singletonModules"] as? Set<AnyHashable> else { 114 fatalError("Singleton modules param cannot be cast to Set<AnyHashable>") 115 } 116 let moduleRegistryProvider = ModuleRegistryProvider(singletonModules: singletonModules) 117 let moduleRegistryAdapter = EXScopedModuleRegistryAdapter(moduleRegistryProvider: moduleRegistryProvider) 118 119 moduleRegistryProvider.moduleRegistryDelegate = EXScopedModuleRegistryDelegate(params: params) 120 121 return moduleRegistryAdapter.moduleRegistry( 122 forParams: params, 123 forExperienceStableLegacyId: manifest.stableLegacyId(), 124 scopeKey: manifest.scopeKey(), 125 manifest: manifest, 126 withKernelServices: params["services"] as? [AnyHashable: Any] 127 ) 128 } 129