【问题标题】:SwiftUI app life cycle iOS14 where to put AppDelegate code?SwiftUI 应用生命周期 iOS14 AppDelegate 代码放哪里?
【发布时间】:2020-10-13 17:06:09
【问题描述】:

现在 AppDelegateSceneDelegate 已从 SwiftUI 中删除,我将以前在 SceneDelegateAppDelegate 中的代码放在哪里,Firebase config for ex?

所以我的AppDelegate 中有这个代码:

我现在应该把这段代码放在哪里?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    
    FirebaseConfiguration.shared.setLoggerLevel(.min)
    FirebaseApp.configure()
    return true
}

【问题讨论】:

    标签: ios firebase swiftui ios14 xcode12


    【解决方案1】:

    请注意,以下方法将停止跨平台支持,因此仅应在您计划仅为 iOS 构建时使用。

    还需要注意的是,这并没有使用 SwiftUI 生命周期方法,而是允许您返回到 UIKit 生命周期方法。

    在 Xcode 12-beta 中创建 SwiftUI 应用时,您仍然可以拥有 AppDelegate 和 SceneDelegate。

    您只需确保在创建应用时为生命周期选择了正确的选项。

    确保为生命周期选择 UIKit App Delegate,您将获得 AppDelegate 和 SceneDelegate

    【讨论】:

    • 所以目前使用 Firebase 的唯一方法就是选择 UIKit App Delegate 对吧?
    • 现有应用的生命周期选项在哪里?
    • @Imh Life Cycle 是您首次创建应用程序时可用的选项。如果您选择了 SwiftUI 应用生命周期,那么您需要从您的 <ProjectName>.swift 中删除 @main,并且您需要重新创建 AppDelegateSceneDelegate。创建一个新项目并复制代码可能会更容易。
    • 不幸的是,这个选项在 Xcode 12 Beta 6 中不可用——有什么提示吗?我想在 Xcode 11 中创建项目仍然是一回事,但必须有更好的解决方案......
    • 它在 Xcode 12-beta6 中可用。我刚刚检查过,它对我来说是存在的。
    【解决方案2】:

    我看到很多将init 用作didFinishLaunching 的解决方案。但是,didFinishLaunchingApp 结构的init 之后被调用。

    相反,我们可以创建一个块来在didFinishLaunching 被调用时通知我们。这允许在 SwiftUI 世界中保留更多代码(而不是在 AppDelegate 中)。

    class AppDelegate: NSObject, UIApplicationDelegate {
    
      var didFinishLaunching: ((AppDelegate) -> Void)?
    
      func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions
          launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
      ) -> Bool {
        didFinishLaunching?(self)
        return true
      }
    }
    
    @main
    struct MyApp: App {
      @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
      @ObservedObject private var applicationModel = ApplicationModel()
    
      // `init` gets called BEFORE `didFinishLaunchingWithOptions`
      init() {
    
        // Subscribe to get a `didFinishLaunching` call
        appDelegate.didFinishLaunching = { [weak applicationObject] appDelegate in
    
          // Setup any application code...
          applicationModel?.setup()
        }
      }
    
      var body: some Scene {
        return WindowGroup {
          if applicationObject.isUserLoggedIn {
            LoggedInView()
          } else {
            LoggedOutView()
          }
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      覆盖 App 中的初始化程序也可以:

      import SwiftUI
      import Firebase
      
      @main
      struct BookSpineApp: App {
        
        init() {
          FirebaseApp.configure()
        }
        
        var body: some Scene {
          WindowGroup {
            BooksListView()
          }
        }
      }
      

      在此处查找更详细的文章:

      【讨论】:

      • 不错的解决方案,如果我们有这样的东西呢? ` func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { GIDSignIn.sharedInstance().handle(url) }`
      • @RexhinHoxha 我认为有一个新的onOpenURL 方法可以用来做这件事(我记得在会话中看到过一个,但是我还没有让它在 b1 中工作) .
      • 我整理了一篇更详尽的文章,展示了如何在 SwiftUI 2 应用程序中初始化 Firebase:peterfriese.dev/swiftui-new-app-lifecycle-firebase
      • 我注意到,在使用它时,我在控制台上收到警告:[GoogleUtilities/AppDelegateSwizzler][I-SWZ001014] App Delegate 不符合 UIApplicationDelegate 协议。
      • 查看我的答案stackoverflow.com/a/65420572/281221,了解有关电话身份验证的详细信息,@bze12。
      【解决方案4】:

      您根本不应该将这种代码放在应用程序委托中,否则您最终将面临Massive App Delegate。相反,您应该考虑将代码重构为更有意义的部分,然后将正确的部分放在正确的位置。对于这种情况,您唯一需要做的就是确保在应用程序准备就绪后代码正在执行这些功能并且只执行一次。所以init 方法可能很棒:

      @main
      struct MyApp: App {
          init() {
              setupFirebase()
          }
      
          var body: some Scene {
              WindowGroup {
                  ContentView()
              }
          }
      }
      
      private extension MyApp {
          func setupFirebase() {
              FirebaseConfiguration.shared.setLoggerLevel(.min)
              FirebaseApp.configure()
          }
      }
      

      AppDelegate ?

      您可以拥有自己的自定义类并将其分配为delegate。但请注意,它不适用于分配之前发生的事件。例如:

      class CustomDelegate: NSObject, UIApplicationDelegate {
          static let Shared = CustomDelegate()
      }
      

      后来:

      UIApplication.shared.delegate = CustomDelegate.Shared
      

      观察通知

      大多数AppDelegate 方法实际上是在观察通知,您可以手动观察而不是定义新类。例如:

      NotificationCenter.default.addObserver(
          self,
          selector: #selector(<#T##@objc method#>),
          name: UIApplication.didBecomeActiveNotification,
          object: nil
      )
      

      原生 AppDelegate Wrapper

      您可以直接将应用委托注入@main 结构:

      @UIApplicationDelegateAdaptor(CustomDelegate.self) var appDelegate
      

      注意:使用AppDelegate

      请记住,添加 AppDelegate 意味着您正在取消默认的多平台支持,您必须手动检查平台。

      【讨论】:

      • 这段代码呢?我把它放在哪里? func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -&gt; Bool { GIDSignIn.sharedInstance().handle(url) }
      • 我已经在我的回答中添加了更多详细信息。
      • 看起来比它需要的复杂得多。最好只是等待 Google 解决他们正在解决的棘手问题。
      • 如何为 didReceiveRemoteNotification 生成组合发布者?请您在stackoverflow.com/questions/64512868/… 回答我的问题
      • “杀死默认的多平台支持”你指的是哪些平台?
      【解决方案5】:

      您还可以将新的 ScenePhase 用于 AppDelegate 和 SceneDelegate 拥有的某些代码。喜欢去后台或变得活跃。来自

      struct PodcastScene: Scene {
          @Environment(\.scenePhase) private var phase
      
          var body: some Scene {
              WindowGroup {
                  TabView {
                      LibraryView()
                      DiscoverView()
                      SearchView()
                  }
              }
              .onChange(of: phase) { newPhase in
                  switch newPhase {
                  case .active:
                      // App became active
                  case .inactive:
                      // App became inactive
                  case .background:
                      // App is running in the background
                  @unknown default:
                      // Fallback for future cases
                  }
              }
          }
      }
      

      示例信用:https://wwdcbysundell.com/2020/building-entire-apps-with-swiftui/

      【讨论】:

      • 当我将FirebaseApp.configure() 放在case .active 中时,我得到'Failed to get FirebaseApp instance. Please call FirebaseApp.configure() before using Firestore' terminating with uncaught exception of type NSException
      • 您可以尝试使用 init() { FirebaseApp.configure() } 配置 Firebase,如其他答案之一所示
      【解决方案6】:

      这是 SwiftUI 生命周期的解决方案。使用 Xcode 12b / iOS 14 测试

      import SwiftUI
      import UIKit
      
      // no changes in your AppDelegate class
      class AppDelegate: NSObject, UIApplicationDelegate {
          func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
              print(">> your code here !!")
              return true
          }
      }
      
      @main
      struct Testing_SwiftUI2App: App {
      
          // inject into SwiftUI life-cycle via adaptor !!!
          @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
      
          var body: some Scene {
              WindowGroup {
                  ContentView()
              }
          }
      }
      

      【讨论】:

      • 太棒了,知道如何更新现有应用程序以使用 SwiftUI 生命周期吗?
      • @RexhinHoxha,将部署目标设置为 iOS 14,从 AppDelegate 中删除 @UIApplicationMain,并添加 is-a App 结构,如上。
      • 对不起,我知道这个问题有点老了,但我正在尝试利用它来更改导航栏背景。这可以用 SwiftUI 来完成吗,把正常的 UINavigationBar.appearance().barTintColor = UIColor.red 放在它说 &gt;&gt; your code here !! 的地方
      猜你喜欢
      • 1970-01-01
      • 2020-10-18
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 2017-09-16
      • 1970-01-01
      • 2016-08-26
      • 1970-01-01
      相关资源
      最近更新 更多