Skip to content

[Feat] #50 - 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현#53

Merged
EunHee-Jeong merged 15 commits intoTeamRecorDream:developfrom
EunHee-Jeong:feature/#50
Dec 13, 2022
Merged

[Feat] #50 - 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현#53
EunHee-Jeong merged 15 commits intoTeamRecorDream:developfrom
EunHee-Jeong:feature/#50

Conversation

@EunHee-Jeong
Copy link
Copy Markdown
Member

@EunHee-Jeong EunHee-Jeong commented Dec 6, 2022

👻 작업한 내용

  • 로그인・스플래쉬 뷰 UI 구성
  • kako・apple 로그인 API 연결
  • 자동 로그인 기능 구현

🎤 PR Point

  • SceneDelegate 커밋 무시바람...!!! 수연이 머지하면 그걸로 바꿀게요
  • 스플래쉬 뷰에서 valid, invalid, missed의 세 가지 경우로 나뉜 토큰의 상태를 검사하여 화면전환 및 로그인 기능을 수행합니다.
    - 여기서 화면전환과 닉네임 데이터 전달 같은 부분들은 TODO 주석 처리해놓았습니다 !!
  • SplashVC 코드 부분 논의
    • 현재 서버에 소셜 부분 토큰을appleToken, kakaoToken로 구분하여 보내야 하는 상황인데 저기서는 어떤 식으로 넣을 지 고민이네요...

📸 스크린샷

구현 내용 스크린샷
로그인 UI image

📮 관련 이슈

