AuthDefaultUIDelegate.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #if os(iOS) || os(tvOS)
  15. import Foundation
  16. import UIKit
  17. #if COCOAPODS
  18. internal import GoogleUtilities
  19. #else
  20. internal import GoogleUtilities_Environment
  21. #endif
  22. /// Class responsible for providing a default AuthUIDelegate.
  23. ///
  24. /// This class should be used in the case that a UIDelegate was expected and necessary to
  25. /// continue a given flow, but none was provided.
  26. final class AuthDefaultUIDelegate: NSObject, AuthUIDelegate {
  27. /// Returns a default AuthUIDelegate object.
  28. /// - Returns: The default AuthUIDelegate object.
  29. @MainActor static func defaultUIDelegate() -> AuthUIDelegate? {
  30. if GULAppEnvironmentUtil.isAppExtension() {
  31. // iOS App extensions should not call [UIApplication sharedApplication], even if
  32. // UIApplication responds to it.
  33. return nil
  34. }
  35. // Using reflection here to avoid build errors in extensions.
  36. let sel = NSSelectorFromString("sharedApplication")
  37. guard UIApplication.responds(to: sel),
  38. let rawApplication = UIApplication.perform(sel),
  39. let application = rawApplication.takeUnretainedValue() as? UIApplication else {
  40. return nil
  41. }
  42. var topViewController: UIViewController?
  43. if #available(iOS 13.0, tvOS 13.0, *) {
  44. let connectedScenes = application.connectedScenes
  45. for scene in connectedScenes {
  46. if let windowScene = scene as? UIWindowScene {
  47. for window in windowScene.windows {
  48. if window.isKeyWindow {
  49. topViewController = window.rootViewController
  50. }
  51. }
  52. }
  53. }
  54. } else {
  55. topViewController = application.keyWindow?.rootViewController
  56. }
  57. while true {
  58. if let controller = topViewController?.presentedViewController {
  59. topViewController = controller
  60. } else if let navController = topViewController as? UINavigationController {
  61. topViewController = navController.topViewController
  62. } else if let tabBarController = topViewController as? UITabBarController {
  63. topViewController = tabBarController.selectedViewController
  64. } else {
  65. break
  66. }
  67. }
  68. return AuthDefaultUIDelegate(withViewController: topViewController)
  69. }
  70. init(withViewController viewController: UIViewController?) {
  71. self.viewController = viewController
  72. }
  73. func present(_ viewControllerToPresent: UIViewController, animated flag: Bool,
  74. completion: (() -> Void)? = nil) {
  75. viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
  76. }
  77. func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
  78. viewController?.dismiss(animated: flag, completion: completion)
  79. }
  80. private let viewController: UIViewController?
  81. }
  82. #endif