From 23e03dcc172839707366a7d839adac3f8223f4f0 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 9 Jan 2023 20:48:08 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[Feat]=20#60=20-=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20(=EB=A1=9C=EA=B7=B8=EC=9D=B8)=20API=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 4 ++ .../Global/Supports/SceneDelegate.swift | 3 +- .../Global/Utils/UserDefaultKeyList.swift | 2 +- .../Router/SignInRouter/SignInRouter.swift | 52 ++++++++++++++++++ .../Presentation/SignIn/VC/SignInVC.swift | 55 +++++++++++++++++++ .../Presentation/Splash/VC/SplashVC.swift | 21 +++++-- 6 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Network/Router/SignInRouter/SignInRouter.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 24c5a15b..b8f6af77 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -107,6 +107,7 @@ CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */; }; CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */; }; CEC2A6922962BE2900160BF7 /* DepartureSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */; }; + CECBAD2F296C2F3C00AC8976 /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECBAD2E296C2F3C00AC8976 /* SignInRouter.swift */; }; CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */; }; CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */; }; CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */; }; @@ -247,6 +248,7 @@ CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNMarker.swift; sourceTree = ""; }; CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = convertLocationObject.swift; sourceTree = ""; }; CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchVC.swift; sourceTree = ""; }; + CECBAD2E296C2F3C00AC8976 /* SignInRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInRouter.swift; sourceTree = ""; }; CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingHomeVC.swift; sourceTree = ""; }; CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; @@ -660,6 +662,7 @@ isa = PBXGroup; children = ( CE10064029680C9F00FD31FB /* .gitkeep */, + CECBAD2E296C2F3C00AC8976 /* SignInRouter.swift */, ); path = SignInRouter; sourceTree = ""; @@ -1264,6 +1267,7 @@ DA20D84E2966A9B300F1581F /* SearchVC.swift in Sources */, CE1006572968230800FD31FB /* DepartureLocationModel.swift in Sources */, CE6655EC295D88D000C64E12 /* UITableView+.swift in Sources */, + CECBAD2F296C2F3C00AC8976 /* SignInRouter.swift in Sources */, CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */, CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */, CEC2A6852961F92C00160BF7 /* CustomButton.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift b/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift index b1a5c3a4..f2baba80 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift @@ -16,7 +16,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) - window.rootViewController = TabBarController() + let nav = UINavigationController(rootViewController: SplashVC()) + window.rootViewController = nav self.window = window window.makeKeyAndVisible() } diff --git a/Runnect-iOS/Runnect-iOS/Global/Utils/UserDefaultKeyList.swift b/Runnect-iOS/Runnect-iOS/Global/Utils/UserDefaultKeyList.swift index c7ed5ade..90a289e2 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Utils/UserDefaultKeyList.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Utils/UserDefaultKeyList.swift @@ -9,6 +9,6 @@ import Foundation struct UserDefaultKeyList { struct Auth { - @UserDefaultWrapper(key: "deviceId") public static var deviceId + @UserDefaultWrapper(key: "didSignIn") public static var didSignIn } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/SignInRouter/SignInRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/SignInRouter/SignInRouter.swift new file mode 100644 index 00000000..49343eaa --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Router/SignInRouter/SignInRouter.swift @@ -0,0 +1,52 @@ +// +// SignInRouter.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/09. +// + +import Foundation + +import Moya + +enum SignInRouter { + case signUp(nickname: String) +} + +extension SignInRouter: TargetType { + var baseURL: URL { + guard let url = URL(string: Config.baseURL) else { + fatalError("baseURL could not be configured") + } + + return url + } + + var path: String { + switch self { + case .signUp: + return "/user" + } + } + + var method: Moya.Method { + switch self { + case .signUp: + return .post + } + } + + var task: Moya.Task { + switch self { + case .signUp(let nickname): + return .requestParameters(parameters: ["nickname": nickname], encoding: JSONEncoding.default) + } + } + + var headers: [String: String]? { + switch self { + case .signUp: + return Config.headerWithDeviceId + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift index 0c0fd5f0..48c7486d 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift @@ -7,10 +7,16 @@ import UIKit +import Moya + final class SignInVC: UIViewController { // MARK: - Properties + private var signInProvider = MoyaProvider( + plugins: [NetworkLoggerPlugin(verbose: true)] + ) + private let nicknameMaxLength = 7 // MARK: - UI Components @@ -50,6 +56,7 @@ final class SignInVC: UIViewController { self.setUI() self.setLayout() self.setDelegate() + self.setAddTarget() } } @@ -60,9 +67,19 @@ extension SignInVC { self.nicknameTextField.delegate = self } + private func setAddTarget() { + self.startButton.addTarget(self, action: #selector(startButtonDidTap), for: .touchUpInside) + } + private func changeTextFieldLayerColor(_ isEditing: Bool) { nicknameTextField.layer.borderColor = isEditing ? UIColor.m1.cgColor : UIColor.g3.cgColor } + + private func pushToTabBarController() { + let tabBarController = TabBarController() + guard let window = self.view.window else { return } + ViewControllerUtils.setRootViewController(window: window, viewController: tabBarController, withAnimation: true) + } } // MARK: - @objc Function @@ -80,6 +97,11 @@ extension SignInVC { self.nicknameTextField.text = String(newString) } } + + @objc func startButtonDidTap() { + guard let nickname = nicknameTextField.text else { return } + self.signIn(nickname: nickname) + } } // MARK: - UI & Layout @@ -124,3 +146,36 @@ extension SignInVC: UITextFieldDelegate { return true } } + +// MARK: - Network + +extension SignInVC { + func signIn(nickname: String) { + signInProvider.request(.signUp(nickname: nickname)) { [weak self] response in + guard let self = self else { return } + switch response { + case .success(let result): + let status = result.statusCode + if 200..<300 ~= status { + do { + let responseDto = try result.map(BaseResponse.self) + if responseDto.status == 200 { + UserDefaultKeyList.Auth.didSignIn = true + self.pushToTabBarController() + } else { + self.showToast(message: responseDto.message) + } + } catch { + print(error.localizedDescription) + } + } + if status >= 400 { + print("400 error") + } + case .failure(let error): + print(error.localizedDescription) + self.showToast(message: "네트워크 통신 실패") + } + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift index e98345e0..4fa32798 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift @@ -31,19 +31,30 @@ final class SplashVC: UIViewController { self.setUI() self.setNavigationBar() self.setLayout() - self.pushToSignInView() + self.checkDidSignIn() } } // MARK: - Methods extension SplashVC { - private func pushToSignInView() { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - let signInVC = SignInVC() - self.navigationController?.pushViewController(signInVC, animated: true) + private func checkDidSignIn() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + let needAuth = (UserDefaultKeyList.Auth.didSignIn == nil) + needAuth ? self.pushToSignInView() : self.pushToTabBarController() } } + + private func pushToSignInView() { + let signInVC = SignInVC() + self.navigationController?.pushViewController(signInVC, animated: true) + } + + private func pushToTabBarController() { + let tabBarController = TabBarController() + guard let window = self.view.window else { return } + ViewControllerUtils.setRootViewController(window: window, viewController: tabBarController, withAnimation: true) + } } // MARK: - UI & Layout From ef7f4cef99976bbec30ec6e0523fe20466d01902 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 9 Jan 2023 20:52:58 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[Chore]=20#60=20-=20signIn=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EC=97=90=20=EB=A1=9C=EB=94=A9=20=EC=9D=B8=EB=94=94?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift index 48c7486d..d30571b6 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift @@ -151,7 +151,9 @@ extension SignInVC: UITextFieldDelegate { extension SignInVC { func signIn(nickname: String) { + LoadingIndicator.showLoading() signInProvider.request(.signUp(nickname: nickname)) { [weak self] response in + LoadingIndicator.hideLoading() guard let self = self else { return } switch response { case .success(let result): From df19b12e3347c1c7853df12a1a7ec050bb1110a7 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Tue, 10 Jan 2023 00:36:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[Feat]=20#60=20-=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85(=EB=A1=9C=EA=B7=B8=EC=9D=B8)=20API=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 4 + .../Global/Utils/KeychainManager.swift | 105 ++++++++++++++++++ .../Presentation/SignIn/VC/SignInVC.swift | 1 - .../Presentation/Splash/VC/SplashVC.swift | 12 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Global/Utils/KeychainManager.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index b8f6af77..27391295 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ CE17F0382961BF8B00E1DED0 /* FontLiterals.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE17F0372961BF8B00E1DED0 /* FontLiterals.swift */; }; CE29D582296402B500F47542 /* CourseDrawingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE29D581296402B500F47542 /* CourseDrawingVC.swift */; }; CE29D584296416D800F47542 /* caculateStatusBarHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE29D583296416D800F47542 /* caculateStatusBarHeight.swift */; }; + CE3A53C5296C6017003D518C /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3A53C4296C6017003D518C /* KeychainManager.swift */; }; CE40BB1C2967E4910030ABCA /* RunningWaitingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE40BB1B2967E4910030ABCA /* RunningWaitingVC.swift */; }; CE40BB1E2968054F0030ABCA /* BaseResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE40BB1D2968054F0030ABCA /* BaseResponse.swift */; }; CE40BB20296805F70030ABCA /* NetworkResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE40BB1F296805F70030ABCA /* NetworkResult.swift */; }; @@ -173,6 +174,7 @@ CE17F0372961BF8B00E1DED0 /* FontLiterals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontLiterals.swift; sourceTree = ""; }; CE29D581296402B500F47542 /* CourseDrawingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingVC.swift; sourceTree = ""; }; CE29D583296416D800F47542 /* caculateStatusBarHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = caculateStatusBarHeight.swift; sourceTree = ""; }; + CE3A53C4296C6017003D518C /* KeychainManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = ""; }; CE40BB1B2967E4910030ABCA /* RunningWaitingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunningWaitingVC.swift; sourceTree = ""; }; CE40BB1D2968054F0030ABCA /* BaseResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseResponse.swift; sourceTree = ""; }; CE40BB1F296805F70030ABCA /* NetworkResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResult.swift; sourceTree = ""; }; @@ -883,6 +885,7 @@ CE29D583296416D800F47542 /* caculateStatusBarHeight.swift */, CE14677729658C7200DCEA1B /* Stopwatch.swift */, CE9291282965E01D0010959C /* RNTimeFormatter.swift */, + CE3A53C4296C6017003D518C /* KeychainManager.swift */, ); path = Utils; sourceTree = ""; @@ -1290,6 +1293,7 @@ CE5875A4296015D2005D967E /* Encodable+.swift in Sources */, A3BC2F4129667A0D00198261 /* NicknameEditorVC.swift in Sources */, CE0C23742966D62A00B45063 /* PagedView.swift in Sources */, + CE3A53C5296C6017003D518C /* KeychainManager.swift in Sources */, CE14677A2965A80700DCEA1B /* CustomBottomSheetVC.swift in Sources */, CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */, CE40BB2D296808B00030ABCA /* DepartureSearchingRouter.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Utils/KeychainManager.swift b/Runnect-iOS/Runnect-iOS/Global/Utils/KeychainManager.swift new file mode 100644 index 00000000..4fd75aa4 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Utils/KeychainManager.swift @@ -0,0 +1,105 @@ +// +// KeychainManager.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/09. +// + +import UIKit + +struct KeychainManager { + + static let shared = KeychainManager() + + private let service = Bundle.main.bundleIdentifier + private let deviceId = "deviceId" + + private init() {} + + func storeDeviceId() -> Bool { + guard let service = service else { + print("Keychain >> addItem Fail with no service") + return false + } + + let query: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: deviceId, + kSecValueData: setDeviceID().data(using: .utf8, allowLossyConversion: false)!] + + // keychain 에 저장을 수행한 결과 값 반환 (true / false) + let status: OSStatus = SecItemAdd(query as CFDictionary, nil) + if status == errSecSuccess { + print("") + print("Keychain >> addItem() : Success Status : \(status)]") + print("") + return true + } else { + print("") + print("[Keychain >> addItem() : Fail Status : \(status)]") + print("") + return false + } + } + + func getDeviceId() -> String { + guard let service = service else { + print("Keychain >> getDeviceId Fail with no service") + return "" + } + + let query: [CFString: Any] = [kSecClass: kSecClassGenericPassword, // 보안 데이터 저장 + kSecAttrService: service, + kSecAttrAccount: deviceId, + kSecReturnData: true, + kSecReturnAttributes: true, + kSecMatchLimit: kSecMatchLimitOne] + + var dataTypeRef: CFTypeRef? + let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef) + + if status == errSecSuccess { + guard let existingItem = dataTypeRef as? [String: Any] + else { + print("Keychain >> getDeviceID() : Type Check : false") + return "" + } + let deviceData = existingItem[kSecValueData as String] as? Data + let uuidData = String(data: deviceData!, encoding: .utf8)! + + print("Keychain >> getDeviceID() : Success Status : \(status)") + return uuidData + } else if status == errSecItemNotFound || status == -25300 { + print("Keychain >> getDeviceID() : Fail Status : 저장된 데이터가 없습니다") + return "" + } else { + print("Keychain >> getDeviceID() : Fail Status : \(status)") + return "" + } + } + + func deleteDeviceID() -> Bool { + guard let service = self.service + else { + print("Keychain >> deleteDeviceID() : Service Check : false") + return false + } + + let query: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: deviceId] + + let status: OSStatus = SecItemDelete(query as CFDictionary) + if status == errSecSuccess { + print("Keychain >> deleteDeviceID() : Success Status : \(status)") + return true + } else { + print("Keychain >> deleteDeviceID() : Fail Status : \(status)") + return false + } + } + + func setDeviceID() -> String { + return UIDevice.current.identifierForVendor!.uuidString + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift index d30571b6..0f4dffcf 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInVC.swift @@ -162,7 +162,6 @@ extension SignInVC { do { let responseDto = try result.map(BaseResponse.self) if responseDto.status == 200 { - UserDefaultKeyList.Auth.didSignIn = true self.pushToTabBarController() } else { self.showToast(message: responseDto.message) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift index 4fa32798..59385253 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift @@ -40,8 +40,16 @@ final class SplashVC: UIViewController { extension SplashVC { private func checkDidSignIn() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - let needAuth = (UserDefaultKeyList.Auth.didSignIn == nil) - needAuth ? self.pushToSignInView() : self.pushToTabBarController() + let deviceId = KeychainManager.shared.getDeviceId() + + if deviceId.isEmpty { + let deviceIdStoreSuccess = KeychainManager.shared.storeDeviceId() + guard deviceIdStoreSuccess else { return } + self.pushToSignInView() + return + } + + self.pushToTabBarController() } }