Skip to content

Commit dfbfbee

Browse files
Merge pull request #1249 from firebase/facebook-google-phone-buttons
2 parents 3f2551e + dcda464 commit dfbfbee

File tree

11 files changed

+73
-34
lines changed

11 files changed

+73
-34
lines changed

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Services/AuthService.swift

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import SwiftUI
33

44
public protocol ExternalAuthProvider {
5-
associatedtype ButtonType: View
6-
@MainActor var authButton: ButtonType { get }
5+
var id: String { get }
6+
@MainActor func authButton() -> AnyView
77
}
88

99
public protocol GoogleProviderAuthUIProtocol: ExternalAuthProvider {
@@ -65,15 +65,9 @@ private final class AuthListenerManager {
6565
@MainActor
6666
@Observable
6767
public final class AuthService {
68-
public init(configuration: AuthConfiguration = AuthConfiguration(), auth: Auth = Auth.auth(),
69-
googleProvider: (any GoogleProviderAuthUIProtocol)? = nil,
70-
facebookProvider: (any FacebookProviderAuthUIProtocol)? = nil,
71-
phoneAuthProvider: (any PhoneAuthProviderAuthUIProtocol)? = nil) {
68+
public init(configuration: AuthConfiguration = AuthConfiguration(), auth: Auth = Auth.auth()) {
7269
self.auth = auth
7370
self.configuration = configuration
74-
self.googleProvider = googleProvider
75-
self.facebookProvider = facebookProvider
76-
self.phoneAuthProvider = phoneAuthProvider
7771
string = StringUtils(bundle: configuration.customStringsBundle ?? Bundle.module)
7872
listenerManager = AuthListenerManager(auth: auth, authEnvironment: self)
7973
}
@@ -96,6 +90,21 @@ public final class AuthService {
9690
private var listenerManager: AuthListenerManager?
9791
private var signedInCredential: AuthCredential?
9892

93+
private var providers: [ExternalAuthProvider] = []
94+
public func register(provider: ExternalAuthProvider) {
95+
providers.append(provider)
96+
}
97+
98+
public func renderButtons(spacing: CGFloat = 16) -> AnyView {
99+
AnyView(
100+
VStack(spacing: spacing) {
101+
ForEach(providers, id: \.id) { provider in
102+
provider.authButton()
103+
}
104+
}
105+
)
106+
}
107+
99108
private var safeGoogleProvider: any GoogleProviderAuthUIProtocol {
100109
get throws {
101110
guard let provider = googleProvider else {

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Strings/Localizable.xcstrings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,9 @@
10471047
}
10481048
}
10491049
}
1050+
},
1051+
"Update password" : {
1052+
10501053
},
10511054
"UpdateEmailAlertMessage" : {
10521055
"comment" : "Alert action message shown before updating email action. Use short/abbreviated translation for 'email' which is less than 15 chars.",

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/AuthPickerView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension AuthPickerView: View {
2828
Text(authService.authenticationFlow == .login ? "Login" : "Sign up")
2929
VStack { Divider() }
3030
EmailAuthView()
31-
providerButtons()
31+
authService.renderButtons()
3232
VStack { Divider() }
3333
HStack {
3434
Text(authService
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// AuthService+Facebook.swift
3+
// FirebaseUI
4+
//
5+
// Created by Russell Wheatley on 01/05/2025.
6+
//
7+
8+
import FirebaseAuthSwiftUI
9+
10+
public extension AuthService {
11+
@discardableResult
12+
func withFacebookSignIn(scopes scopes: [String]? = nil) -> AuthService {
13+
facebookProvider = FacebookProviderAuthUI(scopes: scopes)
14+
register(provider: facebookProvider!)
15+
return self
16+
}
17+
}

FirebaseSwiftUI/FirebaseFacebookSwiftUI/Sources/Services/FacebookProviderAuthUI.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public enum FacebookProviderError: Error {
2222
}
2323

2424
public class FacebookProviderAuthUI: FacebookProviderAuthUIProtocol {
25+
public let id: String = "facebook"
2526
let scopes: [String]
2627
let shortName = "Facebook"
2728
let providerId = "facebook.com"
@@ -35,8 +36,8 @@ public class FacebookProviderAuthUI: FacebookProviderAuthUIProtocol {
3536
shaNonce = CommonUtils.sha256Hash(of: rawNonce)
3637
}
3738

38-
@MainActor public var authButton: SignInWithFacebookButton {
39-
return SignInWithFacebookButton()
39+
@MainActor public func authButton() -> AnyView {
40+
AnyView(SignInWithFacebookButton())
4041
}
4142

4243
@MainActor public func signInWithFacebook(isLimitedLogin: Bool) async throws -> AuthCredential {

FirebaseSwiftUI/FirebaseGoogleSwiftUI/Sources/Services/AuthService+Google.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import FirebaseAuthSwiftUI
99

1010
public extension AuthService {
1111
@discardableResult
12-
func withGoogleSignIn() -> AuthService {
12+
func withGoogleSignIn(scopes scopes: [String]? = nil) -> AuthService {
1313
let clientID = auth.app?.options.clientID ?? ""
14-
googleProvider = GoogleProviderAuthUI(clientID: clientID)
14+
googleProvider = GoogleProviderAuthUI(scopes: scopes, clientID: clientID)
15+
register(provider: googleProvider!)
1516
return self
1617
}
1718
}

FirebaseSwiftUI/FirebaseGoogleSwiftUI/Sources/Services/GoogleProviderAuthUI.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public enum GoogleProviderError: Error {
1616
}
1717

1818
public class GoogleProviderAuthUI: @preconcurrency GoogleProviderAuthUIProtocol {
19+
public let id: String = "google"
1920
let scopes: [String]
2021
let shortName = "Google"
2122
let providerId = "google.com"
@@ -25,12 +26,12 @@ public class GoogleProviderAuthUI: @preconcurrency GoogleProviderAuthUIProtocol
2526
self.clientID = clientID
2627
}
2728

28-
@MainActor public var authButton: GoogleSignInButton {
29-
return GoogleSignInButton {
29+
@MainActor public func authButton() -> AnyView {
30+
AnyView(GoogleSignInButton {
3031
Task {
3132
try await self.signInWithGoogle(clientID: self.clientID)
3233
}
33-
}
34+
})
3435
}
3536

3637
@MainActor public func signInWithGoogle(clientID: String) async throws -> AuthCredential {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// AuthService+Phone.swift
3+
// FirebaseUI
4+
//
5+
// Created by Russell Wheatley on 09/05/2025.
6+
//
7+
8+
import FirebaseAuthSwiftUI
9+
10+
public extension AuthService {
11+
@discardableResult
12+
func withPhoneSignIn() -> AuthService {
13+
phoneAuthProvider = PhoneAuthProviderAuthUI()
14+
register(provider: phoneAuthProvider!)
15+
return self
16+
}
17+
}

FirebaseSwiftUI/FirebasePhoneAuthSwiftUI/Sources/Services/PhoneAuthProviderAuthUI.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import SwiftUI
55
public typealias VerificationID = String
66

77
public class PhoneAuthProviderAuthUI: @preconcurrency PhoneAuthProviderAuthUIProtocol {
8-
public var authButton: Button<Text> {
9-
// TODO: implement me
10-
return Button("Phone", action: {})
11-
}
8+
public let id: String = "phone"
129

13-
public init() {}
10+
@MainActor public func authButton() -> AnyView {
11+
AnyView(PhoneAuthButtonView())
12+
}
1413

1514
@MainActor public func verifyPhoneNumber(phoneNumber: String) async throws -> VerificationID {
1615
return try await withCheckedThrowingContinuation { continuation in

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/ContentView.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,16 @@ struct ContentView: View {
2828
shouldAutoUpgradeAnonymousUsers: true,
2929
emailLinkSignInActionCodeSettings: actionCodeSettings
3030
)
31-
let facebookProvider = FacebookProviderAuthUI()
32-
let phoneAuthProvider = PhoneAuthProviderAuthUI()
3331
authService = AuthService(
34-
configuration: configuration,
35-
facebookProvider: facebookProvider,
36-
phoneAuthProvider: phoneAuthProvider
32+
configuration: configuration
3733
)
3834
.withGoogleSignIn()
35+
.withFacebookSignIn()
36+
.withPhoneSignIn()
3937
}
4038

4139
var body: some View {
4240
AuthPickerView {
43-
SignInWithGoogleButton()
44-
SignInWithFacebookButton()
4541
PhoneAuthButtonView()
4642
}.environment(authService)
4743
}

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/FirebaseSwiftUIExampleApp.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
import FacebookCore
88
import FirebaseAuth
99
import FirebaseCore
10-
import FirebaseGoogleSwiftUI
11-
import FirebasePhoneAuthSwiftUI
1210
import GoogleSignIn
13-
import SwiftData
1411
import SwiftUI
1512

1613
class AppDelegate: NSObject, UIApplicationDelegate {
@@ -61,8 +58,6 @@ class AppDelegate: NSObject, UIApplicationDelegate {
6158
struct FirebaseSwiftUIExampleApp: App {
6259
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
6360

64-
init() {}
65-
6661
var body: some Scene {
6762
WindowGroup {
6863
NavigationView {

0 commit comments

Comments
 (0)