@EunHee-Jeong EunHee-Jeong added 으니짱 🍅 담당자 feat 구현·개선 사항에 관련된 내용입니다. labels Dec 6, 2022
@EunHee-Jeong EunHee-Jeong self-assigned this Dec 6, 2022
@EunHee-Jeong EunHee-Jeong changed the title [#50] 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현 [Feat] #50 - 로그인・스플래쉬 뷰 UI 구성 및 API 연결, 자동 로그인 기능 구현 Dec 6, 2022
L-j-h-c
L-j-h-c previously approved these changes Dec 6, 2022
Copy link
Copy Markdown
Contributor

@L-j-h-c L-j-h-c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

멋있슴당...!

Comment on lines +11 to +17
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()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 PropertyWrapper를 이용했었는데 이 방식도 좋네요!!

Comment on lines +33 to +36
self.remove(key: .platform)
self.remove(key: .userToken)
self.remove(key: .accessToken)
self.remove(key: .nickname)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서는 transform 파일에서 toDomain 메서드를 구현해줘도 좋을 것 같습니다!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!

Comment on lines +37 to +47
.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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 부분에서 필요하다면 response가 nil로 오는 경우에 대한 처리를 할 수도 있을 것 같네요! nil인 경우에 authFail에 넥스트 이벤트를 보내줄 수 있곘네요~~

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!

import Foundation

public struct AuthResponse: Codable {
public let duplicated: Bool
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 duplicated는 어떤 정보를 나타내는 걸까요? 이미 로그인 중이라는 뜻인감..

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 서버 쪽에서 하나의 API로 로그인과 회원가입을 동시에 수행하도록 구현되어 있는데요, (자세한 사항은 아래와 같음)

  • 클라에서는 공통적으로 한 번에 보내면 → 회원가입이 안 되어 있다면 회원가입 수행, 되어 있다면 로그인 수행 → 기존 유저인지의 여부를 bool 값으로 보내줌
  • 이걸 쓰지 않고 UserDefault 에 저장해둔 값의 유무로 토큰의 상태를 static하게 판별하도록 했는데(= SplashVC 68번째 줄), PR 답변 쓰면서 정리하다 보니까 어떻게 사용할 지 정리가 되네요... ㅎㅅㅎ

SplashVC TODO 주석 부분 구현할 때 해당 내용 추가하겠습니다!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적어놓으신 내용을 바탕으로 생각해봤는데, 저도 userDefault에 저장해둔 값으로 판단하기보다는 서버에서 넘어온 값으로 판단하는게 정확할 것 같다는 생각이 듭니다 ~~! 앱에 저장된 userDefault 값이 실수로 제거될 수도 있고.. ㅇ.ㅇ... 여러 오류의 가능성이 있을 것 같다는 생각?? 네이밍도 더 명확하게 변경하는게 좋을 것 같아요 ~~

Comment on lines +86 to +91
self.kakaoLoginButton.rx.tap.map { _ in
AuthPlatformType.kakao
},
self.appleLoginButton.rx.tap.map { _ in
AuthPlatformType.apple
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

버튼을 커스텀하셨으니 서브클래스 안에 해당 AuthPlaformType 이벤트를 방출하는 옵저버블을 선언하는 것도 하나의 방법이겠네요~!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!

Comment on lines +84 to +91
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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피알에 남겨주신 부분이 요기 맞나요??

userDefault에 존재하는 플랫폼 key를 통해서 어떤 플랫폼인지 검사하고 그 결과를 분기처리하면 될 것 같습니다! router에다가 parameter를 하나 더 만들어도 되고,,, 방법은 여러가지가 있겠네용

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마 아직 구현중이라서 그런 것 같지만~~ 될 수 있으면 통신은 repository가 가진 service를 통해 하는 것이 아키텍쳐 목적에 더 잘 어울릴 것 같습니다!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR에 고민 남겨주셔서 저도 생각해봤는데, router에서 카카오로그인, 애플로그인 구분해 주면 나중에도 안헷갈릴 거 같다는 생각이 드네요 !!


func application( _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
KakaoSDK.initSDK(appKey: "000e1e31f022f98fbe16c76ab287abd1") // TODO: - 상수로 빼기
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요기는 상수 만들어두고 깜빡하신 것 같아요!

Copy link
Copy Markdown
Member

@Suyeon9911 Suyeon9911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아이고 고생해씁니다 으니쨩 !! 보는데 좀 걸려서 ~~ 죄송함다 ~~ 아자자

// Copyright © 2022 RecorDream. All rights reserved.
//

public struct C {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서는 축약어를 사용하기 보다는 AuthConstants 나 LoginConstants와 같이 어떤 정보를 상수로 묶어 두셨는지 네이밍해주시면 좋을 것 같습니다 !!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!

Comment on lines +19 to +36
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구웃ㅎㅎㅎ !!

import Foundation

public struct AuthResponse: Codable {
public let duplicated: Bool
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적어놓으신 내용을 바탕으로 생각해봤는데, 저도 userDefault에 저장해둔 값으로 판단하기보다는 서버에서 넘어온 값으로 판단하는게 정확할 것 같다는 생각이 듭니다 ~~! 앱에 저장된 userDefault 값이 실수로 제거될 수도 있고.. ㅇ.ㅇ... 여러 오류의 가능성이 있을 것 같다는 생각?? 네이밍도 더 명확하게 변경하는게 좋을 것 같아요 ~~

Comment on lines +14 to +17
enum AuthPlatformType: String {
case kakao = "kakao"
case apple = "apple"
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 DS_Kit에 Button 설정하는 부분에서도 같은 enum이 존재하는 거 같은데 하나의 enum으로 관리하는 건 어떨까용?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!

Comment on lines +19 to +32
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)
}
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나중에 리팩할 때 아키텍처에 맞게 네트워크 로직은 VC에서 분리 하는게 좋을 것 같아용 ㅎㅎ !!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!

Comment on lines +107 to +109
output.loginSuccess.subscribe(onNext: { entity in
// TODO: - 홈뷰로 화면전환, 닉네임 데이터 넘기기
}).disposed(by: self.disposeBag)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마 홈 진입하면서 닉네임 불러오긴 할텐데 넘겨주시믄 UI 업데이트 필요없이 바로 닉네임 적용 될 수 있을 거 같긴하네요 !!

Comment on lines 33 to 36
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
self.rootController = CoordinatorNavigationController(rootViewController: UIViewController())
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 혹시 여기 GCD 써서 처리하신 이유가 있을까용??

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스플래쉬 뷰를 1초동안 띄운 다음에 홈뷰나 로그인뷰로 화면전환을 해야 하는데여,
시간차를 두고 그려지도록 하기 위해 GCD를 사용하였습니다...!

Comment on lines +69 to +74
if UserDefaults.standard.string(forKey: Key.userToken.rawValue) != nil &&
UserDefaults.standard.string(forKey: Key.accessToken.rawValue) != nil {
// TODO: - 홈뷰 서버통신
/// 성공이라면 토큰 상태로 .valid
/// 실패라면 토큰 상태로 .invalid 넣어주기
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 usetToken과 accessToken의 차이가 모에요??

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 그리고 탈출클로저와 completion handler ㅅ사용하는 부분 나중에 async/await로 리팩해봐도 좋을 것 같아요 ! 요즘 관련 공부중인데 장점이 많은 거 같더라고용 ~~ ><

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userToken → fcm 토큰에 해당, 사용자 고유의 토큰
accessToken → 로그인/회원가입 시 서버로부터 발급 받은 토큰

입니다!!
추후 async/await 반영하겠습니다! 피드백 감사해용 👍

Comment on lines +84 to +91
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR에 고민 남겨주셔서 저도 생각해봤는데, router에서 카카오로그인, 애플로그인 구분해 주면 나중에도 안헷갈릴 거 같다는 생각이 드네요 !!

@EunHee-Jeong EunHee-Jeong merged commit ad2bbc3 into TeamRecorDream:develop Dec 13, 2022
@EunHee-Jeong EunHee-Jeong deleted the feature/#50 branch December 13, 2022 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 구현·개선 사항에 관련된 내용입니다. 으니짱 🍅 담당자

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 스플래쉬, 회원가입/로그인 뷰 UI 구현

3 participants