Skip to content

refactor: follow up PR with updates based on feedback #1244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 8, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ public protocol ExternalAuthProvider {
@MainActor var authButton: ButtonType { get }
}

public protocol GoogleProviderProtocol: ExternalAuthProvider {
public protocol GoogleProviderAuthUIProtocol: ExternalAuthProvider {
@MainActor func signInWithGoogle(clientID: String) async throws -> AuthCredential
}

public protocol FacebookProviderProtocol: ExternalAuthProvider {
public protocol FacebookProviderAuthUIProtocol: ExternalAuthProvider {
@MainActor func signInWithFacebook(isLimitedLogin: Bool) async throws -> AuthCredential
}

public protocol PhoneAuthProviderProtocol: ExternalAuthProvider {
public protocol PhoneAuthProviderAuthUIProtocol: ExternalAuthProvider {
@MainActor func verifyPhoneNumber(phoneNumber: String) async throws -> String
}

Expand Down Expand Up @@ -66,9 +66,9 @@ private final class AuthListenerManager {
@Observable
public final class AuthService {
public init(configuration: AuthConfiguration = AuthConfiguration(), auth: Auth = Auth.auth(),
googleProvider: (any GoogleProviderProtocol)? = nil,
facebookProvider: (any FacebookProviderProtocol)? = nil,
phoneAuthProvider: (any PhoneAuthProviderProtocol)? = nil) {
googleProvider: (any GoogleProviderAuthUIProtocol)? = nil,
facebookProvider: (any FacebookProviderAuthUIProtocol)? = nil,
phoneAuthProvider: (any PhoneAuthProviderAuthUIProtocol)? = nil) {
self.auth = auth
self.configuration = configuration
self.googleProvider = googleProvider
Expand All @@ -89,14 +89,14 @@ public final class AuthService {
public var errorMessage = ""
public let passwordPrompt: PasswordPromptCoordinator = .init()

public var googleProvider: (any GoogleProviderProtocol)?
public var facebookProvider: (any FacebookProviderProtocol)?
public var phoneAuthProvider: (any PhoneAuthProviderProtocol)?
public var googleProvider: (any GoogleProviderAuthUIProtocol)?
public var facebookProvider: (any FacebookProviderAuthUIProtocol)?
public var phoneAuthProvider: (any PhoneAuthProviderAuthUIProtocol)?

private var listenerManager: AuthListenerManager?
private var signedInCredential: AuthCredential?

private var safeGoogleProvider: any GoogleProviderProtocol {
private var safeGoogleProvider: any GoogleProviderAuthUIProtocol {
get throws {
guard let provider = googleProvider else {
throw AuthServiceError
Expand All @@ -106,7 +106,7 @@ public final class AuthService {
}
}

private var safeFacebookProvider: any FacebookProviderProtocol {
private var safeFacebookProvider: any FacebookProviderAuthUIProtocol {
get throws {
guard let provider = facebookProvider else {
throw AuthServiceError
Expand All @@ -116,7 +116,7 @@ public final class AuthService {
}
}

private var safePhoneAuthProvider: any PhoneAuthProviderProtocol {
private var safePhoneAuthProvider: any PhoneAuthProviderAuthUIProtocol {
get throws {
guard let provider = phoneAuthProvider else {
throw AuthServiceError
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CommonCrypto
import FirebaseCore
import Foundation
import Security

Expand Down Expand Up @@ -47,3 +48,20 @@ public class CommonUtils {
return hash.map { String(format: "%02x", $0) }.joined()
}
}

public extension FirebaseOptions {
static func dummyConfigurationForPreview() {
guard FirebaseApp.app() == nil else { return }

let options = FirebaseOptions(
googleAppID: "1:123:ios:123abc456def7890",
gcmSenderID: "dummy"
)
options.apiKey = "dummy"
options.projectID = "dummy-project-id"
options.bundleID = Bundle.main.bundleIdentifier ?? "com.example.dummy"
options.clientID = "dummy-abc.apps.googleusercontent.com"

FirebaseApp.configure(options: options)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Russell Wheatley on 20/03/2025.
//
import FirebaseAuth
import FirebaseCore
import SwiftUI

private enum FocusableField: Hashable {
Expand Down Expand Up @@ -132,3 +133,9 @@ extension EmailAuthView: View {
}
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return EmailAuthView()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import FirebaseAuth
import FirebaseCore
import SwiftUI

public struct EmailLinkView {
Expand Down Expand Up @@ -74,3 +75,9 @@ extension EmailLinkView: View {
})
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return EmailLinkView()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ extension PasswordPromptSheet: View {
.padding()
}
}

#Preview {
PasswordPromptSheet(coordinator: PasswordPromptCoordinator())
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import FirebaseCore
import SwiftUI

public struct PasswordRecoveryView {
Expand Down Expand Up @@ -67,3 +68,9 @@ extension PasswordRecoveryView: View {
})
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return PasswordRecoveryView()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import FirebaseCore
import SwiftUI

@MainActor
Expand Down Expand Up @@ -51,3 +52,9 @@ extension SignedInView: View {
}
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return SignedInView()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import FirebaseCore
import SwiftUI

public struct VerifyEmailView {
Expand Down Expand Up @@ -42,3 +43,9 @@ extension VerifyEmailView: View {
}
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return VerifyEmailView()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum FacebookProviderError: Error {
case authenticationToken(String)
}

public class FacebookProviderSwift: FacebookProviderProtocol {
public class FacebookProviderAuthUI: FacebookProviderAuthUIProtocol {
let scopes: [String]
let shortName = "Facebook"
let providerId = "facebook.com"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import FacebookCore
import FacebookLogin
import FirebaseAuth
import FirebaseAuthSwiftUI
import FirebaseCore
import SwiftUI

@MainActor
Expand Down Expand Up @@ -108,3 +109,9 @@ extension SignInWithFacebookButton: View {
Text(errorMessage).foregroundColor(.red)
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return SignInWithFacebookButton()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import FirebaseAuthSwiftUI

public extension AuthService {

@discardableResult
public func withGoogleSignIn() -> AuthService {
func withGoogleSignIn() -> AuthService {
let clientID = auth.app?.options.clientID ?? ""
self.googleProvider = GoogleProviderSwift(clientID: clientID)
googleProvider = GoogleProviderAuthUI(clientID: clientID)
return self
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum GoogleProviderError: Error {
case user(String)
}

public class GoogleProviderSwift: @preconcurrency GoogleProviderProtocol {
public class GoogleProviderAuthUI: @preconcurrency GoogleProviderAuthUIProtocol {
let scopes: [String]
let shortName = "Google"
let providerId = "google.com"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import FirebaseAuthSwiftUI
import FirebaseCore
import SwiftUI

@MainActor
Expand Down Expand Up @@ -49,3 +50,9 @@ extension SignInWithGoogleButton: View {
}
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return SignInWithGoogleButton()
.environment(AuthService())
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import SwiftUI

public typealias VerificationID = String

public class PhoneAuthProviderSwift: @preconcurrency PhoneAuthProviderProtocol {

public class PhoneAuthProviderAuthUI: @preconcurrency PhoneAuthProviderAuthUIProtocol {
public var authButton: Button<Text> {
// TODO: implement me
return Button("Phone", action: { })
return Button("Phone", action: {})
}

public init() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import FirebaseAuthSwiftUI
import FirebaseCore
import SwiftUI

@MainActor
Expand Down Expand Up @@ -90,3 +91,9 @@ extension PhoneAuthButtonView: View {
Text(errorMessage).foregroundColor(.red)
}
}

#Preview {
FirebaseOptions.dummyConfigurationForPreview()
return PhoneAuthButtonView()
.environment(AuthService())
}
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ let package = Package(
dependencies: [
"FirebaseAuthSwiftUI",
"GoogleSignIn",
.product(name: "GoogleSignInSwift", package: "GoogleSignIn")
.product(name: "GoogleSignInSwift", package: "GoogleSignIn"),
],
path: "FirebaseSwiftUI/FirebaseGoogleSwiftUI/Sources"
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// ContentView.swift
// FirebaseSwiftUIExample
//
// Created by Russell Wheatley on 23/04/2025.
//

import FirebaseAuth
import FirebaseAuthSwiftUI
import FirebaseFacebookSwiftUI
import FirebaseGoogleSwiftUI
import FirebasePhoneAuthSwiftUI
import SwiftUI

struct ContentView: View {
let authService: AuthService

init() {
Auth.auth().signInAnonymously()

let actionCodeSettings = ActionCodeSettings()
actionCodeSettings.handleCodeInApp = true
actionCodeSettings
.url = URL(string: "https://flutterfire-e2e-tests.firebaseapp.com")
actionCodeSettings.linkDomain = "flutterfire-e2e-tests.firebaseapp.com"
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
let configuration = AuthConfiguration(
shouldAutoUpgradeAnonymousUsers: true,
emailLinkSignInActionCodeSettings: actionCodeSettings
)
let facebookProvider = FacebookProviderAuthUI()
let phoneAuthProvider = PhoneAuthProviderAuthUI()
authService = AuthService(
configuration: configuration,
facebookProvider: facebookProvider,
phoneAuthProvider: phoneAuthProvider
)
.withGoogleSignIn()
}

var body: some View {
AuthPickerView {
SignInWithGoogleButton()
SignInWithFacebookButton()
PhoneAuthButtonView()
}.environment(authService)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
//
// Created by Russell Wheatley on 18/02/2025.
//

import FacebookCore
import FirebaseAuth
import FirebaseAuthSwiftUI
import FirebaseCore
import FirebaseFacebookSwiftUI
import FirebaseGoogleSwiftUI
import FirebasePhoneAuthSwiftUI
import GoogleSignIn
Expand Down Expand Up @@ -74,40 +71,3 @@ struct FirebaseSwiftUIExampleApp: App {
}
}
}

struct ContentView: View {
let authService: AuthService

init() {
// Auth.auth().signInAnonymously()

let actionCodeSettings = ActionCodeSettings()
actionCodeSettings.handleCodeInApp = true
actionCodeSettings
.url = URL(string: "https://flutterfire-e2e-tests.firebaseapp.com")
actionCodeSettings.linkDomain = "flutterfire-e2e-tests.firebaseapp.com"
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
let configuration = AuthConfiguration(
shouldAutoUpgradeAnonymousUsers: true,
emailLinkSignInActionCodeSettings: actionCodeSettings
)
let facebookProvider = FacebookProviderSwift()
let phoneAuthProvider = PhoneAuthProviderSwift()
authService = AuthService(
configuration: configuration,
googleProvider: nil,
facebookProvider: facebookProvider,
phoneAuthProvider: phoneAuthProvider
)
// Transition to this api
.withGoogleSignIn()
}

var body: some View {
AuthPickerView {
SignInWithGoogleButton()
SignInWithFacebookButton()
PhoneAuthButtonView()
}.environment(authService)
}
}
Loading