일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- css학습
- 리팩터링
- Di
- IOS
- unittest
- 코딩테스트입문
- firestore
- TDD
- mrc
- AutoLayout
- RC
- ARC
- Swift코딩테스트
- 클린코드
- 앱의생명주기
- algorithm
- hackerrank
- ios면접
- Safari Inspector
- alamofire
- 프로그래머스
- five lines of code
- 카카오맵클론
- UIKit
- SWIFT
- storekit2
- Swift디자인패턴
- firebase
- RxSwift
- five lines of cdde
- Today
- Total
샘성의 iOS 개발 일지
[KakaoMap 클론] 4. Firebase에 카카오톡 로그인 유저 정보 저장하기 본문
로그인 한 유저의 검색 기록, 장소별 별점, 즐겨찾기 한 장소 쉽게 저장하고 꺼내볼 수 있도록 Firebase에 저장할 것이다.
이를 위해 'Cocoa Pods'를 사용하여 Firebase를 세팅하고 카카오톡 로그인 유저 데이터를 저장해보자!
배경 : 카카오톡 로그인 구현 완료 된 상태
카카오톡 로그인 구현이 안 된 상태라면, 하단의 게시글을 참고하시면 좋을 것 같습니다.
1. Firebase 프로젝트 세팅하기
하단의 사이트에 접속 >> '시작하기' 버튼을 눌러 새로운 프로젝트를 생성한다.
원하는 프로젝트명을 기입한 후, 구글 애널리스트 사용 여부 체크를 하면 상단의 이미지와 함께 새 프로젝트 생성이 완료된다.
생성이 완료되면 상단과 같은 화면을 볼 수 있다. iOS 앱을 만드므로 'iOS+'라고 적혀있는 동그라미를 누른다.
이제 각자 프로젝트의 번들 아이디를 사용하여 빈칸을 기입 후, '앱 등록' 버튼을 누른다.
그리고 'GoogleService-Info.plist 다운로드' 버튼을 누르면 하단과 같은 info.plist를 다운받게 된다.
프로젝트에 다운받은 info.plist를 드래그-앤 드롭 하여 집어넣는다.
그리고 Firebase 프로젝트 화면의 '다음' 버튼을 누른다.
주의: 이 때, 파일명이 'GoogleService-Info.plist'인지 잘 확인해야한다. 뒤에 숫자가 붙는다던지.. 다를 경우 실행이 안된다.
이제 Firebase에 필요한 소스파일을 다운받아 프로젝트에 넣어야한다.
SPM(Swift Package Manager)를 사용해도 되지만, 필자는 Cocoa Pods를 사용하여 해당 파일을 프로젝트에 install 할 것이다.
pod 'FirebaseAuth'
pod 'FirebaseFirestore'
pod file에 두가지 pod를 리스트에 추가 및 저장한다.
cd 프로젝트 경로 // 프로젝트 경로로 이동
pod install --repo-update // update 된 pod file 다운로드
여러개의 pod file들이 다운받아지는 것을 확인할 수 있다. (오래걸림..)
다 다운 받아졌으면, 프로젝트가 build되는지 확인한다. (오래걸림2222.... 약 4000개 이상의 파일이 빌드되는 것을 볼 수 있다...)
잘 build 된다면, '다음' 버튼을 눌러서 초기화 코드를 추가할 것이다.
Firebase에서 상단과 같은 코드를 추가하라고 제공했지만 @UIApplicationMain만 봐도 예전에 업로드 후 업데이트 되지 않았다는 것을 알 수 있다..^^.. 그래도 코드의 차이는 없기에..
하단의 코드를 그대로 AppDelegate - didFinishLaunchingWithOptions에 넣으면 된다.
import UIKit
import FirebaseCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
...
2. Firebase Authentication 세팅하기
좌측의 '빌드' >> 'Authentication'을 클릭하여 유저 로그인 및 인증을 관리할 Authentication을 시작할 수 있다.
Firebase에서 제공하는 로그인 제공업체에는 '카카오톡'이 없다.
그러므로 기본 제공업체의 '이메일/비밀번호'를 사용할 예정이다. (클릭하기)
이메일은 '카카오 아이디 이메일', 비밀번호는 '카카오 유저 고유 식별번호'를 사용할 것이다.
3. Firestore 세팅하기
Authentication을 생성한것과 동일하게, 왼쪽에 있는 탭 리스트 중 'Firestore Database'를 눌러서 세팅한다.
이 후, 생성한 Firestore의 규칙을 수정하지 않으면 콘솔창에 하단과 같은 에러를 받을 수 있으니.. 꼭 규칙을 수정해야한다.
error: 'Permission denied: Missing or insufficient permissions.'
false로 되어있는 초록색 부분을 true로 변경하면 끝이다!
4. 로그인 및 회원가입 + Firestore에 유저 정보 저장하기 ( + 소스코드)
Firebase로그인을 담당하는 AuthService라는 구조체를 하나 생성했다.
로직은 간단하다.
- 유저가 로그인 버튼을 누른다.
- 카카오톡으로부터 해당 유저의 카카오톡 이메일, 카카오톡 닉네임, 카카오톡 고유 유저id를 받는다.
(앱 로그인 id == 카카오톡 이메일 / 앱 로그인 비밀번호 == 카카오톡 고유 유저 id) - 해당 유저가 이미 존재하는 유저인지 체크한다. (로그인 시도를 하면, 존재하지 않는 유저인 경우 에러가 발생한다. 이 때 회원가입 코드를 넣으면 된다)
>> 이미 존재하는 유저인 경우: 로그인 진행 // 존재하지 않는 유저인 경우: 회원가입 진행 - 로그인 혹은 회원가입이 완료되면, UserDefaults에 '유저 이메일, 유저 닉네임, 유저 uid, 카카오 로그인 여부' 저장
- 모든 작업이 끝나면 completion 블럭에 이후 처리할 작업 정의하기
(필자는 노티피케이션 센터에 로그인 된 것을 알리고, 해당 알림을 받는 객체들이 로그인 여부에 따라 다음 작업을 할 수 있도록 했다)
* Firebase 로그인을 담당하는 AuthService 구조체 *
import Foundation
import FirebaseAuth
// 필요한 유저 정보 캡슐화
struct AuthCredentials {
let email: String
let nickName: String
let password: String
let isKakaoLogin: Bool
}
typealias AuthDataResultCallback = (AuthDataResult?, Error?) -> Void
struct AuthService {
/// 기존에 없는 새로운 유저 등록
static func registerUser(userInfo credentials: AuthCredentials, completion: @escaping () -> Void) {
Auth.auth().createUser(withEmail: credentials.email,
password: credentials.password) { (result, error) in
if let error = error {
print("AuthService ERROR : \(error.localizedDescription)")
return
}
guard let userUID = result?.user.uid else { return }
// 유저 이메일에 해당되는 다큐먼트에 들어갈 컬렉션 형태의 데이터
let data = ["email": credentials.email,
"nickName": credentials.nickName,
"isKakaoLogin": credentials.isKakaoLogin,
"uid": userUID] as [String : Any]
// 'uses' 컬렉션에 유저 이메일을 id로 새로운 다큐먼트 생성 + 다큐먼트에 생성한 컬렉션 데이터 넣기
Firestore.firestore().collection("users").document(credentials.email).setData(data) { error in
if let _ = error {
print("새로운 유저 생성하기 실해")
return
}
// UserDefaults에 로그인 된 유저 정보 저장
UserDefaultsManager.shared.setUserInfo(nickName: credentials.nickName,
email: credentials.email,
uid: userUID,
isKakaoLogin: credentials.isKakaoLogin)
completion()
}
}
}
/// 기존 유저 로그인
static func logUserIn(withEmail email: String, password: String, completion: AuthDataResultCallback?) {
Auth.auth().signIn(withEmail: email, password: password, completion: completion)
}
}
* UserDefaults를 담당하는 구조체 *
struct UserDefaultsManager {
static let shared = UserDefaultsManager()
private init() { }
func setUserInfo(nickName: String, email: String, uid: String, isKakaoLogin: Bool) {
UserDefaults.standard.set(nickName, forKey: "name")
UserDefaults.standard.set(email, forKey: "email")
UserDefaults.standard.set(uid, forKey: "uid")
UserDefaults.standard.set(isKakaoLogin, forKey: "isKakaoLogin")
}
}
* 카카오톡 로그인 버튼에 연결된 target Action 함수 *
@objc private func kakaoLoginButtonTapped() {
// 로그인 된 경우 -> 로그아웃
// 로그인 안 된 경우 -> 로그인
if UserApi.isKakaoTalkLoginAvailable() {
UserApi.shared.loginWithKakaoTalk { [weak self] token, error in
if let error = error {
print(error)
return
}
print("카카오 로그인 성공")
_ = token
// 로그인 된 카카오톡 정보 노티피케이션 센터에 등록 및 메뉴에 있는 프로필 세팅하기
// firebase에 해당 카카오톡 아이디로 회원가입 유무 확인 후, 없으면 가입하고 있으면 로그인시키기
self?.setFirebaseForKakaoTalkLogin()
}
}
print("카카오 로그인 구현하기")
}
* 카카오톡 로그인 된 유저 정보로 Firebase에 로그인 및 회원가입 후, 완료되면 NotificationCenter에 알리는 메서드
private func setFirebaseForKakaoTalkLogin() {
UserApi.shared.me {[weak self] user, error in
guard let user = user,
let email = user.kakaoAccount?.email,
let nickName = user.kakaoAccount?.profile?.nickname,
let password = user.id,
error == nil else {
print(error!)
return
}
let kakaoAuthCredentials = AuthCredentials(email: email,
nickName: nickName,
password: String(password),
isKakaoLogin: true)
AuthService.logUserIn(withEmail: email, password: String(password)) { result, error in
// 이미 존재하는 유저인지 확인 (로그인 실패: 유저 존재 X, 로그인 성공: 유저 존재 O)
guard let result = result,
let email = result.user.email,
error == nil else {
// 로그인 실패, 유저 존재 X
print("새로운 유저 회원가입 필요")
AuthService.registerUser(userInfo: kakaoAuthCredentials) {
NotificationManager.postloginNotification(name: nickName,
userEmail: email,
profileImageURL: user.kakaoAccount?.profile?.profileImageUrl,
isKakaoLogin: true)
self?.cancelButtonTapped()
}
return
}
// 로그인 성공, 유저 존재 O
print("기존 존재하는 유저로 로그인하기")
UserDefaultsManager.shared.setUserInfo(nickName: nickName,
email: email,
uid: result.user.uid,
isKakaoLogin: true)
NotificationManager.postloginNotification(name: nickName,
userEmail: email,
profileImageURL: user.kakaoAccount?.profile?.profileImageUrl,
isKakaoLogin: true)
self?.cancelButtonTapped()
}
}
}
Authentication에 성공적으로 카카오톡 아이디를 이용해 로그인이 된 것을 확인할 수 있다.
추가적으로 필요한 유저의 정보들 또한 Firestore에 저장된것을 확인할 수 있다.
끝-
'iOS > UiKit' 카테고리의 다른 글
[iOS 16.4~] Inspector로 iOS 앱 내 띄운 웹뷰 디버깅 하기 (1) | 2024.03.27 |
---|---|
[KakaoMap 클론] 5. 장소 즐겨찾기 기능 추가하기 (feat. Firestore) (0) | 2023.06.11 |
UIApplication 객체의 컨트롤러 역할은 어디에 구현해야 하는가? (0) | 2023.06.08 |
UIImage를 원하는 사이즈로 조절하는 법 (0) | 2023.06.08 |
[KakaoMap 클론] 3. 지도 위에 경로 그리기 (0) | 2023.05.31 |