1 // Copyright 2015-present 650 Industries. All rights reserved. 2 3 import React 4 5 @objc 6 class DevMenuAppInstance: DevMenuRCTCxxBridgeDelegate, RCTBridgeDelegate { 7 static private var CloseEventName = "closeDevMenu" 8 static private var OpenEventName = "openDevMenu" 9 10 private let manager: DevMenuManager 11 12 var bridge: RCTBridge? 13 14 init(manager: DevMenuManager) { 15 self.manager = manager 16 17 super.init() 18 19 self.bridge = DevMenuRCTBridge.init(delegate: self, launchOptions: nil) 20 } 21 22 init(manager: DevMenuManager, bridge: RCTBridge) { 23 self.manager = manager 24 25 super.init() 26 27 self.bridge = bridge 28 } 29 30 /** 31 Sends an event to JS triggering the animation that collapses the dev menu. 32 */ 33 public func sendCloseEvent() { 34 bridge?.enqueueJSCall("RCTDeviceEventEmitter.emit", args: [DevMenuAppInstance.CloseEventName]) 35 } 36 37 public func sendOpenEvent() { 38 bridge?.enqueueJSCall("RCTDeviceEventEmitter.emit", args: [DevMenuAppInstance.OpenEventName]) 39 } 40 41 // MARK: RCTBridgeDelegate 42 43 func sourceURL(for bridge: RCTBridge!) -> URL! { 44 #if DEBUG 45 if let packagerHost = jsPackagerHost() { 46 return RCTBundleURLProvider.jsBundleURL( 47 forBundleRoot: "index", 48 packagerHost: packagerHost, 49 enableDev: true, 50 enableMinification: false) 51 } 52 #endif 53 return jsSourceUrl() 54 } 55 56 func extraModules(for bridge: RCTBridge!) -> [RCTBridgeModule]! { 57 var modules: [RCTBridgeModule] = [DevMenuInternalModule(manager: manager)] 58 modules.append(contentsOf: DevMenuVendoredModulesUtils.vendoredModules(bridge)) 59 modules.append(DevMenuLoadingView.init()) 60 modules.append(DevMenuRCTDevSettings.init()) 61 return modules 62 } 63 64 func bridge(_ bridge: RCTBridge!, didNotFindModule moduleName: String!) -> Bool { 65 return moduleName == "DevMenu" 66 } 67 68 // MARK: private 69 70 private func jsSourceUrl() -> URL? { 71 return DevMenuUtils.resourcesBundle()?.url(forResource: "EXDevMenuApp.ios", withExtension: "js") 72 } 73 74 private func jsPackagerHost() -> String? { 75 // Return `nil` if resource doesn't exist in the bundle. 76 guard let packagerHostPath = DevMenuUtils.resourcesBundle()?.path(forResource: "dev-menu-packager-host", ofType: nil) else { 77 return nil 78 } 79 // Return `nil` if the content is not a valid URL. 80 guard let content = try? String(contentsOfFile: packagerHostPath, encoding: String.Encoding.utf8).trimmingCharacters(in: CharacterSet.newlines), 81 let url = URL(string: content) else { 82 return nil 83 } 84 return url.absoluteString 85 } 86 } 87