# 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](https://github.com/firebase/firebase-ios-sdk/projects/3)
## 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
```swift
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)
```
```swift
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:
```swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
// ...
if let error = 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 {
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
```swift
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)
```
```swift
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)
```