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