티스토리 뷰

애플 로그인 구현하기 (Sign in with Apple)

애플 로그인이란??

앱을 다운받고 실행하면 초기화면에 다음과 같은 버튼을 본적이 있다.

요녀석들! 혹은 카카오, 네이버, Google 로 시작하기 같은 버튼등 편리한 로그인 기능이 있는데 그중 apple 아이디로 회원가입,로그인 기능을 얘기한다.

apple에서는 유저의 어떠한 개인정보도 드러내지 않고 로그인할수있도록 했다.
(일부앱은 이름이나 이메일을 요구할수도 있다.)

위와같이 이메일을 숨길수도 있는데 이때 숨김옵션을 사용하게되면 실제이메일을 유니크한 랜덤 주소로 만들어준다.

애플은 아무것도 track 하지 않으므로 유저의 개인정보를 보호할수 있도록한다.

구현하기

1. 프레임워크 import하기.

import AuthenticationServices

AuthenticationServices를 import하게되면 ASAuthorizationAppleIDButton() 을 사용할 수 있게되는데 Rx를 사용해서 만든 모습은 다음과 같다!

2. 애플 Sign 버튼 만들기

private let appleSignButton: ASAuthorizationAppleIDButton = {
        let button = ASAuthorizationAppleIDButton(
            authorizationButtonType: .continue,
            authorizationButtonStyle: .whiteOutline
        )

        return button
    }()

private func bind() {
    self.appleSignButton.rx.controlEvent(.touchUpInside)
            .bind {
                //appleSignButton 탭할경우 해야할 동작
            }
            .disposed(by: self.disposeBag)
}

HIG에 위의 apple로그인 버튼에대해 설명하는데, apple로그인을 구현하기위해서는 꼭 저걸 사용해야한다고 한다.
ASAuthorizationAppleIDButton의 특징으로는

  1. Apple이 승인한 타이틀, 폰트, 컬러, 스타일을 사용하도록 보장함.
  2. 버튼의 내용이 스타일을 변경할 때 이상적인 비율을 유지함을 보장함.
  3. 버튼의 제목을 디바이스에 설정된 언어로 자동번역.
  4. UI스타일과 일치하도록 버튼의 corner radius configuring지원.

cornerRadius기본값은 6이다.

maximum corner radius값을 초과한경우 지정된 max값을 사용하게된다.

자그럼 버튼을 눌렀을때 어떤 동작을 할것인지 정의해줘야하는데!

func didTapAppleSignButton(
        delegate: ASAuthorizationControllerDelegate,
        presentationProvider: ASAuthorizationControllerPresentationContextProviding
    ) {
        let request = ASAuthorizationAppleIDProvider().createRequest()
        request.requestedScopes = [.fullName, .email]
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = delegate
        controller.presentationContextProvider = presentationProvider
        controller.performRequests()
    }

요렇게 구현하고!

self.appleSignButton.rx.controlEvent(.touchUpInside)
            .withUnretained(self)
            .bind { owner, _ in
                owner.viewModel.didTapAppleSignButton(
                    delegate: self,
                    presentationProvider: self
                )
            }
            .disposed(by: self.disposeBag)

요렇게 호출해주면!

오류가납니다!

메서드의 인자갑을 self 로 넣어줬는데 self는 여기서 로그인뷰의 ViewController 인데 delegate랑 PresentationContextProviding을 채택 안해줘서 그렇다!

버튼눌렀을때 이름이랑 이메일 요구하도록 했는데 등록창 어디서 띄울건지 정해주는것같다.

무튼 그럼 ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding 요 녀석 채택해주고 필수 구현메서드를 구현해주면 된다!

extension InitalViewController: ASAuthorizationControllerDelegate {}

extension InitalViewController: ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        return self.view.window!
    }
}

필수 구현메서드는 하난데 내부로직은 예제코드 그대로 복붙했다!

여기까지 진행후 버튼을눌러도 시뮬레이터엔 아무런 변화가 없다.

Target > Signing & capabilities 요기가서

요거 추가해주면!!

요렇게 생기는데 요러면 완성!

다시 버튼을눌러보면!! 시뮬레이터에 요렇게 나온다!

이름이랑 이메일이은 아까 위에서 버튼탭했을때
request.requestedScopes = [.fullName, .email] 요렇게 요구했기때문에 애플아이디로 가입하기위해서는 이름과 email을 요구하게 된다!

