289 lines
10 KiB
Swift
289 lines
10 KiB
Swift
import Dispatch
|
|
import Foundation
|
|
import ExpoModulesCore
|
|
import ReactAppDependencyProvider
|
|
|
|
/**
|
|
Note: you cannot subclass Swift from Objective-C, use EXAppDelegateWrapper with Obj-C app delegates
|
|
Allows classes extending `ExpoAppDelegateSubscriber` to hook into project's app delegate
|
|
by forwarding `UIApplicationDelegate` events to the subscribers.
|
|
|
|
Keep functions and markers in sync with https://developer.apple.com/documentation/uikit/uiapplicationdelegate
|
|
*/
|
|
@objc(EXExpoAppDelegate)
|
|
open class ExpoAppDelegate: UIResponder, @preconcurrency ReactNativeFactoryProvider, UIApplicationDelegate {
|
|
@objc public var factory: RCTReactNativeFactory?
|
|
private let defaultModuleName = "main"
|
|
private let defaultInitialProps = [AnyHashable: Any]()
|
|
|
|
public func bindReactNativeFactory(_ factory: RCTReactNativeFactory) {
|
|
self.factory = factory
|
|
}
|
|
|
|
public func recreateRootView(
|
|
withBundleURL: URL?,
|
|
moduleName: String?,
|
|
initialProps: [AnyHashable: Any]?,
|
|
launchOptions: [AnyHashable: Any]?
|
|
) -> UIView {
|
|
guard let delegate = self.factory?.delegate,
|
|
let rootViewFactory = self.factory?.rootViewFactory else {
|
|
fatalError("recreateRootView: Missing factory in ExpoAppDelegate")
|
|
}
|
|
|
|
if delegate.newArchEnabled() {
|
|
// chrfalch: rootViewFactory.reactHost is not available here in swift due to the underlying RCTHost type of the property. (todo: check)
|
|
assert(rootViewFactory.value(forKey: "reactHost") == nil, "recreateRootViewWithBundleURL: does not support when react instance is created")
|
|
} else {
|
|
assert(rootViewFactory.bridge == nil, "recreateRootViewWithBundleURL: does not support when react instance is created")
|
|
}
|
|
|
|
let configuration = rootViewFactory.value(forKey: "_configuration") as? RCTRootViewFactoryConfiguration
|
|
|
|
if let bundleURL = withBundleURL {
|
|
configuration?.bundleURLBlock = {
|
|
return bundleURL
|
|
}
|
|
}
|
|
|
|
let rootView: UIView
|
|
if let factory = rootViewFactory as? ExpoReactRootViewFactory {
|
|
// When calling `recreateRootViewWithBundleURL:` from `EXReactRootViewFactory`,
|
|
// we don't want to loop the ReactDelegate again. Otherwise, it will be an infinite loop.
|
|
rootView = factory.superView(
|
|
withModuleName: moduleName ?? defaultModuleName,
|
|
initialProperties: initialProps,
|
|
launchOptions: launchOptions ?? [:]
|
|
)
|
|
} else {
|
|
rootView = rootViewFactory.view(
|
|
withModuleName: moduleName ?? defaultModuleName,
|
|
initialProperties: initialProps,
|
|
launchOptions: launchOptions
|
|
)
|
|
}
|
|
|
|
return rootView
|
|
}
|
|
|
|
// MARK: - Initializing the App
|
|
#if os(iOS) || os(tvOS)
|
|
|
|
open func application(
|
|
_ application: UIApplication,
|
|
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(application, willFinishLaunchingWithOptions: launchOptions)
|
|
}
|
|
|
|
open func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
}
|
|
|
|
#elseif os(macOS)
|
|
open func applicationWillFinishLaunching(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillFinishLaunching(notification)
|
|
}
|
|
|
|
open func applicationDidFinishLaunching(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidFinishLaunching(notification)
|
|
}
|
|
|
|
// TODO: - Configuring and Discarding Scenes
|
|
#endif
|
|
|
|
// MARK: - Responding to App Life-Cycle Events
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
|
|
@objc
|
|
open func applicationDidBecomeActive(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidBecomeActive(application)
|
|
}
|
|
|
|
@objc
|
|
open func applicationWillResignActive(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillResignActive(application)
|
|
}
|
|
|
|
@objc
|
|
open func applicationDidEnterBackground(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidEnterBackground(application)
|
|
}
|
|
|
|
open func applicationWillEnterForeground(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillEnterForeground(application)
|
|
}
|
|
|
|
open func applicationWillTerminate(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillTerminate(application)
|
|
}
|
|
|
|
#elseif os(macOS)
|
|
@objc
|
|
open func applicationDidBecomeActive(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidBecomeActive(notification)
|
|
}
|
|
|
|
@objc
|
|
open func applicationWillResignActive(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillResignActive(notification)
|
|
}
|
|
|
|
@objc
|
|
open func applicationDidHide(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidHide(notification)
|
|
}
|
|
|
|
open func applicationWillUnhide(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillUnhide(notification)
|
|
}
|
|
|
|
open func applicationWillTerminate(_ notification: Notification) {
|
|
ExpoAppDelegateSubscriberManager.applicationWillTerminate(notification)
|
|
}
|
|
#endif
|
|
|
|
// MARK: - Responding to Environment Changes
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
|
|
open func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
|
|
ExpoAppDelegateSubscriberManager.applicationDidReceiveMemoryWarning(application)
|
|
}
|
|
|
|
#endif
|
|
|
|
// TODO: - Managing App State Restoration
|
|
|
|
// MARK: - Downloading Data in the Background
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
open func application(
|
|
_ application: UIApplication,
|
|
handleEventsForBackgroundURLSession identifier: String,
|
|
completionHandler: @escaping () -> Void
|
|
) {
|
|
ExpoAppDelegateSubscriberManager.application(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler)
|
|
}
|
|
|
|
#endif
|
|
|
|
// MARK: - Handling Remote Notification Registration
|
|
|
|
open func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
ExpoAppDelegateSubscriberManager.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
|
|
}
|
|
|
|
open func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
ExpoAppDelegateSubscriberManager.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
|
|
}
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
open func application(
|
|
_ application: UIApplication,
|
|
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
|
|
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
) {
|
|
ExpoAppDelegateSubscriberManager.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
|
|
}
|
|
|
|
#elseif os(macOS)
|
|
open func application(
|
|
_ application: NSApplication,
|
|
didReceiveRemoteNotification userInfo: [String: Any]
|
|
) {
|
|
ExpoAppDelegateSubscriberManager.application(application, didReceiveRemoteNotification: userInfo)
|
|
}
|
|
#endif
|
|
|
|
// MARK: - Continuing User Activity and Handling Quick Actions
|
|
|
|
open func application(_ application: UIApplication, willContinueUserActivityWithType userActivityType: String) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(application, willContinueUserActivityWithType: userActivityType)
|
|
}
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
open func application(
|
|
_ application: UIApplication,
|
|
continue userActivity: NSUserActivity,
|
|
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
|
|
) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
|
}
|
|
#elseif os(macOS)
|
|
open func application(
|
|
_ application: NSApplication,
|
|
continue userActivity: NSUserActivity,
|
|
restorationHandler: @escaping ([any NSUserActivityRestoring]) -> Void
|
|
) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
|
}
|
|
#endif
|
|
|
|
open func application(_ application: UIApplication, didUpdate userActivity: NSUserActivity) {
|
|
return ExpoAppDelegateSubscriberManager.application(application, didUpdate: userActivity)
|
|
}
|
|
|
|
open func application(_ application: UIApplication, didFailToContinueUserActivityWithType userActivityType: String, error: Error) {
|
|
return ExpoAppDelegateSubscriberManager.application(application, didFailToContinueUserActivityWithType: userActivityType, error: error)
|
|
}
|
|
|
|
#if os(iOS)
|
|
open func application(
|
|
_ application: UIApplication,
|
|
performActionFor shortcutItem: UIApplicationShortcutItem,
|
|
completionHandler: @escaping (Bool) -> Void
|
|
) {
|
|
ExpoAppDelegateSubscriberManager.application(application, performActionFor: shortcutItem, completionHandler: completionHandler)
|
|
}
|
|
#endif
|
|
|
|
// MARK: - Background Fetch
|
|
|
|
#if os(iOS) || os(tvOS)
|
|
open func application(
|
|
_ application: UIApplication,
|
|
performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
) {
|
|
ExpoAppDelegateSubscriberManager.application(application, performFetchWithCompletionHandler: completionHandler)
|
|
}
|
|
|
|
// TODO: - Interacting With WatchKit
|
|
|
|
// TODO: - Interacting With HealthKit
|
|
#endif
|
|
|
|
// MARK: - Opening a URL-Specified Resource
|
|
#if os(iOS) || os(tvOS)
|
|
|
|
open func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
|
return ExpoAppDelegateSubscriberManager.application(app, open: url, options: options)
|
|
}
|
|
#elseif os(macOS)
|
|
open func application(_ app: NSApplication, open urls: [URL]) {
|
|
ExpoAppDelegateSubscriberManager.application(app, open: urls)
|
|
}
|
|
#endif
|
|
// TODO: - Disallowing Specified App Extension Types
|
|
|
|
// TODO: - Handling SiriKit Intents
|
|
|
|
// TODO: - Handling CloudKit Invitations
|
|
|
|
// MARK: - Managing Interface Geometry
|
|
#if os(iOS)
|
|
|
|
/**
|
|
* Sets allowed orientations for the application. It will use the values from `Info.plist`as the orientation mask unless a subscriber requested
|
|
* a different orientation.
|
|
*/
|
|
open func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
|
return ExpoAppDelegateSubscriberManager.application(application, supportedInterfaceOrientationsFor: window)
|
|
}
|
|
#endif
|
|
}
|