샘성의 iOS 개발 일지

구글 유저 정보 Firebase RealTime Database에 저장하기 본문

iOS/UiKit

구글 유저 정보 Firebase RealTime Database에 저장하기

SamusesApple 2023. 5. 7. 16:57
728x90

목적:

  구글 로그인 + 유저 정보 받아서 Firebase - Realtime Database에 이름과 이메일 저장하기

 

 

준비물:

  Firebase Auth 프로젝트에 Google Auth 허용해놓기

 

 

1. Database를 다룰 객체 만들기

Firebase의 데이터베이스에 접근하여 데이터를 받아오고 생성하기 위해, class에 database 인스턴스를 생성해야한다.

(하단 코드 참고)

 

import FirebaseDatabase

final class DatabaseManager {
    // 싱글톤 객체로 만들기
    static let shared = DatabaseManager()
    
    private let database = Database.database().reference()
    
    private init() { }
    
}

 

 

  이제 이 DatabaseManager가 database에 새로운 데이터를 생성하고, 기존의 데이터를 읽을 수 있도록 메서드를 구현해야한다.

그 전에 Database의 구조를 보면, key - value 값으로 프로젝트라는 큰 데이터 안에 다른 데이터들이 중첩되어 들어있는 형태로 되어있다.

 

  하단의 이미지를 보면, 유저 이메일을 토글하면 그 안에 키와 value 값이 들어있다. (JSON 구조 같다..)

email, name 이라는 키값이 왼쪽에 있고 각각의 키값에 해당하는 이메일과 이름이 오른쪽에 위치한다.

 

 

 

이제, 빈 깡통의 database에 child data를 생성하면서 데이터를 저장하면 될 것 같다.

 

 

 

 

 

2. DatabaseManager에게 능력 주기

  이제 DatabaseManager가 데이터베이스에 접근해서 새로운 데이터를 만들고, 기존에 존재하는 데이터를 읽어올 수 있도록 능력을 부여해야한다.

 

  데이터베이스에 child 데이터를 추가하고, 그 child data에 '키 - 값' 형태로 데이터를 중첩해서 저장할 것이다. (하단 코드 참고)

func createUser(with user: User, completion: @escaping (Bool) -> Void) {
         // 유저 이메일 안에 'name', 'email' 이라는 키와 이에 해당하는 값들 중첩해서 저장
        database.child(유저 이메일).setValue(["name": user.name,
                                                 "email": user.emailAddress]) { error, ref in
            guard error == nil else {
				// error 발생 시 handle error
                print("Firebase - 유저 데이터 업로드 실패")
                completion(false)
                return
            }
        }
        // 완료 후 할 작업 completion block에 다루기
        print("Firebase - \(user.name) 데이터 업로드 성공")
        completion(true)
    }

 

 

그리고 중복되는 데이터를 저장하고 싶지 않기에, 이미 저장된 데이터인지 확인하는 메서드도 추가한다.

func checkIfUserExists(with email: String, completion: @escaping ((Bool) -> Void)) {
		// database에 .을 사용할 수 없기에 .을 -로 대치
        let safeEmail = email.replacingOccurrences(of: ".", with: "-")
        
        // 하나의 이벤트만 확인해주고 사라지는 옵저버한테 safeEmail로 저장된 데이터가 있는지 확인시키기
        database.child(safeEmail).observeSingleEvent(of: .value) { snapshot in
        	// snapshot의 데이터가 문자열로 바뀌는지 확인 (email은 문자열타입이므로)
            guard snapshot.value as? String != nil else {
                // 존재하지 않는 이메일 처리
                completion(false)
                return
            }
            // 이미 존재하는 이메일 처리
            completion(true)
        }
    }

 

 

 

 

 

 

3.  ViewController 일 시키기

 

  '구글로 로그인하기'와 같은 버튼이 눌리면 하단처럼 코드가 작동되도록 구현하면 된다.

확인할 이메일에는 아마 textField와 같이 사용자가 제공하는 이메일을 넣으면 될 것 같다..!

import FirebaseAuth

  let clientID = FirebaseApp.app()?.options.clientID
        let config = GIDConfiguration(clientID: clientID!)
        GIDSignIn.sharedInstance.configuration = config
        GIDSignIn.sharedInstance.signIn(withPresenting: self) { [unowned self] result, error in
            guard error == nil else {
                print(error?.localizedDescription as Any)
                return
            }
            guard let user = result?.user,
                  let idToken = user.idToken?.tokenString
            else {
                // 토큰 오류
                return
            }
            let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                           accessToken: user.accessToken.tokenString)
            guard let email = user.profile?.email,
                  let userName = user.profile?.name else { return }
            
            // 이미 존재하는 유저인지 확인
            let loggingUser = User(name: userName, emailAddress: email)
            DatabaseManager.shared.checkIfUserExists(with: email) { exists in
                if !exists {
                    // 유저 정보 저장 
                    DatabaseManager.shared.createUser(with: loggingUser) { success in
                        if success {
                        // 저장 성공하면 firebase auth signIn 실행
                            FirebaseAuth.Auth.auth().signIn(with: credential) { [weak self] result, error in
                                guard result != nil, error == nil else {
                                    print("GOOGLE - credential error")
                                    print(error?.localizedDescription)
                                    return
                                }
                                print("GOOGLE 로그인 성공")
                            }
                        }
                    }
                }
            }
        }

 

 

 

 

 

 

결과 

끝 -

 

Authentication에도 구글로 나오고, Realtime Database에도 잘 저장된다.

 

  Facebook도 비슷한 맥락으로 하면 되지만, data가 중첩된 형식으로 되어있어서 result["email"] as? String 이런식으로 데이터를 받아서 변수에 저장한 후에 Firebase에 저장하는 작업을 시작해야한다.

 

 

 

그나저나 애플이 남았구나..!

 

 

 

728x90