2021-01-14 23:37:01 +01:00
# Combine Support for Firebase
2021-02-26 22:19:01 +01:00
This module contains Combine support for Firebase APIs.
2021-01-14 23:37:01 +01:00
2021-10-01 10:41:09 +02:00
**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 )
2021-04-19 18:56:52 +02:00
2021-01-14 23:37:01 +01:00
## Installation
<details><summary>CocoaPods</summary>
* 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
```
</details>
<details><summary>Swift Package Manager</summary>
* Follow the instructions in [Swift Package Manager for Firebase Beta
2021-10-01 10:41:09 +02:00
](../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
2021-01-14 23:37:01 +01:00
</details>
## 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 )
2021-01-23 14:08:17 +01:00
```
2021-02-26 22:19:01 +01:00
#### Sign in with a given 3rd-party credentials
2021-01-23 14:08:17 +01:00
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:
2021-02-26 22:19:01 +01:00
```swift
2021-01-23 14:08:17 +01:00
func sign ( _ signIn : GIDSignIn !, didSignInFor user : GIDGoogleUser !, withError error : Error ?) {
// ...
2024-05-03 17:50:20 +02:00
if let error {
2021-01-23 14:08:17 +01:00
// ...
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 )
2021-02-26 22:19:01 +01:00
}
2021-01-23 14:08:17 +01:00
private func handleError ( _ error : NSError ) throws -> AnyPublisher < AuthDataResult , Error > {
guard isMFAEnabled && error . code == AuthErrorCode . secondFactorRequired . rawValue
else { throw error }
2021-02-26 22:19:01 +01:00
2021-01-23 14:08:17 +01:00
// 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 : " " )
2021-02-26 22:19:01 +01:00
2021-01-23 14:08:17 +01:00
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
2021-02-26 22:19:01 +01:00
let credential = PhoneAuthProvider . provider (). credential ( withVerificationID : verificationID ,
2021-01-23 14:08:17 +01:00
verificationCode : verificationCode )
return PhoneMultiFactorGenerator . assertion ( with : credential )
}
}
. flatMap { assertion in
resolver . resolveSignIn ( withAssertion : assertion )
2021-02-26 22:19:01 +01:00
}
2021-01-23 14:08:17 +01:00
. eraseToAnyPublisher ()
}
```
2021-02-26 22:19:01 +01:00
### 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 )
```