Ben Hagen b7db7b4492 [Auth] TOTP support for macOS (#15112) il y a 7 mois
..
Sources b7db7b4492 [Auth] TOTP support for macOS (#15112) il y a 7 mois
Tests 907df98c61 [Infra] Add `@unchecked` Sendable to `MockQuery` (#15124) il y a 8 mois
CHANGELOG.md ed8b815aeb [Auth] Remove wrapper API that uses deprecated Auth API (#15060) il y a 9 mois
DECISIONS.md 36a3f1b85e Fix typo of the FirebaseCombineSwift files (#13347) il y a 1 an
DEVELOPING.md ffa115847c Add development documentation il y a 5 ans
README.md e8a12e04c2 Improve/use shorthand syntax for unwrapping optionals and fix typos (#12369) il y a 1 an

README.md

Combine Support for Firebase

This module contains Combine support for Firebase APIs.

Note: This feature is under development and is supported only on a community basis. You can follow development on the project tracker

Installation

CocoaPods * Add `pod 'Firebase/FirebaseCombineSwift'` to your podfile: ```Ruby platform :ios, '14.0' target 'YourApp' do use_frameworks! pod 'Firebase/Auth' pod 'Firebase/Analytics' pod 'Firebase/FirebaseCombineSwift' end ```
Swift Package Manager * Follow the instructions in [Swift Package Manager for Firebase Beta ](../SwiftPackageManager.md) to add Firebase to your project * Make sure to import all of the following packages you intend to use: * FirebaseAuthCombine-Community * FirebaseFirestoreCombine-Community * FirebaseFunctionsCombine-Community * FirebaseStorageCombine-Community * In your code, import the respective module: * FirebaseAuthCombineSwift * FirebaseFirestoreCombineSwift * FirebaseFunctionsCombineSwift * FirebaseStorageCombineSwift

Usage

Auth

Sign in anonymously

  Auth.auth().signInAnonymously()
    .sink { completion in
      switch completion {
      case .finished:
        print("Finished")
      case let .failure(error):
        print("\(error.localizedDescription)")
      }
    } receiveValue: { authDataResult in
    }
    .store(in: &cancellables)
  Auth.auth().signInAnonymously()
    .map { result in
      result.user.uid
    }
    .replaceError(with: "(unable to sign in anonymously)")
    .assign(to: \.uid, on: self)
    .store(in: &cancellables)

Sign in with a given 3rd-party credentials

In the sign(_:didSignInFor:withError:) method, get a Google ID token and Google access token from the GIDAuthentication object and asynchronously exchange them for a Firebase credential:

  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
    // ...
    if let error {
      // ...
      return
    }

    guard let authentication = user.authentication else { return }
    let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                   accessToken: authentication.accessToken)
    Auth.auth()
      .signIn(withCredential: credential)
      .mapError { $0 as NSError }
      .tryCatch(handleError)
      .sink { /* ... */ } receiveValue: {  /* ... */  }
      .store(in: &subscriptions)
  }

  private func handleError(_ error: NSError) throws -> AnyPublisher<AuthDataResult, Error> {
    guard isMFAEnabled && error.code == AuthErrorCode.secondFactorRequired.rawValue
    else { throw error }

    // The user is a multi-factor user. Second factor challenge is required.
    let resolver = error.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
    let displayNameString = resolver.hints.compactMap(\.displayName).joined(separator: " ")

    return showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)")
      .compactMap { displayName in
        resolver.hints.first(where: { displayName == $0.displayName }) as? PhoneMultiFactorInfo
      }
      .flatMap { [unowned self] factorInfo in
        PhoneAuthProvider.provider()
          .verifyPhoneNumber(withMultiFactorInfo: factorInfo, multiFactorSession: resolver.session)
          .zip(self.showTextInputPrompt(withMessage: "Verification code for \(factorInfo.displayName ?? "")"))
          .map { (verificationID, verificationCode) in
            let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID,
                                                                     verificationCode: verificationCode)
            return PhoneMultiFactorGenerator.assertion(with: credential)
          }
      }
      .flatMap { assertion in
        resolver.resolveSignIn(withAssertion: assertion)
      }
      .eraseToAnyPublisher()
  }

Functions

let helloWorld = Functions.functions().httpsCallable("helloWorld")
helloWorld.call()
  .sink { completion in
    switch completion {
      case .finished:
        print("Finished")
      case let .failure(error):
        print("\(error.localizedDescription)")
    }
  } receiveValue: { functionResult in
    if let result = functionResult.data as? String {
      print("The function returned: \(result)")
    }
  }
  .store(in: &cancellables)
let helloWorld = Functions.functions().httpsCallable("helloWorld")
helloWorld.call("Peter")
  .sink { completion in
    switch completion {
      case .finished:
        print("Finished")
      case let .failure(error):
        print("\(error.localizedDescription)")
    }
  } receiveValue: { functionResult in
    if let result = functionResult.data as? String {
      print("The function returned: \(result)")
    }
  }
  .store(in: &cancellables)