[Feat] #50 - 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현#53
[Feat] #50 - 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현#53EunHee-Jeong merged 15 commits intoTeamRecorDream:developfrom
Conversation
- AuthView 재사용하도록 수정
| public protocol UserDefaultManager { | ||
| static func set(value: Any, keyPath: Key.RawValue) | ||
| static func string(key: Key) -> String? | ||
| static func int(key: Key) -> Int? | ||
| static func remove(key: Key) | ||
| static func clearUserData() | ||
| } |
There was a problem hiding this comment.
저는 PropertyWrapper를 이용했었는데 이 방식도 좋네요!!
| self.remove(key: .platform) | ||
| self.remove(key: .userToken) | ||
| self.remove(key: .accessToken) | ||
| self.remove(key: .nickname) |
There was a problem hiding this comment.
casIterable을 채택해서 allcases로 지워주는 방법도 있을 것 같습니다~~! 취향 차이인 것 같아여
| self.authService.login(kakaoToken: request.kakaoToken, appleToken: request.appleToken, fcmToken: request.fcmToken) | ||
| .subscribe(onNext: { response in | ||
| guard let response = response else { return } | ||
| observer.onNext(.init(duplicated: response.duplicated, accessToken: response.accessToken, refreshToken: response.refreshToken)) |
There was a problem hiding this comment.
여기서는 transform 파일에서 toDomain 메서드를 구현해줘도 좋을 것 같습니다!
| .filter { $0 != nil } | ||
| .subscribe(onNext: { [weak self] entity in | ||
| guard let self = self else { return } | ||
| guard let entity = entity else { | ||
| return } | ||
| DefaultUserDefaultManager.set(value: entity.accessToken, keyPath: C.accessToken) | ||
| DefaultUserDefaultManager.set(value: entity.refreshToken, keyPath: C.refreshToken) | ||
| self.authSuccess.onNext(entity) | ||
| }, onError: { err in | ||
| self.authFail.onNext(err) | ||
| }).disposed(by: disposeBag) |
There was a problem hiding this comment.
요 부분에서 필요하다면 response가 nil로 오는 경우에 대한 처리를 할 수도 있을 것 같네요! nil인 경우에 authFail에 넥스트 이벤트를 보내줄 수 있곘네요~~
| import Foundation | ||
|
|
||
| public struct AuthResponse: Codable { | ||
| public let duplicated: Bool |
There was a problem hiding this comment.
혹시 duplicated는 어떤 정보를 나타내는 걸까요? 이미 로그인 중이라는 뜻인감..
There was a problem hiding this comment.
현재 서버 쪽에서 하나의 API로 로그인과 회원가입을 동시에 수행하도록 구현되어 있는데요, (자세한 사항은 아래와 같음)
- 클라에서는 공통적으로 한 번에 보내면 → 회원가입이 안 되어 있다면 회원가입 수행, 되어 있다면 로그인 수행 → 기존 유저인지의 여부를
bool값으로 보내줌 - 이걸 쓰지 않고
UserDefault에 저장해둔 값의 유무로 토큰의 상태를 static하게 판별하도록 했는데(= SplashVC 68번째 줄), PR 답변 쓰면서 정리하다 보니까 어떻게 사용할 지 정리가 되네요... ㅎㅅㅎ
SplashVC TODO 주석 부분 구현할 때 해당 내용 추가하겠습니다!
There was a problem hiding this comment.
적어놓으신 내용을 바탕으로 생각해봤는데, 저도 userDefault에 저장해둔 값으로 판단하기보다는 서버에서 넘어온 값으로 판단하는게 정확할 것 같다는 생각이 듭니다 ~~! 앱에 저장된 userDefault 값이 실수로 제거될 수도 있고.. ㅇ.ㅇ... 여러 오류의 가능성이 있을 것 같다는 생각?? 네이밍도 더 명확하게 변경하는게 좋을 것 같아요 ~~
| self.kakaoLoginButton.rx.tap.map { _ in | ||
| AuthPlatformType.kakao | ||
| }, | ||
| self.appleLoginButton.rx.tap.map { _ in | ||
| AuthPlatformType.apple | ||
| }) |
There was a problem hiding this comment.
버튼을 커스텀하셨으니 서브클래스 안에 해당 AuthPlaformType 이벤트를 방출하는 옵저버블을 선언하는 것도 하나의 방법이겠네요~!
| DefaultAuthService.shared.login(kakaoToken: userToken, appleToken: userToken, fcmToken: accessToken) // ✅ | ||
| .subscribe(onNext: { response in | ||
| guard let response = response else { return } | ||
| DefaultUserDefaultManager.set(value: response.accessToken, keyPath: Key.accessToken.rawValue) | ||
| completion(true) | ||
| }, onError: { _ in | ||
| completion(false) | ||
| }).disposed(by: self.disposeBag) |
There was a problem hiding this comment.
피알에 남겨주신 부분이 요기 맞나요??
userDefault에 존재하는 플랫폼 key를 통해서 어떤 플랫폼인지 검사하고 그 결과를 분기처리하면 될 것 같습니다! router에다가 parameter를 하나 더 만들어도 되고,,, 방법은 여러가지가 있겠네용
There was a problem hiding this comment.
아마 아직 구현중이라서 그런 것 같지만~~ 될 수 있으면 통신은 repository가 가진 service를 통해 하는 것이 아키텍쳐 목적에 더 잘 어울릴 것 같습니다!
There was a problem hiding this comment.
PR에 고민 남겨주셔서 저도 생각해봤는데, router에서 카카오로그인, 애플로그인 구분해 주면 나중에도 안헷갈릴 거 같다는 생각이 드네요 !!
|
|
||
| func application( _ application: UIApplication, | ||
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { | ||
| KakaoSDK.initSDK(appKey: "000e1e31f022f98fbe16c76ab287abd1") // TODO: - 상수로 빼기 |
Suyeon9911
left a comment
There was a problem hiding this comment.
아이고 고생해씁니다 으니쨩 !! 보는데 좀 걸려서 ~~ 죄송함다 ~~ 아자자
| // Copyright © 2022 RecorDream. All rights reserved. | ||
| // | ||
|
|
||
| public struct C { |
There was a problem hiding this comment.
여기서는 축약어를 사용하기 보다는 AuthConstants 나 LoginConstants와 같이 어떤 정보를 상수로 묶어 두셨는지 네이밍해주시면 좋을 것 같습니다 !!
| public class DefaultUserDefaultManager: UserDefaultManager { | ||
| public static func set(value: Any, keyPath: Key.RawValue) { | ||
| UserDefaults.standard.setValue(value, forKeyPath: keyPath) | ||
| } | ||
| public static func string(key: Key) -> String? { | ||
| return UserDefaults.standard.string(forKey: key.rawValue) | ||
| } | ||
| public static func int(key: Key) -> Int? { | ||
| return UserDefaults.standard.integer(forKey: key.rawValue) | ||
| } | ||
| public static func remove(key: Key) { | ||
| UserDefaults.standard.removeObject(forKey: key.rawValue) | ||
| } | ||
| public static func clearUserData() { | ||
| self.remove(key: .platform) | ||
| self.remove(key: .userToken) | ||
| self.remove(key: .accessToken) | ||
| self.remove(key: .nickname) |
| import Foundation | ||
|
|
||
| public struct AuthResponse: Codable { | ||
| public let duplicated: Bool |
There was a problem hiding this comment.
적어놓으신 내용을 바탕으로 생각해봤는데, 저도 userDefault에 저장해둔 값으로 판단하기보다는 서버에서 넘어온 값으로 판단하는게 정확할 것 같다는 생각이 듭니다 ~~! 앱에 저장된 userDefault 값이 실수로 제거될 수도 있고.. ㅇ.ㅇ... 여러 오류의 가능성이 있을 것 같다는 생각?? 네이밍도 더 명확하게 변경하는게 좋을 것 같아요 ~~
| enum AuthPlatformType: String { | ||
| case kakao = "kakao" | ||
| case apple = "apple" | ||
| } |
There was a problem hiding this comment.
요거 DS_Kit에 Button 설정하는 부분에서도 같은 enum이 존재하는 거 같은데 하나의 enum으로 관리하는 건 어떨까용?
| func kakaoLoginAuthentication() { | ||
| if UserApi.isKakaoTalkLoginAvailable() { | ||
| UserApi.shared.loginWithKakaoTalk { [weak self] oauthToken, error in | ||
| guard let self = self else { return } | ||
| self.kakaoLoginRequest(oauthToken, error) | ||
| } | ||
| } | ||
| else { | ||
| UserApi.shared.loginWithKakaoAccount { [weak self] oauthToken, error in | ||
| guard let self = self else { return } | ||
| self.kakaoLoginRequest(oauthToken, error) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
나중에 리팩할 때 아키텍처에 맞게 네트워크 로직은 VC에서 분리 하는게 좋을 것 같아용 ㅎㅎ !!
| output.loginSuccess.subscribe(onNext: { entity in | ||
| // TODO: - 홈뷰로 화면전환, 닉네임 데이터 넘기기 | ||
| }).disposed(by: self.disposeBag) |
There was a problem hiding this comment.
아마 홈 진입하면서 닉네임 불러오긴 할텐데 넘겨주시믄 UI 업데이트 필요없이 바로 닉네임 적용 될 수 있을 거 같긴하네요 !!
| DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { | ||
| self.rootController = CoordinatorNavigationController(rootViewController: UIViewController()) | ||
| } | ||
|
|
There was a problem hiding this comment.
오 혹시 여기 GCD 써서 처리하신 이유가 있을까용??
There was a problem hiding this comment.
스플래쉬 뷰를 1초동안 띄운 다음에 홈뷰나 로그인뷰로 화면전환을 해야 하는데여,
시간차를 두고 그려지도록 하기 위해 GCD를 사용하였습니다...!
| if UserDefaults.standard.string(forKey: Key.userToken.rawValue) != nil && | ||
| UserDefaults.standard.string(forKey: Key.accessToken.rawValue) != nil { | ||
| // TODO: - 홈뷰 서버통신 | ||
| /// 성공이라면 토큰 상태로 .valid | ||
| /// 실패라면 토큰 상태로 .invalid 넣어주기 | ||
| } |
There was a problem hiding this comment.
혹시 usetToken과 accessToken의 차이가 모에요??
There was a problem hiding this comment.
- 그리고 탈출클로저와 completion handler ㅅ사용하는 부분 나중에 async/await로 리팩해봐도 좋을 것 같아요 ! 요즘 관련 공부중인데 장점이 많은 거 같더라고용 ~~ ><
There was a problem hiding this comment.
userToken → fcm 토큰에 해당, 사용자 고유의 토큰
accessToken → 로그인/회원가입 시 서버로부터 발급 받은 토큰
입니다!!
추후 async/await 반영하겠습니다! 피드백 감사해용 👍
| DefaultAuthService.shared.login(kakaoToken: userToken, appleToken: userToken, fcmToken: accessToken) // ✅ | ||
| .subscribe(onNext: { response in | ||
| guard let response = response else { return } | ||
| DefaultUserDefaultManager.set(value: response.accessToken, keyPath: Key.accessToken.rawValue) | ||
| completion(true) | ||
| }, onError: { _ in | ||
| completion(false) | ||
| }).disposed(by: self.disposeBag) |
There was a problem hiding this comment.
PR에 고민 남겨주셔서 저도 생각해봤는데, router에서 카카오로그인, 애플로그인 구분해 주면 나중에도 안헷갈릴 거 같다는 생각이 드네요 !!
👻 작업한 내용
🎤 PR Point
- 여기서 화면전환과 닉네임 데이터 전달 같은 부분들은 TODO 주석 처리해놓았습니다 !!
SplashVC코드 부분 논의appleToken,kakaoToken로 구분하여 보내야 하는 상황인데 저기서는 어떤 식으로 넣을 지 고민이네요...📸 스크린샷
📮 관련 이슈