ssap_app/node_modules/expo-dev-menu/ios/DevMenuPackagerConnectionHa...

103 lines
2.9 KiB
Swift

// Copyright 2015-present 650 Industries. All rights reserved.
import Foundation
import React
class DevMenuPackagerConnectionHandler {
weak var manager: DevMenuManager?
private static var suppressRNDevMenu = true
init(manager: DevMenuManager) {
self.manager = manager
}
func setup() {
// `RCT_DEV` isn't available in Swift, that's why we used `DEBUG` instead.
// It shouldn't diverge, because of the definition of `RCT_DEV`.
#if DEBUG
self.swizzleRCTDevMenuShow()
RCTPackagerConnection
.shared()
.addNotificationHandler(
self.sendDevCommandNotificationHandler,
queue: DispatchQueue.main,
forMethod: "sendDevCommand"
)
RCTPackagerConnection
.shared()
.addNotificationHandler(
self.devMenuNotificationHanlder,
queue: DispatchQueue.main,
forMethod: "devMenu"
)
#endif
}
private func swizzleRCTDevMenuShow() {
// [@alan] HACK: We are only doing this to prevent the RN dev menu from showing except when called from
// our dev menu. Without this, it will still respond to commands coming from the packager. I could not
// find an easier way to do this until we have a proper api.
guard let devMenuClass = NSClassFromString("RCTDevMenu") else {
return
}
let originalSelector = NSSelectorFromString("show")
guard let originalMethod = class_getInstanceMethod(devMenuClass, originalSelector) else {
return
}
let originalImplementation = method_getImplementation(originalMethod)
let block: @convention(block) (AnyObject) -> Void = { devMenuInstance in
if DevMenuPackagerConnectionHandler.suppressRNDevMenu {
return
}
typealias ShowFunction = @convention(c) (AnyObject, Selector) -> Void
let showFunc = unsafeBitCast(originalImplementation, to: ShowFunction.self)
showFunc(devMenuInstance, originalSelector)
}
let blockImpl = imp_implementationWithBlock(block)
method_setImplementation(originalMethod, blockImpl)
}
@objc
func sendDevCommandNotificationHandler(_ params: [String: Any]) {
guard let manager = manager,
let command = params["name"] as? String,
let bridge = manager.currentBridge
else {
return
}
let devDelegate = DevMenuDevOptionsDelegate(forBridge: bridge)
switch command {
case "reload":
devDelegate.reload()
case "toggleDevMenu":
self.manager?.toggleMenu()
case "toggleElementInspector":
devDelegate.toggleElementInsector()
case "togglePerformanceMonitor":
devDelegate.togglePerformanceMonitor()
default:
NSLog("Unknown command from packager: %@", command)
}
}
@objc
func devMenuNotificationHanlder(_ parames: [String: Any]) {
self.manager?.toggleMenu()
}
static func allowRNDevMenuTemporarily() {
suppressRNDevMenu = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
suppressRNDevMenu = true
}
}
}