Skip to content
2 changes: 1 addition & 1 deletion FirebaseStorageUI/Sources/FUIStorageImageLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ - (BOOL)canRequestImageForURL:(NSURL *)url {
BOOL finished = receivedSize >= expectedSize;
if (coderQueue.operationCount == 0) {
[coderQueue addOperationWithBlock:^{
UIImage *image = SDImageLoaderDecodeProgressiveImageData(partialData, url, finished, task, options, context);
UIImage *image = SDImageLoaderDecodeProgressiveImageData(partialData, url, finished, (id<SDWebImageOperation>)task, options, context);
if (image) {
dispatch_main_async_safe(^{
if (completedBlock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import FirebaseAuth
import SwiftUI

/// Context information for OAuth provider reauthentication (Google, Apple, Facebook, Twitter, etc.)
public struct OAuthReauthContext: Equatable {
public struct OAuthReauthContext: Equatable, Sendable {
public let providerId: String
public let providerName: String

Expand All @@ -31,7 +31,7 @@ public struct OAuthReauthContext: Equatable {
}

/// Context information for email/password reauthentication
public struct EmailReauthContext: Equatable {
public struct EmailReauthContext: Equatable, Sendable {
public let email: String

public init(email: String) {
Expand All @@ -44,7 +44,7 @@ public struct EmailReauthContext: Equatable {
}

/// Context information for email link reauthentication
public struct EmailLinkReauthContext: Equatable {
public struct EmailLinkReauthContext: Equatable, Sendable {
public let email: String

public init(email: String) {
Expand All @@ -57,7 +57,7 @@ public struct EmailLinkReauthContext: Equatable {
}

/// Context information for phone number reauthentication
public struct PhoneReauthContext: Equatable {
public struct PhoneReauthContext: Equatable, Sendable {
public let phoneNumber: String

public init(phoneNumber: String) {
Expand All @@ -70,7 +70,7 @@ public struct PhoneReauthContext: Equatable {
}

/// Type-safe wrapper for reauthentication contexts
public enum ReauthenticationType: Equatable {
public enum ReauthenticationType: Equatable, Sendable {
case oauth(OAuthReauthContext)
case email(EmailReauthContext)
case emailLink(EmailLinkReauthContext)
Expand All @@ -91,7 +91,7 @@ public enum ReauthenticationType: Equatable {
}

/// Describes the specific type of account conflict that occurred
public enum AccountConflictType: Equatable {
public enum AccountConflictType: Equatable, Sendable {
/// Account exists with a different provider (e.g., user signed up with Google, trying to use
/// email)
/// Solution: Sign in with existing provider, then link the new credential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public final class AuthService {
}

public func signOut() async throws {
try await auth.signOut()
try auth.signOut()
// Cannot wait for auth listener to change, feedback needs to be immediate
currentUser = nil
// Clear email link sign-in flag
Expand All @@ -239,7 +239,7 @@ public final class AuthService {
updateAuthenticationState()
}

public func linkAccounts(credentials credentials: AuthCredential) async throws {
public func linkAccounts(credentials: AuthCredential) async throws {
authenticationState = .authenticating
do {
guard let user = currentUser else {
Expand Down Expand Up @@ -414,7 +414,7 @@ public extension AuthService {
}
}

func createUser(email email: String, password: String) async throws -> SignInOutcome {
func createUser(email: String, password: String) async throws -> SignInOutcome {
authenticationState = .authenticating
let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Expand Down Expand Up @@ -474,7 +474,7 @@ public extension AuthService {
}
}

func handleSignInLink(url url: URL) async throws {
func handleSignInLink(url: URL) async throws {
do {
// Check which flow we're in based on the flag
let email: String
Expand Down Expand Up @@ -532,9 +532,9 @@ public extension AuthService {
paramName: "ui_auid"
)
if shouldHandleAnonymousUpgrade, anonymousUserID == currentUser?.uid {
try await handleAutoUpgradeAnonymousUser(credentials: credential)
_ = try await handleAutoUpgradeAnonymousUser(credentials: credential)
} else {
let result = try await auth.signIn(withEmail: email, link: link)
_ = try await auth.signIn(withEmail: email, link: link)
Comment thread
ncooke3 marked this conversation as resolved.
Resolved
}
updateAuthenticationState()
// Track that user signed in with email link
Expand Down Expand Up @@ -586,7 +586,7 @@ public extension AuthService {
func signInWithPhoneNumber(verificationID: String, verificationCode: String) async throws {
let credential = PhoneAuthProvider.provider()
.credential(withVerificationID: verificationID, verificationCode: verificationCode)
try await signIn(credentials: credential)
_ = try await signIn(credentials: credential)
}
}

Expand Down Expand Up @@ -758,7 +758,7 @@ public extension AuthService {
}

do {
let result = try await resolver.resolveSignIn(with: assertion)
_ = try await resolver.resolveSignIn(with: assertion)
updateAuthenticationState()

// Clear MFA resolution state
Expand Down Expand Up @@ -792,8 +792,6 @@ public extension AuthService {
throw AuthServiceError.noCurrentUser
}

let multiFactorUser = user.multiFactor

// Create the appropriate assertion based on factor type
let assertion: MultiFactorAssertion

Expand All @@ -814,7 +812,7 @@ public extension AuthService {

case .totp:
// For TOTP, we need the secret from the session
guard let totpInfo = session.totpInfo else {
guard session.totpInfo != nil else {
throw AuthServiceError
.multiFactorAuth("TOTP info is missing from enrollment session")
}
Expand Down Expand Up @@ -903,10 +901,10 @@ public extension AuthService {
}
}

// MARK: - Private Helper Methods
// MARK: - Internal Helper Methods

private extension AuthService {
internal func updateAuthenticationState() {
extension AuthService {
Comment thread
ncooke3 marked this conversation as resolved.
Resolved
func updateAuthenticationState() {
authenticationState =
(currentUser == nil || currentUser?.isAnonymous == true)
? .unauthenticated
Expand All @@ -916,8 +914,12 @@ private extension AuthService {
legacySignInRecovery = nil
}
}
}

// MARK: - Private Helper Methods

private var shouldHandleAnonymousUpgrade: Bool {
private extension AuthService {
var shouldHandleAnonymousUpgrade: Bool {
currentUser?.isAnonymous == true && configuration.shouldAutoUpgradeAnonymousUsers
}

Expand Down Expand Up @@ -1090,7 +1092,8 @@ private extension AuthService {

private func buildLegacySignInRecovery(email: String,
signInMethods: [String],
attemptedProviderId: String?) -> LegacySignInRecoveryContext? {
attemptedProviderId: String?)
-> LegacySignInRecoveryContext? {
let attemptedOptionId = attemptedProviderId.map(normalizeLegacyOptionId)
var options: [LegacySignInOption] = []
var unavailableProviders: [String] = []
Expand Down Expand Up @@ -1137,7 +1140,9 @@ private extension AuthService {
displayName: string.legacyEmailLinkOptionLabel
)
default:
guard let provider = providers.first(where: { $0.id == normalizeLegacyOptionId(signInMethod) }) else {
guard let provider = providers.first(where: {
$0.id == normalizeLegacyOptionId(signInMethod)
}) else {
return nil
}
return LegacySignInOption(id: provider.id, displayName: provider.displayName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import FirebaseAuth
import FirebaseCore
import SwiftUI

extension MultiFactorInfo: Identifiable {
extension MultiFactorInfo: @retroactive Identifiable {
public var id: String { uid }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class FacebookProviderSwift: CredentialAuthProviderSwift {
.providerAuthenticationFailed("Failed to create Facebook login configuration")
}

let result = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<
Void,
Error
>) in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class GoogleProviderSwift: CredentialAuthProviderSwift {
}

@MainActor public func createAuthCredential() async throws -> AuthCredential {
guard let presentingViewController = await (UIApplication.shared.connectedScenes
guard let presentingViewController = (UIApplication.shared.connectedScenes
.first as? UIWindowScene)?.windows.first?.rootViewController else {
throw AuthServiceError
.rootViewControllerNotFound(
Expand Down
6 changes: 3 additions & 3 deletions FirebaseSwiftUI/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ Signs in using email and password credentials.
##### Create User with Email/Password

```swift
public func createUser(email email: String, password: String) async throws -> SignInOutcome
public func createUser(email: String, password: String) async throws -> SignInOutcome
```

Creates a new user account with email and password.
Expand Down Expand Up @@ -1218,7 +1218,7 @@ Button("Sign Out") {
##### Link Accounts

```swift
public func linkAccounts(credentials credentials: AuthCredential) async throws
public func linkAccounts(credentials: AuthCredential) async throws
```

Links a new authentication method to the current user's account.
Expand Down Expand Up @@ -1255,7 +1255,7 @@ Sends a sign-in link to the specified email address. Can also be used for reauth
##### Handle Sign-In Link

```swift
public func handleSignInLink(url url: URL) async throws
public func handleSignInLink(url: URL) async throws
```

Handles the email link flow when the user taps the link. Automatically routes to either sign-in or reauthentication based on the current context.
Expand Down
30 changes: 15 additions & 15 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import PackageDescription
let package = Package(
name: "FirebaseUI",
defaultLocalization: "en",
platforms: [.iOS(.v17)],
platforms: [
.iOS(.v17),
// Satisfies SPM's dependency graph check for FirebaseAuth 13 & GoogleSignIn 10.
// This package only supports iOS.
.macOS(.v12),
],
Comment thread
ncooke3 marked this conversation as resolved.
Resolved
products: [
.library(
name: "FirebaseDatabaseUI",
Expand Down Expand Up @@ -74,15 +79,11 @@ let package = Package(
),
.package(
url: "https://github.com/firebase/firebase-ios-sdk.git",
"8.0.0" ..< "13.0.0"
"8.0.0" ..< "14.0.0"
),
.package(
url: "https://github.com/google/GoogleSignIn-iOS",
from: "10.0.0"
),
.package(
url: "https://github.com/google/GoogleUtilities.git",
"7.4.1" ..< "9.0.0"
"7.0.0" ..< "11.0.0"
),
.package(
url: "https://github.com/SDWebImage/SDWebImage.git",
Expand Down
11 changes: 8 additions & 3 deletions okf-bundle/packaging/spm-and-cocoapods-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ Canonical consumer docs: [`README.md`](../../README.md), [`GETTING_STARTED.md`](
1. **SwiftUI Auth is SPM-first.** Do not add CocoaPods subspecs for `FirebaseAuthSwiftUI` / provider packages unless durable docs and CI are updated in the same change.
2. **UIKit data-binding modules are dual-built.** Edits under `Firebase*UI/Sources` must keep CocoaPods tests and SPM scheme builds green ([distribution path gate](../testing/running-tests.md#distribution-path-gate-blocking)).
3. **One source tree per module.** Do not fork SPM-only copies of UIKit sources; `Package.swift` targets point at the same `Sources` directories as the pods.
4. **Versioning is split operationally:**
- CocoaPods / umbrella: [`release.sh`](../../release.sh), [`staging.sh`](../../staging.sh), podspecs
- SwiftUI Auth package version stamp: [`release-swift.sh`](../../release-swift.sh) updates `FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Version.swift` (human-driven; agents need explicit user request)
4. **Versioning and releases:**
- CocoaPods / umbrella: Starting with Firebase 13 and FirebaseUI-iOS 16.2,
podspecs are frozen and no longer published to CocoaPods trunk.
- SwiftUI Auth package version stamp:
[`release-swift.sh`](../../release-swift.sh) updates
`FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Version.swift` (human-driven;
agents need explicit user request).
5. **Swift language mode:** SwiftUI Auth targets set `.swiftLanguageMode(.v6)` in `Package.swift`. Do not silently relax to silence concurrency errors — fix or record an accepted exception.

## `Package.swift` ownership
Expand All @@ -56,5 +60,6 @@ Canonical consumer docs: [`README.md`](../../README.md), [`GETTING_STARTED.md`](
| Dist-AD-1 | SwiftUI Auth ships via SPM; UIKit Database/Firestore/Storage remain CocoaPods-supported and SPM-listed | Accepted |
| Dist-AD-2 | Shared UIKit sources must pass both CocoaPods `./test.sh` and CI SPM scheme jobs when changed | Accepted |
| Dist-AD-3 | Agents do not run trunk/release scripts without explicit user request | Accepted |
| Dist-AD-4 | Starting with Firebase 13 and FirebaseUI-iOS 16.2, CocoaPods podspecs are frozen and no longer published to trunk | Accepted |

New distribution decisions get a row here; active migration tasks go in the [work queue](spm-cocoapods-work-queue.md).
Loading
Loading