ssap_app/node_modules/expo-dev-launcher/ios/ReactDelegateHandler/ExpoDevLauncherReactDelegat...

130 lines
5.1 KiB
Swift

// Copyright 2018-present 650 Industries. All rights reserved.
import ExpoModulesCore
import EXUpdatesInterface
@objc
public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, EXDevLauncherControllerDelegate {
private weak var reactNativeFactory: RCTReactNativeFactory?
private weak var reactDelegate: ExpoReactDelegate?
private var launchOptions: [AnyHashable: Any]?
private var deferredRootView: EXDevLauncherDeferredRCTRootView?
private var rootViewModuleName: String?
private var rootViewInitialProperties: [AnyHashable: Any]?
public override func createReactRootView(
reactDelegate: ExpoReactDelegate,
moduleName: String,
initialProperties: [AnyHashable: Any]?,
launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> UIView? {
if !EXAppDefines.APP_DEBUG {
return nil
}
self.reactDelegate = reactDelegate
self.launchOptions = launchOptions
EXDevLauncherController.sharedInstance().autoSetupPrepare(self, launchOptions: launchOptions)
if let sharedController = UpdatesControllerRegistry.sharedInstance.controller {
// for some reason the swift compiler and bridge are having issues here
EXDevLauncherController.sharedInstance().updatesInterface = sharedController
sharedController.updatesExternalInterfaceDelegate = EXDevLauncherController.sharedInstance()
}
self.rootViewModuleName = moduleName
self.rootViewInitialProperties = initialProperties
self.deferredRootView = EXDevLauncherDeferredRCTRootView()
return self.deferredRootView
}
@objc
public func isReactInstanceValid() -> Bool {
return self.reactNativeFactory?.rootViewFactory.value(forKey: "reactHost") != nil
}
@objc
public func destroyReactInstance() {
self.reactNativeFactory?.rootViewFactory.setValue(nil, forKey: "reactHost")
}
// MARK: EXDevelopmentClientControllerDelegate implementations
public func devLauncherController(_ developmentClientController: EXDevLauncherController, didStartWithSuccess success: Bool) {
let appDelegate = (UIApplication.shared.delegate as? (any ReactNativeFactoryProvider)) ??
(UIApplication.shared.delegate?.responds(to: Selector(("_expoAppDelegate"))) ?? false ?
((UIApplication.shared.delegate as? NSObject)?.value(forKey: "_expoAppDelegate") as? (any ReactNativeFactoryProvider)) : nil)
let reactDelegate = self.reactDelegate
guard let reactNativeFactory = appDelegate?.factory as? RCTReactNativeFactory ?? reactDelegate?.reactNativeFactory as? RCTReactNativeFactory else {
fatalError("`UIApplication.shared.delegate` must be an `ExpoAppDelegate` or `EXAppDelegateWrapper`")
}
self.reactNativeFactory = reactNativeFactory
// Reset rctAppDelegate so we can relaunch the app
if RCTIsNewArchEnabled() {
self.reactNativeFactory?.rootViewFactory.setValue(nil, forKey: "_reactHost")
} else {
self.reactNativeFactory?.bridge = nil
self.reactNativeFactory?.rootViewFactory.bridge = nil
}
func recreateRootView(
withBundleURL: URL?,
moduleName: String?,
initialProps: [AnyHashable: Any]?,
launchOptions: [AnyHashable: Any]?
) -> UIView {
if let appDelegate = appDelegate {
return appDelegate.recreateRootView(
withBundleURL: withBundleURL,
moduleName: moduleName,
initialProps: initialProps,
launchOptions: launchOptions
)
}
if let factory = reactDelegate?.reactNativeFactory {
return factory.recreateRootView(
withBundleURL: withBundleURL,
moduleName: moduleName,
initialProps: initialProps,
launchOptions: launchOptions
)
}
fatalError("`UIApplication.shared.delegate` must be an `ExpoAppDelegate` or `EXAppDelegateWrapper`")
}
let rootView = recreateRootView(
withBundleURL: developmentClientController.sourceUrl(),
moduleName: self.rootViewModuleName,
initialProps: self.rootViewInitialProperties,
launchOptions: developmentClientController.getLaunchOptions()
)
developmentClientController.appBridge = RCTBridge.current()
rootView.backgroundColor = self.deferredRootView?.backgroundColor ?? UIColor.white
let window = getWindow()
// NOTE: this order of assignment seems to actually have an effect on behaviour
// direct assignment of window.rootViewController.view = rootView does not work
guard let rootViewController = self.reactDelegate?.createRootViewController() else {
fatalError("Invalid rootViewController returned from ExpoReactDelegate")
}
rootViewController.view = rootView
window.rootViewController = rootViewController
window.makeKeyAndVisible()
// it is purposeful that we don't clean up saved properties here, because we may initialize
// several React instances over a single app lifetime and we want them all to have the same
// initial properties
}
// MARK: Internals
private func getWindow() -> UIWindow {
guard let window = UIApplication.shared.windows.filter(\.isKeyWindow).first ?? UIApplication.shared.delegate?.window as? UIWindow else {
fatalError("Cannot find the current window.")
}
return window
}
}