From b5a9afb63ce7841994cb2b035860ea98dde4a19b Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Fri, 26 Jan 2024 01:28:04 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[Feat]=20#225=20-=20=EC=95=B1=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=B2=B4=ED=81=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iOS-NOTTODO.xcodeproj/project.pbxproj | 56 +++++- .../iOS-NOTTODO/Application/AppDelegate.swift | 112 +---------- .../Application/SceneDelegate.swift | 3 +- .../iOS-NOTTODO/Global/Literals/Strings.swift | 3 + .../Network/External/FirebaseUtil.swift | 47 +++++ .../UpdateCheckViewController.swift | 180 ++++++++++++++++++ 6 files changed, 285 insertions(+), 116 deletions(-) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Network/External/FirebaseUtil.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/UpdateCheck/ViewControllers/UpdateCheckViewController.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj index 81370737..1e141b91 100644 --- a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj +++ b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj @@ -62,6 +62,10 @@ 09F6719029CB6AB400708725 /* OnboardingFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F6718F29CB6AB400708725 /* OnboardingFooterView.swift */; }; 09F6719529CBFCD200708725 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F6719429CBFCD200708725 /* GradientView.swift */; }; 09F6719729CC81B500708725 /* DetailAchievementCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F6719629CC81B500708725 /* DetailAchievementCollectionViewCell.swift */; }; + 155E45532B5BB8AC008628E7 /* API_KEY.plist in Resources */ = {isa = PBXBuildFile; fileRef = 155E45522B5BB8AC008628E7 /* API_KEY.plist */; }; + 155E45662B5FF089008628E7 /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 155E45652B5FF089008628E7 /* FirebaseRemoteConfig */; }; + 155E45692B5FF2EE008628E7 /* FirebaseUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155E45682B5FF2EE008628E7 /* FirebaseUtil.swift */; }; + 155E456D2B62B1A1008628E7 /* UpdateCheckViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155E456C2B62B1A1008628E7 /* UpdateCheckViewController.swift */; }; 3B027A78299C31B500BEB65C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027A77299C31B500BEB65C /* AppDelegate.swift */; }; 3B027A7A299C31B500BEB65C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027A79299C31B500BEB65C /* SceneDelegate.swift */; }; 3B027A7C299C31B500BEB65C /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027A7B299C31B500BEB65C /* AuthViewController.swift */; }; @@ -151,7 +155,6 @@ 6CA208362A1957CA001C4247 /* AuthAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CA208352A1957CA001C4247 /* AuthAPI.swift */; }; 6CA2083A2A195906001C4247 /* AuthResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CA208392A195906001C4247 /* AuthResponseDTO.swift */; }; 6CA2B7BB2A222D2300A9E549 /* ValueOnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CA2B7BA2A222D2300A9E549 /* ValueOnboardingViewController.swift */; }; - 6CBE702D2A5AA29E00A7EC30 /* API_KEY.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6CBE702C2A5AA29E00A7EC30 /* API_KEY.plist */; }; 6CC54C1A2A28C3AE00AAD76D /* value.json in Resources */ = {isa = PBXBuildFile; fileRef = 6CC54C192A28C3AE00AAD76D /* value.json */; }; 6CD4F8BA29AA493600CCC740 /* RecommendActionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD4F8B929AA493600CCC740 /* RecommendActionHeaderView.swift */; }; 6CD4F8BC29AA494300CCC740 /* RecommendActionFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD4F8BB29AA494300CCC740 /* RecommendActionFooterView.swift */; }; @@ -224,6 +227,9 @@ 09F6718F29CB6AB400708725 /* OnboardingFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFooterView.swift; sourceTree = ""; }; 09F6719429CBFCD200708725 /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = ""; }; 09F6719629CC81B500708725 /* DetailAchievementCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailAchievementCollectionViewCell.swift; sourceTree = ""; }; + 155E45522B5BB8AC008628E7 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = API_KEY.plist; sourceTree = ""; }; + 155E45682B5FF2EE008628E7 /* FirebaseUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseUtil.swift; sourceTree = ""; }; + 155E456C2B62B1A1008628E7 /* UpdateCheckViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCheckViewController.swift; sourceTree = ""; }; 3B027A74299C31B500BEB65C /* iOS-NOTTODO.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS-NOTTODO.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B027A77299C31B500BEB65C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 3B027A79299C31B500BEB65C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -301,7 +307,6 @@ 6CA208352A1957CA001C4247 /* AuthAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPI.swift; sourceTree = ""; }; 6CA208392A195906001C4247 /* AuthResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResponseDTO.swift; sourceTree = ""; }; 6CA2B7BA2A222D2300A9E549 /* ValueOnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueOnboardingViewController.swift; sourceTree = ""; }; - 6CBE702C2A5AA29E00A7EC30 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = API_KEY.plist; sourceTree = ""; }; 6CC54C192A28C3AE00AAD76D /* value.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = value.json; sourceTree = ""; }; 6CD4F8B929AA493600CCC740 /* RecommendActionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendActionHeaderView.swift; sourceTree = ""; }; 6CD4F8BB29AA494300CCC740 /* RecommendActionFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendActionFooterView.swift; sourceTree = ""; }; @@ -335,6 +340,7 @@ 6C44127129A35A1000313C3F /* KakaoSDK in Frameworks */, 3B146DA4299D0A8600B17B62 /* Then in Frameworks */, 3B146DA7299D0AA300B17B62 /* Moya in Frameworks */, + 155E45662B5FF089008628E7 /* FirebaseRemoteConfig in Frameworks */, 3B2B59442AEB814B00B4619A /* FirebaseMessaging in Frameworks */, 6C44127729A35A1000313C3F /* KakaoSDKNavi in Frameworks */, 6C44128129A35A1000313C3F /* KakaoSDKUser in Frameworks */, @@ -594,6 +600,37 @@ path = ViewControllers; sourceTree = ""; }; + 155E45642B5FF089008628E7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 155E45672B5FF2DE008628E7 /* External */ = { + isa = PBXGroup; + children = ( + 155E45682B5FF2EE008628E7 /* FirebaseUtil.swift */, + ); + path = External; + sourceTree = ""; + }; + 155E456A2B62B17D008628E7 /* UpdateCheck */ = { + isa = PBXGroup; + children = ( + 155E456B2B62B18F008628E7 /* ViewControllers */, + ); + path = UpdateCheck; + sourceTree = ""; + }; + 155E456B2B62B18F008628E7 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + 155E456C2B62B1A1008628E7 /* UpdateCheckViewController.swift */, + ); + path = ViewControllers; + sourceTree = ""; + }; 3B027A6B299C31B500BEB65C = { isa = PBXGroup; children = ( @@ -601,6 +638,7 @@ 3BDE6157299EDD02001CCEA9 /* .swiftlint.yml */, 3B027A76299C31B500BEB65C /* iOS-NOTTODO */, 3B027A75299C31B500BEB65C /* Products */, + 155E45642B5FF089008628E7 /* Frameworks */, ); sourceTree = ""; }; @@ -681,6 +719,7 @@ 3B027A90299C33CA00BEB65C /* Network */ = { isa = PBXGroup; children = ( + 155E45672B5FF2DE008628E7 /* External */, 093DB0312A1468F100ECA5F6 /* Service */, 093DB02F2A1468CE00ECA5F6 /* DataModel */, 093DB02B2A14687300ECA5F6 /* API */, @@ -692,6 +731,7 @@ 3B027A97299C343D00BEB65C /* Presentation */ = { isa = PBXGroup; children = ( + 155E456A2B62B17D008628E7 /* UpdateCheck */, 3B03D0D32B0F157700302872 /* NotificatoinDialog */, 09F6717E29CAD68100708725 /* Onboarding */, 3B027A9B299C348800BEB65C /* Achievement */, @@ -769,7 +809,7 @@ 3B027AA6299C359900BEB65C /* Resource */ = { isa = PBXGroup; children = ( - 6CBE702C2A5AA29E00A7EC30 /* API_KEY.plist */, + 155E45522B5BB8AC008628E7 /* API_KEY.plist */, 3B3EF2F72AF35C90001F79BC /* GoogleService-Info.plist */, 3B027A85299C31B600BEB65C /* Info.plist */, 3B027AAA299C35D000BEB65C /* Assets */, @@ -1170,6 +1210,7 @@ 0943A9F42A531D0000614761 /* Amplitude */, 09C8602C2AB14B4800C4F4B1 /* FSCalendar */, 3B2B59432AEB814B00B4619A /* FirebaseMessaging */, + 155E45652B5FF089008628E7 /* FirebaseRemoteConfig */, ); productName = "iOS-NOTTODO"; productReference = 3B027A74299C31B500BEB65C /* iOS-NOTTODO.app */; @@ -1231,11 +1272,11 @@ 3B710A5C2A62D4AB00E95620 /* Settings.bundle in Resources */, 3B027A84299C31B600BEB65C /* LaunchScreen.storyboard in Resources */, 6CC54C1A2A28C3AE00AAD76D /* value.json in Resources */, + 155E45532B5BB8AC008628E7 /* API_KEY.plist in Resources */, 3B3EF2F82AF35C90001F79BC /* GoogleService-Info.plist in Resources */, 6C049A312A595C670085E40B /* logo.mp4 in Resources */, 3B027A81299C31B600BEB65C /* Assets.xcassets in Resources */, 3B146D9A299D079D00B17B62 /* Pretendard-Light.otf in Resources */, - 6CBE702D2A5AA29E00A7EC30 /* API_KEY.plist in Resources */, 3B146D98299D077800B17B62 /* Pretendard-Medium.otf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1330,6 +1371,7 @@ 6CA208302A1925EE001C4247 /* RecommendActionResponseDTO.swift in Sources */, 09F6718629CB26E400708725 /* OnboardingHeaderView.swift in Sources */, 3B11740D2A4B574B0033DDF3 /* CALayer+.swift in Sources */, + 155E456D2B62B1A1008628E7 /* UpdateCheckViewController.swift in Sources */, 3B14A13D29A6FBD300F92897 /* UIView+.swift in Sources */, 09F6719529CBFCD200708725 /* GradientView.swift in Sources */, 3B4E12F82A27C12F001D1EC1 /* WithdrawModalView.swift in Sources */, @@ -1393,6 +1435,7 @@ 3B0CBA222A45FC170004F2DB /* UpdateMissionResponseDTO.swift in Sources */, 3B892ABE2A2FBDDE00A316BC /* AddMissionAPI.swift in Sources */, 092C09B72A48596500E9B06B /* DeleteModalView.swift in Sources */, + 155E45692B5FF2EE008628E7 /* FirebaseUtil.swift in Sources */, 6CF4706329A690CD008D145C /* NetworkResult.swift in Sources */, 3B9532F42A284CC1006510F8 /* ModalProtocol.swift in Sources */, 3B5F8F8329BF90290063A7F8 /* SituationCollectionViewCell.swift in Sources */, @@ -1716,6 +1759,11 @@ package = 09C8602B2AB14B4700C4F4B1 /* XCRemoteSwiftPackageReference "FSCalendar" */; productName = FSCalendar; }; + 155E45652B5FF089008628E7 /* FirebaseRemoteConfig */ = { + isa = XCSwiftPackageProductDependency; + package = 3B2B59422AEB814B00B4619A /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseRemoteConfig; + }; 3B146DA0299D0A7A00B17B62 /* SnapKit */ = { isa = XCSwiftPackageProductDependency; package = 3B146D9F299D0A7A00B17B62 /* XCRemoteSwiftPackageReference "SnapKit" */; diff --git a/iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift b/iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift index 77f8729b..57bed8ea 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift @@ -16,6 +16,7 @@ import Amplitude import Firebase import FirebaseMessaging +import FirebaseRemoteConfig @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -27,9 +28,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Amplitude.instance().initializeApiKey(Bundle.main.amplitudeAPIKey) KakaoSDK.initSDK(appKey: Bundle.main.kakaoAPIKey) FirebaseApp.configure() - - checkForUpdate() - + // 메시지 대리자 설정 Messaging.messaging().delegate = self @@ -42,20 +41,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } - func skipAuthView() { - // 홈 화면으로 바로 이동 - DispatchQueue.main.async { - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let window = windowScene.windows.first { - let tabBarController = TabBarController() - let navigationController = UINavigationController(rootViewController: tabBarController) - navigationController.isNavigationBarHidden = true - window.rootViewController = navigationController - window.makeKeyAndVisible() - } - } - } - func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken @@ -99,96 +84,3 @@ extension AppDelegate: UNUserNotificationCenterDelegate { completionHandler() } } - -extension AppDelegate { - func checkForUpdate() { - // 앱스토어 버전 - guard let appstoreVersion = getAppstoreVersion() else { return } - - // 현재 설치된 앱의 버전 - guard let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { return } - - if compareVersion(userVersion: appVersion, appstoreVersion: appstoreVersion) { - DispatchQueue.main.async { - self.showUpdateAlert() - } - } else { - if KeychainUtil.getAccessToken() != "" { - self.skipAuthView() - print("토큰 유효") - } - } - } - - /// 버전 비교하는 메서드 - func compareVersion(userVersion: String, appstoreVersion: String) -> Bool { - let userMajor = userVersion.split(separator: ".").map {Int($0)!}[0] - let appstoreMajor = appstoreVersion.split(separator: ".").map {Int($0)!}[0] - - if userMajor < appstoreMajor { - return true - } - - let userMinor = userVersion.split(separator: ".").map {Int($0)!}[1] - let appstoreMinor = appstoreVersion.split(separator: ".").map {Int($0)!}[1] - - if userMinor < appstoreMinor { - return true - } - - let userPatch = userVersion.split(separator: ".").map {Int($0)!}[2] - let appstorePatch = appstoreVersion.split(separator: ".").map {Int($0)!}[2] - - if userPatch < appstorePatch { - return true - } - - return false - } - - /// 앱스토어에 배포된 버전 가져오는 메서드 - func getAppstoreVersion() -> String? { - let appleID = Bundle.main.appleId - guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(appleID)"), - let data = try? Data(contentsOf: url), - let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any], - let results = json["results"] as? [[String: Any]], - let appStoreVersion = results[0]["version"] as? String else { - return nil - } - return appStoreVersion - } - - /// 선택 업데이트 경고창 - func showUpdateAlert() { - let alertController = UIAlertController( - title: I18N.update, - message: I18N.updateAlert, - preferredStyle: .alert - ) - - let updateAction = UIAlertAction(title: I18N.update, style: .default) { _ in - // App Store로 이동 - if let appStoreURL = URL(string: "https://itunes.apple.com/app/\(Bundle.main.appleId)") { - UIApplication.shared.open(appStoreURL, options: [:], completionHandler: {_ in - if KeychainUtil.getAccessToken() != "" { - self.skipAuthView() - print("토큰 유효") - } - }) - } - } - - let cancelAction = UIAlertAction(title: I18N.later, style: .default) - - alertController.addAction(updateAction) - alertController.addAction(cancelAction) - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { - if let keyWindow = windowScene.windows.first, - let rootViewController = keyWindow.rootViewController { - rootViewController.present(alertController, animated: true, completion: nil) - } - } - } -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Application/SceneDelegate.swift b/iOS-NOTTODO/iOS-NOTTODO/Application/SceneDelegate.swift index 5751950f..eed04f6c 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Application/SceneDelegate.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Application/SceneDelegate.swift @@ -18,7 +18,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let window = UIWindow(windowScene: windowScene) window.overrideUserInterfaceStyle = UIUserInterfaceStyle.light - let rootViewController = ValueOnboardingViewController() + let rootViewController = UpdateCheckViewController() let navigationController = UINavigationController(rootViewController: rootViewController) navigationController.isNavigationBarHidden = true window.rootViewController = navigationController @@ -52,7 +52,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } extension SceneDelegate { - func changeRootViewControllerTo(_ viewController: UIViewController) { guard let window = window else { return } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift b/iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift index e086c32a..f4c002ef 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift @@ -167,6 +167,9 @@ struct I18N { 최신 업데이트가 있습니다. 업데이트하시겠습니까? """ + static func forceUpdateAlert(newVersion: String) -> String { + return "낫투두의 새로운 버전이 있습니다. \(newVersion)버전 으로 업데이트 해주세요." + } static let later = "나중에" static let notiDialogTitle = """ 알림을 허용하면 diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/External/FirebaseUtil.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/External/FirebaseUtil.swift new file mode 100644 index 00000000..244f6abb --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/External/FirebaseUtil.swift @@ -0,0 +1,47 @@ +// +// FirebaseUtil.swift +// iOS-NOTTODO +// +// Created by 김혜수 on 1/23/24. +// + +import Foundation + +import FirebaseRemoteConfig + +final class FirebaseUtil { + + static let shared = FirebaseUtil() + + private let config = RemoteConfig.remoteConfig() + + enum RemoteConfigType { + case minimumVersion + } + + init() { + self.setRemoteConfigSetting() + } + + func fetchRemoteConfig(type: RemoteConfigType) async -> String? { + return await withCheckedContinuation { continuation in + config.fetch { [weak self] status, _ in + if status == .success { + self?.config.activate() + guard let version = self?.config["minimum_version"].stringValue, !version.isEmpty else { + continuation.resume(returning: nil) + return + } + continuation.resume(returning: version) + } + } + } + } + + private func setRemoteConfigSetting() { + let setting = RemoteConfigSettings() + setting.minimumFetchInterval = 0 + setting.fetchTimeout = 10 + config.configSettings = setting + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/UpdateCheck/ViewControllers/UpdateCheckViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/UpdateCheck/ViewControllers/UpdateCheckViewController.swift new file mode 100644 index 00000000..904585ef --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/UpdateCheck/ViewControllers/UpdateCheckViewController.swift @@ -0,0 +1,180 @@ +// +// UpdateCheckViewController.swift +// iOS-NOTTODO +// +// Created by 김혜수 on 1/26/24. +// + +import UIKit + +final class UpdateCheckViewController: UIViewController { + + enum UpdateType { + case optional + case force(newVersion: String) + case none + } + + enum UpdateCheckError: Error { + case versionFetchError + } + + enum Constant { + static let appstoreURL: String = "itms-apps://itunes.apple.com/app/\(Bundle.main.appleId)" + } + + override func viewDidLoad() { + super.viewDidLoad() + + self.setUI() + self.checkUpdate() + } +} + +extension UpdateCheckViewController { + private func setUI() { + self.view.backgroundColor = .ntdBlack + } + + private func checkUpdate() { + Task { + do { + let updateType = try await checkUpdateType() + switch updateType { + case .force(let newVersion): + self.showForceUpdateAlert(newVersion: newVersion) + case .optional: + self.showUpdateAlert() + case .none: + self.changeMainViewController() + } + } catch { + self.changeMainViewController() + } + } + } + + private func changeMainViewController() { + if KeychainUtil.getAccessToken().isEmpty { + SceneDelegate.shared?.changeRootViewControllerTo(ValueOnboardingViewController()) + } else { + SceneDelegate.shared?.changeRootViewControllerTo(TabBarController()) + } + } + + private func checkUpdateType() async throws -> UpdateType { + // 앱스토어 버전 + guard let appstoreVersion = try await getAppstoreVersion() else { + throw UpdateCheckError.versionFetchError + } + + // 현재 설치된 앱의 버전 + guard let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { + throw UpdateCheckError.versionFetchError + } + + // 최소 지원버전 + guard let minimumVersion = await FirebaseUtil.shared.fetchRemoteConfig(type: .minimumVersion) else { + throw UpdateCheckError.versionFetchError + } + + if shouldUpdate(userVersion: appVersion, appstoreVersion: minimumVersion) { + return .force(newVersion: appstoreVersion) + } + + if shouldUpdate(userVersion: appVersion, appstoreVersion: appstoreVersion) { + return .optional + } + + return .none + } + + /// 버전 비교하는 메서드 + private func shouldUpdate(userVersion: String, appstoreVersion: String) -> Bool { + let userMajor = userVersion.split(separator: ".").map {Int($0)!}[0] + let appstoreMajor = appstoreVersion.split(separator: ".").map {Int($0)!}[0] + + if userMajor < appstoreMajor { + return true + } + + let userMinor = userVersion.split(separator: ".").map {Int($0)!}[1] + let appstoreMinor = appstoreVersion.split(separator: ".").map {Int($0)!}[1] + + if userMinor < appstoreMinor { + return true + } + + let userPatch = userVersion.split(separator: ".").map {Int($0)!}[2] + let appstorePatch = appstoreVersion.split(separator: ".").map {Int($0)!}[2] + + if userPatch < appstorePatch { + return true + } + + return false + } + + /// 앱스토어에 배포된 버전 가져오는 메서드 + private func getAppstoreVersion() async throws -> String? { + let appleID = Bundle.main.appleId + guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(appleID)") else { return nil } + let (data, _) = try await URLSession.shared.data(from: url) + let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] + guard let results = json?["results"] as? [[String: Any]], + let appStoreVersion = results[0]["version"] as? String else { + return nil + } + return appStoreVersion + } + + /// 선택 업데이트 경고창 + private func showUpdateAlert() { + let alertController = UIAlertController( + title: I18N.update, + message: I18N.updateAlert, + preferredStyle: .alert + ) + + let updateAction = UIAlertAction(title: I18N.update, style: .default) { _ in + // App Store로 이동 + if let appStoreURL = URL(string: Constant.appstoreURL) { + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: { [weak self] _ in + self?.changeMainViewController() + }) + } + } + + let cancelAction = UIAlertAction(title: I18N.later, style: .default) { _ in + // App Store로 이동 + if let appStoreURL = URL(string: Constant.appstoreURL) { + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: { [weak self] _ in + self?.changeMainViewController() + }) + } + } + + alertController.addAction(updateAction) + alertController.addAction(cancelAction) + + self.present(alertController, animated: true) + } + + /// 강제 업데이트 경고창 + private func showForceUpdateAlert(newVersion: String) { + let alertController = UIAlertController( + title: I18N.update, + message: I18N.forceUpdateAlert(newVersion: newVersion), + preferredStyle: .alert + ) + + let updateAction = UIAlertAction(title: I18N.update, style: .default) { _ in + // App Store로 이동 + if let appStoreURL = URL(string: Constant.appstoreURL) { + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) + } + } + alertController.addAction(updateAction) + self.present(alertController, animated: true) + } +} From af76f312acdea0fd0cd9005048c294365116f5c7 Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Fri, 26 Jan 2024 01:28:22 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[Fix]=20#225=20-=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=9D=B4=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iOS-NOTTODO/Presentation/Auth/AuthViewController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Auth/AuthViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Auth/AuthViewController.swift index 33af0b2b..416a42a1 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Auth/AuthViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Auth/AuthViewController.swift @@ -254,12 +254,12 @@ extension AuthViewController { } func checkNotificationSettings() { - UNUserNotificationCenter.current().getNotificationSettings { settings in + UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in switch settings.authorizationStatus { case .notDetermined: - self.showNotiDialogView() + self?.showNotiDialogView() default: - break + self?.presentToHomeViewController() } } }