Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions DevLog/App/Assembler/InfraAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
// Created by 최윤진 on 12/7/25.
//

final class InfraAssembler: @MainActor Assembler {
@MainActor
final class InfraAssembler: Assembler {
func assemble(_ container: any DIContainer) {
container.register(
AuthenticationService.self,
Expand Down
4 changes: 4 additions & 0 deletions DevLog/Data/Common/Error+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ enum FirestoreError: Error, LocalizedError {
}
}
}

enum UIError: Error {
case notFoundTopViewController
}
59 changes: 35 additions & 24 deletions DevLog/Infra/Service/SocialLogin/GoogleAuthenticationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,35 @@ import FirebaseMessaging
import Foundation
import GoogleSignIn

@MainActor
final class GoogleAuthenticationService: AuthenticationService {
private let store = Firestore.firestore()
private let functions = Functions.functions(region: "asia-northeast3")
private let messaging = Messaging.messaging()
private var user: User? { Auth.auth().currentUser }
private let provider = TopViewControllerProvider()

@MainActor
func signIn() async throws -> AuthenticationDataResponse {
guard let topVC = topViewController() else {
throw URLError(.cannotFindHost)
guard let topViewController = provider.topViewController() else {
throw UIError.notFoundTopViewController
}
let gidSignIn = try await GIDSignIn.sharedInstance.signIn(withPresenting: topVC)
guard let idToken = gidSignIn.user.idToken?.tokenString else {

let signIn = try await GIDSignIn.sharedInstance.signIn(withPresenting: topViewController)

guard let idToken = signIn.user.idToken?.tokenString else {
throw URLError(.badServerResponse)
}

let accessToken = gidSignIn.user.accessToken.tokenString
let accessToken = signIn.user.accessToken.tokenString
let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)

let result = try await Auth.auth().signIn(with: credential)

if let photoURL = gidSignIn.user.profile?.imageURL(withDimension: 200) {
if let photoURL = signIn.user.profile?.imageURL(withDimension: 200) {
let changeRequest = result.user.createProfileChangeRequest()
changeRequest.photoURL = photoURL
changeRequest.displayName = gidSignIn.user.profile?.name
changeRequest.displayName = signIn.user.profile?.name

try await changeRequest.commitChanges()
}

Expand Down Expand Up @@ -74,8 +75,11 @@ final class GoogleAuthenticationService: AuthenticationService {
}

func link(uid: String, email: String) async throws {
guard let topViewController = topViewController() else {
throw URLError(.cannotFindHost)
let topViewController = await MainActor.run {
provider.topViewController()
}
guard let topViewController = topViewController else {
throw UIError.notFoundTopViewController
}

if GIDSignIn.sharedInstance.hasPreviousSignIn() {
Expand Down Expand Up @@ -111,27 +115,34 @@ final class GoogleAuthenticationService: AuthenticationService {

}

extension GoogleAuthenticationService {
func topViewController(controller: UIViewController? = nil) -> UIViewController? {
final class TopViewControllerProvider {
@MainActor
func topViewController() -> UIViewController? {
let keyWindow = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first { $0.isKeyWindow }

let controller = controller ?? keyWindow?.rootViewController

let rootController = keyWindow?.rootViewController

return topViewController(controller: rootController)
}

@MainActor
private func topViewController(controller: UIViewController?) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}

if let tabController = controller as? UITabBarController, let selected = tabController.selectedViewController {
return topViewController(controller: selected)

if let tabController = controller as? UITabBarController,
let selectedController = tabController.selectedViewController {
return topViewController(controller: selectedController)
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)

if let presentedController = controller?.presentedViewController {
return topViewController(controller: presentedController)
}

return controller
}
}