Использование аутентификации Firebase с новым протоколом @App

#ios #firebase #swiftui

# #iOS #firebase #swiftui

Вопрос:

Я новичок в разработке iOS и изо всех сил пытаюсь внедрить аутентификацию телефона Firebase с помощью нового протокола @App в SwiftUI. Документация для Firebase написана для UIKit, а онлайн-руководства для SwiftUI используют AppDelegate и SceneDelegate вместо нового протокола @main в структуре приложения.

Мои конкретные вопросы заключаются в следующем: как / где я мог бы ввести этот класс состояния аутентификации, который я создал?

 import Foundation
class AuthenticationState: NSObject,  ObservableObject
{
    @Published var loggedInUser: User?
    @Published var isAuthenticating = false
    @Published var error: NSError?
    
    static let shared = AuthenticationState();
    
    private let auth = Auth.auth();
    fileprivate var currentNonce: String?
    
    func login(with loginOption: LoginOption) {
            self.isAuthenticating = true
            self.error = nil

            switch loginOption {
                case .signInWithApple:
                    handleSignInWithApple()
            }
        }

        func signup(email: String, password: String, passwordConfirmation: String) {
            // TODO
        }

       private func handleSignInWithApple() {
            // TODO
        }
}
    

 

Во-вторых, класс AuthenticationState не знает об объекте аутентификации Firebase, я полагаю, потому что он неправильно настроен. Пока я настраиваю Firebase в классе AppDelegate:

 import UIKit
import Firebase


class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions:
        [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    
    
    return true
  }
    
            
    
   
    }
 

В то время как у меня также есть файл MapworkApp.swift, который, как я полагаю, должен заменить AppDelegate, но я не уверен:

 import SwiftUI
import Firebase
@main
struct MapworkApp: App {
    let persistenceController = PersistenceController.shared
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

struct MapworkApp_Previews: PreviewProvider {
    static var previews: some View {
        /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
    }
}
 

Ошибки времени выполнения, которые я получаю в настоящее время:

 020-12-16 13:22:34.416917-0700 Mapwork[1351:332863] 7.3.0 - [Firebase/Core][I-COR000003] The default Firebase app has not yet been configured. Add `[FIRApp configure];` (`FirebaseApp.configure()` in Swift) to your application initialization. Read more: 
2020-12-16 13:22:34.417240-0700 Mapwork[1351:332633] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The default FIRApp instance must be configured before the default FIRAuthinstance can be initialized. One way to ensure that is to call `[FIRApp configure];` (`FirebaseApp.configure()` in Swift) in the App Delegate's `application:didFinishLaunchingWithOptions:` (`application(_:didFinishLaunchingWithOptions:)` in Swift).'
*** First throw call stack:
(0x1863a586c 0x19b314c50 0x18629e4a4 0x102bc8918 0x1028465d8 0x1028466f4 0x102845c1c 0x102845be4 0x102ec96c0 0x102ecb1f8 0x18a32c5bc 0x102845c64 0x102854aa0 0x102854cbc 0x18cdba724 0x102854c18 0x102855028 0x185fda6b0)
libc  abi.dylib: terminating with uncaught exception of type NSException
terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The default FIRApp instance must be configured before the default FIRAuthinstance can be initialized. One way to ensure that is to call `[FIRApp configure];` (`FirebaseApp.configure()` in Swift) in the App Delegate's `application:didFinishLaunchingWithOptions:` (`application(_:didFinishLaunchingWithOptions:)` in Swift).'
Message from debugger: The LLDB RPC server has exited unexpectedly. Please file a bug if you have reproducible steps.
 

Любая помощь или указания будут с благодарностью приняты, поскольку онлайн-документы теперь неприменимы.

Комментарии:

1. Вам не нужен AppDelegate. В файле MapworkApp.swift добавьте функцию init() и внутри инициализации вызовите FirebaseApp.configure() .

2. При попытке этого я получаю ошибку компилятора: «init не может использоваться в качестве ключевого слова здесь»

3. init() — это функция. Это должно выглядеть так: init() { FirebaseApp.configure()} … поместите его за пределы тела.

4. К сожалению, после этого я по-прежнему получаю те же ошибки во время выполнения, что и выше. Все равно спасибо за помощь.

Ответ №1:

Для многих API Firebase вам не нужно использовать этот AppDelegate подход. Вместо этого вам может сойти с рук инициализация Firebase в инициализаторе вашего приложения, например:

 import SwiftUI
import Firebase

@main
struct MapworkApp: App {
  init() {
    FirebaseApp.configure()
  }
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}
 

Это хорошо работает для приложений, использующих облачный Firestore и аутентификацию Firebase (войдите в систему с помощью Apple).

Для некоторых SDK Firebase вам необходимо реализовать AppDelegate . Для этого выполните AppDelegate следующее:

 class AppDelegate: NSObject, UIApplicationDelegate {
  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    print("Application is starting up. ApplicationDelegate didFinishLaunchingWithOptions.")
    return true
  }
  
  // ... add any callbacks your app might require
}
 

Затем подключите свой App к AppDelegate следующему:

 @main
struct MapworkApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
  
  init() {
    FirebaseApp.configure()
  }
  
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}
 

Возможно, вам придется переместить вызов FirebaseApp.configure() на AppDelegate . В этом случае ваш AppDelegate и App может выглядеть следующим образом (вы можете сохранить их в одном файле, если хотите):

 class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    FirebaseApp.configure()

    return true
  }
}

@main
struct MapworkApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
  
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}
 

Чтобы узнать больше об этом, ознакомьтесь с моими статьями о новом жизненном цикле приложения:

В этом примере приложения, которое я написал, показано, как создать простое приложение со списком дел с помощью SwiftUI и Firebase: peterfriese / MakeItSo. Последняя версия кода соответствует новому жизненному циклу приложения SwiftUI 2 и включает вход в систему с помощью Apple.