diff --git a/NADA-iOS-forRelease/Resouces/Constants/Const.swift b/NADA-iOS-forRelease/Resouces/Constants/Const.swift index c37b3728..1b721fb6 100644 --- a/NADA-iOS-forRelease/Resouces/Constants/Const.swift +++ b/NADA-iOS-forRelease/Resouces/Constants/Const.swift @@ -8,5 +8,5 @@ import Foundation struct Const { - + static let headerToken: String = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) ?? "" } diff --git a/NADA-iOS-forRelease/Resouces/Constants/Header.swift b/NADA-iOS-forRelease/Resouces/Constants/Header.swift index 44c05e0e..922a9a61 100644 --- a/NADA-iOS-forRelease/Resouces/Constants/Header.swift +++ b/NADA-iOS-forRelease/Resouces/Constants/Header.swift @@ -8,10 +8,11 @@ import Foundation extension Const { + struct Header { static var bearerHeader = ["Authorization": "Bearer " + UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)!] static var basicHeader = ["Content-Type": "application/json", - "Authorization": "Bearer " + UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken)!] + "Authorization": "Bearer " + headerToken] } } diff --git a/NADA-iOS-forRelease/Resouces/Constants/UserDefaults.swift b/NADA-iOS-forRelease/Resouces/Constants/UserDefaults.swift index f8d09df4..d83b9442 100644 --- a/NADA-iOS-forRelease/Resouces/Constants/UserDefaults.swift +++ b/NADA-iOS-forRelease/Resouces/Constants/UserDefaults.swift @@ -16,5 +16,7 @@ extension Const { static let isFirstCard = "isFirstCard" static let isOnboarding = "isOnboarding" static let firstCardID = "firstCardID" + static let isAppleLogin = "isAppleLogin" + static let isKakaoLogin = "isKakaoLogin" } } diff --git a/NADA-iOS-forRelease/Sources/AppDelegate.swift b/NADA-iOS-forRelease/Sources/AppDelegate.swift index 746a3a45..249b5af9 100644 --- a/NADA-iOS-forRelease/Sources/AppDelegate.swift +++ b/NADA-iOS-forRelease/Sources/AppDelegate.swift @@ -7,39 +7,66 @@ import UIKit import KakaoSDKCommon +import KakaoSDKAuth +import KakaoSDKUser import AuthenticationServices @main class AppDelegate: UIResponder, UIApplicationDelegate { - // var isLogin = false + var isLogin = false func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - // removeKeychainAtFirstLaunch() + KakaoSDKCommon.initSDK(appKey: "5b8dd8cc878344bb7532eeca4365a4aa") + let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) -// let appleIDProvider = ASAuthorizationAppleIDProvider() -// appleIDProvider.getCredentialState(forUserID: Const.UserDefaults.userID) { (credentialState, error) in -// switch credentialState { -// case .authorized: -// print("해당 ID는 연동되어있습니다.") -// self.isLogin = true -// case .revoked: -// print("해당 ID는 연동되어있지않습니다.") -// self.isLogin = false -// case .notFound: -// print("해당 ID를 찾을 수 없습니다.") -// self.isLogin = false -// default: -// break -// } -// } - -// NotificationCenter.default.addObserver(forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification, object: nil, queue: nil) { (Notification) in -// print("Revoked Notification") -// self.isLogin = false -// } + if acToken != nil { + if UserDefaults.standard.bool(forKey: Const.UserDefaultsKey.isAppleLogin) { + // 애플 로그인으로 연동되어 있을 때, -> 애플 ID와의 연동상태 확인 로직 + let appleIDProvider = ASAuthorizationAppleIDProvider() + appleIDProvider.getCredentialState(forUserID: UserDefaults.standard.string(forKey: Const.UserDefaultsKey.userID) ?? "") { (credentialState, error) in + switch credentialState { + case .authorized: + print("해당 ID는 연동되어있습니다.") + self.isLogin = true + case .revoked: + print("해당 ID는 연동되어있지않습니다.") + self.isLogin = false + case .notFound: + print("해당 ID를 찾을 수 없습니다.") + self.isLogin = false + default: + break + } + } + } else { + if AuthApi.hasToken() { // 유효한 토큰 존재 + UserApi.shared.accessTokenInfo { (_, error) in + if let error = error { + if let sdkError = error as? SdkError, sdkError.isInvalidTokenError() == true { + self.isLogin = false + } + } else { + // 토큰 유효성 체크 성공(필요 시 토큰 갱신됨) + self.isLogin = true + } + } + } else { + // 카카오 토큰 없음 -> 로그인 필요 + self.isLogin = false + } + } + } else { + self.isLogin = false // acToken 값이 nil일 때 -> 로그인 뷰로 + } + + // 앱 실행 중 애플 ID 강제로 연결 취소 시 + NotificationCenter.default.addObserver(forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification, object: nil, queue: nil) { (Notification) in + print("Revoked Notification") + self.isLogin = false + } return true } @@ -57,7 +84,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } - - } - diff --git a/NADA-iOS-forRelease/Sources/NetworkService/Group/GroupService.swift b/NADA-iOS-forRelease/Sources/NetworkService/Group/GroupService.swift index eda2c321..75964961 100644 --- a/NADA-iOS-forRelease/Sources/NetworkService/Group/GroupService.swift +++ b/NADA-iOS-forRelease/Sources/NetworkService/Group/GroupService.swift @@ -96,8 +96,8 @@ extension GroupService: TargetType { return Const.Header.bearerHeader case .groupAdd, .groupEdit, .cardAddInGroup, .changeCardGroup: return Const.Header.bearerHeader - case .groupReset(let token): - return ["Content-Type": "application/json", "Authorization": "Bearer " + token] + case .groupReset: + return Const.Header.basicHeader } } } diff --git a/NADA-iOS-forRelease/Sources/NetworkService/User/UserSevice.swift b/NADA-iOS-forRelease/Sources/NetworkService/User/UserSevice.swift index 4b64bc8a..1f025ec8 100644 --- a/NADA-iOS-forRelease/Sources/NetworkService/User/UserSevice.swift +++ b/NADA-iOS-forRelease/Sources/NetworkService/User/UserSevice.swift @@ -77,10 +77,8 @@ extension UserSevice: TargetType { return Const.Header.bearerHeader case .userSignUp, .userSocialSignUp, .userTokenReissue: return ["Content-Type": "application/json"] - case .userDelete(let token): - return ["Content-Type": "application/json", "Authorization": "Bearer " + token] - case .userLogout(let token): - return ["Content-Type": "application/json", "Authorization": "Bearer " + token] + case .userDelete, .userLogout: + return Const.Header.basicHeader } } } diff --git a/NADA-iOS-forRelease/Sources/SceneDelegate.swift b/NADA-iOS-forRelease/Sources/SceneDelegate.swift index f78aa647..15d9ca21 100644 --- a/NADA-iOS-forRelease/Sources/SceneDelegate.swift +++ b/NADA-iOS-forRelease/Sources/SceneDelegate.swift @@ -36,14 +36,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window.overrideUserInterfaceStyle = .light } } - - // 스플래시 지연시간동안 자동 로그인 작업처리 - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { - let acToken = self.defaults.string(forKey: Const.UserDefaultsKey.accessToken) - let rfToken = self.defaults.string(forKey: Const.UserDefaultsKey.refreshToken) - - self.postUserTokenReissue(request: UserTokenReissueRequset(accessToken: acToken ?? "", refreshToken: rfToken ?? "")) - } + } func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { @@ -54,53 +47,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } - // MARK: - Network - - func postUserTokenReissue(request: UserTokenReissueRequset) { - UserAPI.shared.userTokenReissue(request: request) { response in - switch response { - case .success: - print("postUserTokenReissue - Success") - - var rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil) - .instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController) - - if self.defaults.string(forKey: Const.UserDefaultsKey.accessToken) != "" { - rootViewController = UIStoryboard(name: Const.Storyboard.Name.tabBar, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.tabBarViewController) - } else { - rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil) - .instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController) - } - self.window?.rootViewController = rootViewController - self.window?.makeKeyAndVisible() - case .requestErr(let message): - print("postUserTokenReissue - requestErr: \(message)") - - self.presentToLoginViewController() - case .pathErr: - print("postUserTokenReissue - pathErr") - case .serverErr: - print("postUserTokenReissue - serverErr") - case .networkFail: - print("postUserTokenReissue - networkFail") - } - } - } - // MARK: - Methods - private func presentToLoginViewController() { - if UserDefaults.standard.object(forKey: Const.UserDefaultsKey.isOnboarding) != nil { - let rootViewController = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(identifier: Const.ViewController.Identifier.loginViewController) - self.window?.rootViewController = rootViewController - self.window?.makeKeyAndVisible() - } else { - let rootViewController = UIStoryboard(name: Const.Storyboard.Name.onboarding, bundle: nil).instantiateViewController(identifier: Const.ViewController.Identifier.onboardingViewController) - self.window?.rootViewController = rootViewController - self.window?.makeKeyAndVisible() - } - } - func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/Login/LoginViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/Login/LoginViewController.swift index 61c6f74e..205d1398 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/Login/LoginViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/Login/LoginViewController.swift @@ -40,8 +40,6 @@ class LoginViewController: UIViewController { ]) let authorizationButton = ASAuthorizationAppleIDButton(type: .signIn, style: .black) - // let authorizationButton = UIButton() - // authorizationButton.setImage(UIImage(named: "appleLogin"), for: .normal) authorizationButton.addTarget(self, action: #selector(appleSignInButtonPress), for: .touchUpInside) loginProviderStackView.addSubview(authorizationButton) @@ -76,24 +74,16 @@ class LoginViewController: UIViewController { // 카카오 로그인 버튼 클릭 시 @objc func kakaoSignInButtonPress() { - if AuthApi.hasToken() { // 유효한 토큰 존재 - UserApi.shared.accessTokenInfo { (_, error) in - if let error = error { - if let sdkError = error as? SdkError, sdkError.isInvalidTokenError() == true { - // 로그인 필요 - self.signUp() - } - } else { - // 토큰 유효성 체크 성공(필요 시 토큰 갱신됨) - self.signUp() - } - } + // 카카오톡 설치 여부 확인 + if UserApi.isKakaoTalkLoginAvailable() { + // 카카오톡 로그인. api 호출 결과를 클로저로 전달. + loginWithApp() } else { - // 카카오 토큰 없음 -> 로그인 필요 - self.signUp() + // 만약, 카카오톡이 깔려있지 않을 경우에는 웹 브라우저로 카카오 로그인함. + loginWithWeb() } } - + // 애플 로그인 버튼 클릭 시 @objc func appleSignInButtonPress() { @@ -124,6 +114,8 @@ extension LoginViewController { } else { if let email = user?.kakaoAccount?.email { self.postUserSignUpWithAPI(request: email) + UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isAppleLogin) + UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isKakaoLogin) } } } @@ -145,6 +137,8 @@ extension LoginViewController { } else { if let email = user?.kakaoAccount?.email { self.postUserSignUpWithAPI(request: email) + UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isAppleLogin) + UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isKakaoLogin) } } } @@ -174,17 +168,13 @@ extension LoginViewController: ASAuthorizationControllerDelegate, ASAuthorizatio // Apple ID 연동 성공 시 func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { switch authorization.credential { - // Apple ID + // Apple ID case let appleIDCredential as ASAuthorizationAppleIDCredential: let userIdentifier = appleIDCredential.user - // let fullName = appleIDCredential.fullName - // let email = appleIDCredential.email - - // print("User ID : \(userIdentifier)") - // print("User Email : \(email ?? "")") - // print("User Name : \((fullName?.givenName ?? "") + (fullName?.familyName ?? ""))") postUserSignUpWithAPI(request: userIdentifier) + UserDefaults.standard.set(true, forKey: Const.UserDefaultsKey.isAppleLogin) + UserDefaults.standard.set(false, forKey: Const.UserDefaultsKey.isKakaoLogin) default: break @@ -206,10 +196,8 @@ extension LoginViewController { print("postUserSignUpWithAPI - success") if let userData = loginData as? UserWithTokenRequest { UserDefaults.standard.set(userData.user.userID, forKey: Const.UserDefaultsKey.userID) - let tokenData = userData.user.token - UserDefaults.standard.set(tokenData.accessToken, forKey: Const.UserDefaultsKey.accessToken) - UserDefaults.standard.set(tokenData.refreshToken, forKey: Const.UserDefaultsKey.refreshToken) - + UserDefaults.standard.set(userData.user.token.accessToken, forKey: Const.UserDefaultsKey.accessToken) + UserDefaults.standard.set(userData.user.token.refreshToken, forKey: Const.UserDefaultsKey.refreshToken) self.presentToMain() } case .requestErr(let message): diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/More/MoreViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/More/MoreViewController.swift index 0288f61d..e54720fc 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/More/MoreViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/More/MoreViewController.swift @@ -113,6 +113,7 @@ extension MoreViewController { if let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) { self.logoutUserWithAPI(token: acToken) self.defaults.removeObject(forKey: Const.UserDefaultsKey.accessToken) + self.defaults.removeObject(forKey: Const.UserDefaultsKey.refreshToken) self.defaults.removeObject(forKey: Const.UserDefaultsKey.darkModeState) let nextVC = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.loginViewController) nextVC.modalPresentationStyle = .overFullScreen @@ -147,6 +148,7 @@ extension MoreViewController { if let acToken = UserDefaults.standard.string(forKey: Const.UserDefaultsKey.accessToken) { self.deleteUserWithAPI(token: acToken) self.defaults.removeObject(forKey: Const.UserDefaultsKey.accessToken) + self.defaults.removeObject(forKey: Const.UserDefaultsKey.refreshToken) self.defaults.removeObject(forKey: Const.UserDefaultsKey.darkModeState) let nextVC = UIStoryboard(name: Const.Storyboard.Name.login, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.loginViewController) nextVC.modalPresentationStyle = .overFullScreen diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/Splash/SplashViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/Splash/SplashViewController.swift index c2452a6f..a84582c9 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/Splash/SplashViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/Splash/SplashViewController.swift @@ -11,15 +11,24 @@ class SplashViewController: UIViewController { // MARK: - Properties private weak var appDelegate = UIApplication.shared.delegate as? AppDelegate - - // MARK: - @IBOutlet Properties - + let defaults = UserDefaults.standard + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() + + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) - // Do any additional setup after loading the view. - // postUserTokenReissue(request: UserTokenReissueRequset(accessToken: UserDefaults.standard.string(forKey: Const.UserDefaults.accessToken)!, refreshToken: UserDefaults.standard.string(forKey: Const.UserDefaults.refreshToken)!)) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { + if self.appDelegate?.isLogin == true { + self.presentToMain() + } else { + self.presentToLogin() + } + } } // MARK: - Functions @@ -38,25 +47,3 @@ class SplashViewController: UIViewController { } } - -// MARK: - Networks -extension SplashViewController { - - func postUserTokenReissue(request: UserTokenReissueRequset) { - UserAPI.shared.userTokenReissue(request: request) { response in - switch response { - case .success: - print("postUserTokenReissue - Success") - case .requestErr(let message): - print("postUserTokenReissue - requestErr: \(message)") - self.presentToLogin() - case .pathErr: - print("postUserTokenReissue - pathErr") - case .serverErr: - print("postUserTokenReissue - serverErr") - case .networkFail: - print("postUserTokenReissue - networkFail") - } - } - } -}