안녕하세요.
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)
따로 지정하지 않으면 현재 테마에 맞춰 버튼이 나옵니다.
시뮬레이터에서 테스트 결과 로그인이 정상 동작합니다.
'프로젝트 > 장기 프로젝트' 카테고리의 다른 글
[뮤즐리 이슈 해결] LetsEncrypt(Certbot) 도메인 인증서 만료 / 갱신 / 크론탭 등록 (0) | 2023.11.24 |
---|---|
Hustle #11. 처음 시작하는 사람도 작업할 수 있도록, 스프링 부트 개발 컨벤션 정하기 (0) | 2023.11.22 |
Hustle #10. 프로젝트 구조 잡기 (0) | 2023.09.11 |
Hustle #9. Aquery Tool 으로 ERD 모델링하기 (1) | 2023.09.04 |
Hustle #8. Jasypt 암호화 라이브러리 적용 (2) | 2023.09.03 |
댓글