3. apple ID 연동성공과 실패

위에서 ASAuthorizationControllerPresentationContextProviding를 채택하고 필수 메서드를 만들어줬지만 delegate에 대한 메서드를 만들어 주지 않았으니 이번에는 delegate의 메서드를 구현해보자!

delegate메서드는 다음과같이 2개가 존재한다.

  1. authorizationController(controller:didCompleteWithAuthorization:):
    Apple ID 연동에 성공시 실행되는함수다!

     func authorizationController(
         controller: ASAuthorizationController,
         didCompleteWithAuthorization authorization: ASAuthorization
     ) {
         switch authorization.credential {
         case let appleIDCredential as ASAuthorizationAppleIDCredential:
             let userInfo = UserInfo(
                 identifier: appleIDCredential.user,
                 name: appleIDCredential.fullName?.formatted(),
                 email: appleIDCredential.email)
             //여기서 만들어진 userInfo 를 가지고 추가작업을 해주면 될듯 하다!
    
         default:
             self.coordinator.showErrorAlert(
                 title: "Apple ID 연동 에러",
                 message: "Apple ID 정보를 가져올 수 없습니다."
             )
         }
     }
  2. authorizationController(controller:didCompleteWithError:):
    실패시 실행되는 함수다!(에러 처리해주면 되겠지!?)

func authorizationController(
        controller: ASAuthorizationController,
        didCompleteWithError error: Error
    ) {
        self.coordinator.showErrorAlert(
            title: "Apple ID 연동 에러",
            message: error.localizedDescription
        )
    }

4. 로그인 완료시 데이터형태

//최초 로그인시
User ID : [User Identifier]
User Email : XXXXXX@privaterelay.appleid.com
User Name : 김동욱

//이후 로그인시
User ID : [User Identifier]
User Email :  
User Name :  
  • 최초 로그인에만 이름과 이메일을 받을 수 있다.
  • 두번째 로그인 부터는 앱에서 Apple ID 사용 중단하기 전까지 ID 값만 리턴해준다.
  • [설정 앱] - [Apple ID] - [암호 및 보안] - [내 Apple ID를 사용하는 앱] 에서 'Apple ID 사용 중단'

5. 앱 실행시 로그인 상태 확인

AppDelegate.swift에서 application(_:didFinishLaunchingWithOptions:)를 활용하면된다!

func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        appleIDProvider.getCredentialState(forUserID: /* 로그인에 사용한 User Identifier */) { (credentialState, error) in
            switch credentialState {
            case .authorized:
                print("해당 ID는 연동되어있습니다.")
            case .revoked
                print("해당 ID는 연동되어있지않습니다.")
            case .notFound:
                print("해당 ID를 찾을 수 없습니다.")
            default:
                break
            }
        }
        return true
    }
  • authorized : 해당 User Identifier 값이 앱과 연결이 허가되어있다.
  • revoked : 해당 User Identifier 값이 앱과 연결이 취소되어있다.
  • notFound : 해당 User Identifier 값이 앱과 연결을 찾을 수 없다.

6. 앱 실행중 강제로 연결 취소 시

앱 실행 중 [설정 앱] - [Apple ID] - [암호 및 보안] - [내 Apple ID를 사용하는 앱] 에서 'Apple ID 사용 중단' 했을 경우 앱으로 돌아왔을때 유저정보를 사용할수 없게되니 다시 유저정보를 요청해야한다!

Appdelegate의 didFinishLaunchingWithOptions 메서드에서 NotificationCenter를 이용해 LoginView를 띄워주면 된다!

func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        NotificationCenter.default.addObserver(
            forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification,
            object: nil, queue: nil
        ) { (Notification) in
            // 로그인 페이지로 이동
        return true
    }

참고한 문서및 자료

애플 예제코드
https://zeddios.tistory.com/781
https://huisoo.tistory.com/3

'iOS > iOS-Memo' 카테고리의 다른 글

Launch Screen을 적용해보자!  (0) 2022.10.10
APIKey를 숨겨보자!  (0) 2022.10.09
Cache, NSCache, URLCache  (1) 2022.09.30
Underline SegmanetControl  (0) 2022.08.12
NotificationCenter, Modal 사용시 주의점!  (0) 2022.04.29
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함