<aside> 💡 Xcode 프로젝트 Target 탭 ⇒ Signing & Capabilities ⇒ + 버튼 ⇒ Sign in with Apple 추가
</aside>
문서의 코드를 그대로 사용하면 된다
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
}
}