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
CocoaPods
- Add
pod 'Firebase/FirebaseCombineSwift'
to your podfile:
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
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
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
=
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
(
)
}
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
)