초기 세팅

<aside> 💡 Xcode 프로젝트 Target 탭 ⇒ Signing & Capabilities ⇒ + 버튼 ⇒ Sign in with Apple 추가

</aside>

문서


Apple을 사용하여 인증  |  Firebase

기본 세팅 코드

문서의 코드를 그대로 사용하면 된다


import CryptoKit
import **AuthenticationServices**
		
final class AppleService: NSObject {
	static let shared = AppleService()
	private override init() { }
	var initLoginFlowViewController: UIViewController! // 📌 인증 인터페이스를 LoginVC에서 제공하기 위해

===============================================**파이어베이스 문서 로직**===============================================
	private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      var randomBytes = [UInt8](repeating: 0, count: length)
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
      if errorCode != errSecSuccess {
          fatalError(
              "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \\(errorCode)"
          )
      }

      let charset: [Character] =
          Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")

      let nonce = randomBytes.map { byte in
          // Pick a random character from the set, wrapping around if needed.
          charset[Int(byte) % charset.count]
      }

      return String(nonce)
    }

    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
        let inputData = Data(input.utf8)
        let hashedData = SHA256.hash(data: inputData)
        let hashString = hashedData.compactMap {
            String(format: "%02x", $0)
        }.joined()

        return hashString
    }

    // Unhashed nonce.
    fileprivate var currentNonce: String?

    /// 📌 애플 로그인 버튼 눌렀을 때 실행
    @available(iOS 13, *) func **startSignInWithAppleFlow**(view: UIViewController) {
	    self.initLoginFlowViewController = view
	
	    let nonce = randomNonceString()
	    currentNonce = nonce
	    let appleIDProvider = ASAuthorizationAppleIDProvider()
	    let request = appleIDProvider.createRequest()
	    request.requestedScopes = [.fullName, .email]
	    request.nonce = sha256(nonce)
	
	    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
	    authorizationController.delegate = self
	    authorizationController.presentationContextProvider = self
	    authorizationController.performRequests()
	  }
===============================================**파이어베이스 문서 로직**===============================================
}

extension AppleService: **ASAuthorizationControllerDelegate** {

	// 📌 로그인이 성공하면
	func authorizationController(controller: ASAuthorizationController, **didCompleteWithAuthorization** authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
            guard let nonce = currentNonce else {
                fatalError("Invalid state: A login callback was received, but no login request was sent.")
            }
            guard let appleIDToken = appleIDCredential.identityToken else {
                print("Unable to fetch identity token")
                return
            }
            guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
                print("Unable to serialize token string from data: \\(appleIDToken.debugDescription)")
                return
            }

            let email = appleIDCredential.email ?? ""
            let name = formatName(credentialName: appleIDCredential.fullName)
            let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
                                                           rawNonce: nonce,
                                                           fullName: appleIDCredential.fullName)

						// 📌 파이어베이스 로그인 후 리턴된 UID값과 애플로그인 사용자 정보로 유저 가입 유무 판별 후 UserDefaults에 저장
            FirebaseService.shared.loginFirebase(credential: credential) { uid, isNewUser, docID in
                if let uid = uid {
                    print("UID : \\(uid)")
                    print("EMAIL : \\(email)")
                    print("NAME : \\(name)")

                    if isNewUser {
                        FirebaseService.shared.saveUserInDatabase(name: name, email: email, uid: uid) { docID in
                            print("DATABASE에 저장 완료 🟢")

                            UserDefaultsManager.shared.saveUserInfo(name: name, email: email, docID: docID, uid: uid) {
                                CommonUtil.changeRootView(to: BaseTabBar())
                            }
                        }
                    } else {
                        // docID로 유저 정보 가져오기
                        guard let docID = docID else { return }
                        FirebaseService.shared.getUserInfo(with: docID) { name, email, uid, docID in
                            print("가입되어 있는 유저 NAME : \\(name)")
                            print("가입되어 있는 유저 EMAIL : \\(email)")
                            print("가입되어 있는 유저 UID : \\(uid)")
                            print("가입되어 있는 유저 DOC ID : \\(docID)")

                            UserDefaultsManager.shared.saveUserInfo(name: name, email: email, docID: docID, uid: uid) {
                                CommonUtil.changeRootView(to: BaseTabBar())
                            }
                        }
                    }
                }
            }
        }
    }

		// 📌 로그인 에러 시
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Sign in with Apple errored: \\(error)")
    }
}

// 📌 loginView에서 startSignInWithAppleFlow(with: self)를 실행하여 loginView에서 인증 인터페이스가 제공되게 작성
extension AppleService: ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        guard let window = initLoginFlowViewController.view.window else { fatalError("No Window") }
        return window
    }
}