본문 바로가기
Swift

Swift TCA로 Apple SNS 로그인 구현하기

by mr.conan 2023. 7. 16.
728x90
반응형

Swift TCA(Two Complementary Architectures)는 Redux 아키텍처를 기반으로 한 Swift 앱 아키텍처 패턴입니다. 이번 예제에서는 Apple SNS 로그인을 구현해보겠습니다. Apple SNS 로그인을 위해서는 Apple Developer 계정에 등록하고, 인증을 처리하기 위한 API를 사용해야 합니다. 이를 위해 Sign in with Apple 기능을 활용하여 로그인을 구현합니다.

 

1. 상태(State) 정의

로그인 상태를 저장할 State를 정의합니다. 로그인 성공 여부와 사용자 정보를 저장하도록 합니다

import Foundation

struct AppState {
    var isLoggedIn: Bool = false
    var user: User?
}

struct User {
    let id: String
    let name: String
    // 다른 사용자 정보들을 추가로 정의할 수 있습니다.
}

 

 

2.액션(Action) 정의

앱의 상태 변경에 필요한 액션들을 정의합니다. Apple SNS 로그인의 경우 로그인 성공, 로그인 실패, 그리고 Apple 로그인 버튼이 눌렸을 때의 상태를 나타내는 액션을 추가합니다.

 

enum AppAction {
    case loginSuccess(User)
    case loginFailure(Error)
    case appleSignInTapped
    // 기타 다른 액션들을 추가할 수 있습니다.
}

 

반응형

 

3. 리듀서(Reducer) 정의

리듀서는 상태와 액션을 받아 상태를 변경하는 역할을 합니다. 로그인 성공과 실패에 따라 상태를 업데이트하고, Apple 로그인 버튼이 눌렸을 때 인증을 처리하는 로직을 추가합니다.

 

import ComposableArchitecture
import AuthenticationServices

let appReducer = Reducer<AppState, AppAction, AppEnvironment> { state, action, environment in
    switch action {
    case let .loginSuccess(user):
        state.isLoggedIn = true
        state.user = user
        return .none

    case .loginFailure:
        // 로그인 실패 시에 대한 처리를 추가합니다.
        return .none

    case .appleSignInTapped:
        // Apple 로그인 버튼이 눌렸을 때의 처리를 추가합니다.
        let appleSignInProvider = ASAuthorizationAppleIDProvider()
        let appleSignInRequest = appleSignInProvider.createRequest()
        appleSignInRequest.requestedScopes = [.fullName, .email]
        return environment.appleSignInController
            .signIn(with: appleSignInRequest)
            .map { authorization in
                // Apple 로그인 성공 시에 대한 처리를 추가합니다.
                // 사용자 정보를 추출하여 액션을 디스패치합니다.
                guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else {
                    return .loginFailure(AppError.unknownError)
                }

                let user = User(id: appleIDCredential.user,
                                name: "\(appleIDCredential.fullName?.givenName ?? "") \(appleIDCredential.fullName?.familyName ?? "")")
                return .loginSuccess(user)
            }
            .eraseToEffect()
    }
}

 

 

4. 환경(Environment) 정의

환경은 앱의 외부 의존성을 캡슐화하는데 사용됩니다. Apple SNS 로그인은 인증과 관련하여 외부 프레임워크와 상호작용해야 하므로, 이를 위한 환경을 정의합니다. 이 예제에서는 ASAuthorizationController를 사용하여 Apple 로그인을 처리합니다.

import AuthenticationServices

struct AppEnvironment {
    let appleSignInController: ASAuthorizationController
}

 

 

 

5. 스토어(Store) 설정

이제 정의한 리듀서와 초기 상태를 기반으로 스토어를 설정합니다.

import ComposableArchitecture
import AuthenticationServices

let appleSignInController = ASAuthorizationController(authorizationRequests: [ASAuthorizationAppleIDProvider().createRequest()])

let appStore = Store(
    initialState: AppState(),
    reducer: appReducer,
    environment: AppEnvironment(appleSignInController: appleSignInController)
)

 

 

6. SwiftUI 뷰에서 앱 디스패치

마지막으로 SwiftUI 뷰에서 앱 스토어를 사용하여 액션을 디스패치하는 방법을 보여드리겠습니다.

import SwiftUI
import ComposableArchitecture

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appStore) // 앱 스토어를 환경 객체로 주입합니다.
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var store: Store<AppState, AppAction> // 앱 스토어를 주입받습니다.

    var body: some View {
        VStack {
            if store.state.isLoggedIn {
                LoggedInView()
            } else {
                Button("Apple 로그인", action: {
                    store.send(.appleSignInTapped) // Apple 로그인 버튼이 눌렸을 때 액션을 디스패치합니다.
                })
            }
        }
    }
}

 

이제 Apple SNS 로그인 버튼을 누르면 .appleSignInTapped 액션이 디스패치되며, 이를 처리하는 리듀서에서 상태를 변경하고 로그인 결과에 따라 적절한 뷰를 표시할 수 있습니다.

 

Swift TCA를 활용하여 앱의 상태 관리를 체계적으로 구현하면 유지 보수가 용이하고 테스트도 쉽게 할 수 있습니다. Apple SNS 로그인 뿐만 아니라 다양한 기능을 구현할 때에도 TCA를 활용하여 코드를 깔끔하고 견고하게 유지하는 것을 추천드립니다.

728x90
반응형