프로젝트/장기 프로젝트

[MOTI] iOS 시뮬레이터에서 애플 로그인 안되는 이슈 해결

Chipmunks 2023. 9. 11.
728x90

안녕하세요.

SwiftUI 초기 버전 (iOS 13) 에서 소셜 로그인으로 애플 로그인을 구현했습니다.

배포 후 언젠가부터 실기기에선 정상 동작하지만, 시뮬레이터에서 애플 로그인이 안되더라고요.

당시엔 원인을 모르겠고 일시적인 오류인 줄만 알았어요.

시간이 지나도 해결이 안되길래 구글링을 열심히 했었는데요.

저 뿐만 아니라 많은 사람들도 시뮬레이터에서 애플 로그인이 되지 않는 이슈 스레드가 많았습니다.

명확한 해결책이 없어 애플에서 고쳐주질 않는구나 싶어서 실기기로 테스트를 주로 했었습니다.

어쩔 수 없이 시뮬레이터로 테스트를 할 때엔 토큰을 직접 입력하고 넘어가며 테스트를 했었습니다.

 

최근에 구글링을 하던 중 SwiftUI 에서 애플 로그인을 지원하는 중이더군요.

기존 코드에선 직접 버튼 뷰를 만들고, 버튼 뷰에서 ASAuthorizationAppleIDButton 버튼뷰를 생성하였습니다.

기존 코드는 아래와 같습니다.

import SwiftUI
import AuthenticationServices

final class SignWithApple: UIViewRepresentable {
    typealias UIViewType = ASAuthorizationAppleIDButton
    
    func makeUIView(context: Context) -> UIViewType {
        let button = ASAuthorizationAppleIDButton(type: .default, style: .white)
        button.cornerRadius = 22
        return button
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        // Empty
    }
}

직접 버튼 뷰를 만들고 버튼을 누르면 ASAuthorizationController 컨트롤러를 생성하였습니다.

컨트롤러에서 응답이 오면 백엔드 서버와 통신하는 딜리게이트를 연결했습니다.

private func showAppleLogin() {
    let request = ASAuthorizationAppleIDProvider().createRequest()
    request.requestedScopes = [.fullName, .email]

    performSignIn(using: [request])
}

private func performSignIn(using requests: [ASAuthorizationRequest]) {
    appleSignInDelegates = SignInWithAppleDelegates(window: window) { (success, haveAccount) in
        if success, let haveAccount = haveAccount {
            // update UI
            if haveAccount {
                self.window.rootViewController = UIHostingController(rootView: MainView(window: self.window))
            } else {
                self.window.rootViewController = UIHostingController(rootView: NavigationView { SignUpNickNameView(window: self.$window) })
            }
        } else {
            // show the user an error
        }
    }
    
    let controller = ASAuthorizationController(authorizationRequests: requests)
    controller.delegate = appleSignInDelegates
    controller.presentationContextProvider = appleSignInDelegates

    controller.performRequests()
}

 

이제 위 코드 대신에 SwiftUI 에서 지원해주는 버튼으로 코드를 대체했습니다.

iOS 14 버전 SwiftUI 부터 지원하는 SignInWithAppleButton 버튼으로 대체합니다.

import SwiftUI
import AuthenticationServices

...

struct SignInView: View {

    ...
    
    var body: some View {
        VStack {
            SignInWithAppleButton(
                onRequest: { request in
                    request.requestedScopes = [.fullName, .email]
                },
                onCompletion: signInOnCompletion
            )
            .signInWithAppleButtonStyle(.white)
            .frame(height: 44, alignment: .center)
            .cornerRadius(22)
        }
        .padding(.horizontal, 15)
    	.padding(.bottom, 23)
    }
    
    ...
    
    private func signInOnCompletion(result: Result<ASAuthorization, Error>) -> Void {
        switch result {
        case .success(let authResults):
            switch authResults.credential{
            case let appleIDCredential as ASAuthorizationAppleIDCredential:
                let id = String(decoding: appleIDCredential.identityToken ?? Data(), as: UTF8.self)
                let auth = String(decoding: appleIDCredential.authorizationCode ?? Data(), as: UTF8.self)
                
                AhobsuProvider.signIn(snsId: auth, auth: id, completion: { wrapper in
                    if let signInToken = wrapper?.data {
                        if signInToken.signUp {
                            TokenManager.sharedInstance.registerAccessToken(token: signInToken.accessToken,
                                                                            completion: nil,
                                                                            error: nil)
                            TokenManager.sharedInstance.registerRefreshToken(token: signInToken.refreshToken,
                                                                             completion: nil,
                                                                             error: nil)
                        } else {
                            TokenManager.sharedInstance.temporaryAccessToken = signInToken.accessToken
                            TokenManager.sharedInstance.temporaryRefreshToken = signInToken.refreshToken
                        }
                        self.signInSucceeded(success: true, haveAccount: signInToken.signUp)
                    } else {
                        self.signInSucceeded(success: false, haveAccount: nil)
                    }
                }, error: { err in
                    self.signInSucceeded(success: false, haveAccount: nil)
                }, expireTokenAction: {
                    // Empty
                }, filteredStatusCode: nil)
            default:
                break
            }
        case .failure(_):
            self.signInSucceeded(success: false, haveAccount: nil)
        }
    }
}

onCompletion 코드가 길므로 따로 메소드로 분리했습니다.

SignInWithAppleButton 버튼은 부모 뷰에 맞춰 자동으로 너비가 최대로 맞춰집니다.

부모 뷰에 padding 속성을 넣어 버튼의 가로 크기를 지정했습니다.

기존 디자인에선 검정 배경이라 눈에 잘 띄는 하얀 버튼으로 표시했습니다.

signInWithAppleButtonStyle 으로 .white 또는 .black 속성으로 스타일을 지정할 수 있습니다.

.signInWithAppleButtonStyle(.white)

 

따로 지정하지 않으면 현재 테마에 맞춰 버튼이 나옵니다.

 

하얀 버튼 지정 (좌), 현재 테마 따라 적용 (우)

시뮬레이터에서 테스트 결과 로그인이 정상 동작합니다.

댓글