diff --git a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj index 0ee0a16e..443f1b2e 100644 --- a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj +++ b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj @@ -78,6 +78,7 @@ 2F27A3AC2B70B7650018779F /* PostDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F27A3AB2B70B7650018779F /* PostDetailViewController.swift */; }; 2F3182E52B5A3B2400E77EFD /* DontBeDeletePopupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3182E42B5A3B2400E77EFD /* DontBeDeletePopupView.swift */; }; 2F40D5822B58364500AF68BC /* DeletePostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F40D5812B58364500AF68BC /* DeletePostViewModel.swift */; }; + 2F4BE0C62BD90EC4003147E7 /* AppStoreCheckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4BE0C52BD90EC4003147E7 /* AppStoreCheckManager.swift */; }; 2F65B72F2B84D68500775853 /* CopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F65B72E2B84D68500775853 /* CopyableLabel.swift */; }; 2F8735402B4BE65300E55552 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F87353F2B4BE65300E55552 /* HomeView.swift */; }; 2F8735422B4BE66500E55552 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F8735412B4BE66500E55552 /* HomeViewController.swift */; }; @@ -235,6 +236,7 @@ 2F27A3AB2B70B7650018779F /* PostDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDetailViewController.swift; sourceTree = ""; }; 2F3182E42B5A3B2400E77EFD /* DontBeDeletePopupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DontBeDeletePopupView.swift; sourceTree = ""; }; 2F40D5812B58364500AF68BC /* DeletePostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletePostViewModel.swift; sourceTree = ""; }; + 2F4BE0C52BD90EC4003147E7 /* AppStoreCheckManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreCheckManager.swift; sourceTree = ""; }; 2F65B72E2B84D68500775853 /* CopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLabel.swift; sourceTree = ""; }; 2F87353F2B4BE65300E55552 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 2F8735412B4BE66500E55552 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; @@ -684,6 +686,14 @@ path = RequestDTO; sourceTree = ""; }; + 2F4BE0C42BD90EA2003147E7 /* Shared */ = { + isa = PBXGroup; + children = ( + 2F4BE0C52BD90EC4003147E7 /* AppStoreCheckManager.swift */, + ); + path = Shared; + sourceTree = ""; + }; 2FB818CD2B5168C400B7498F /* Post */ = { isa = PBXGroup; children = ( @@ -797,6 +807,7 @@ 3C6193012B3A772B00220CEB /* Global */ = { isa = PBXGroup; children = ( + 2F4BE0C42BD90EA2003147E7 /* Shared */, 3C6193042B3A776C00220CEB /* Extension */, 2A2672002B4C3B37009D214F /* Protocol */, 3C6193052B3A777300220CEB /* Literals */, @@ -1329,6 +1340,7 @@ 2A5220EF2B507F97001510B7 /* NotificationViewModel.swift in Sources */, 2A84465C2B4EEC6C00F98F2A /* JoinProfileViewModel.swift in Sources */, 3CBCA3CC2B573F9000D348D3 /* MyPageProfileViewModel.swift in Sources */, + 2F4BE0C62BD90EC4003147E7 /* AppStoreCheckManager.swift in Sources */, 2F3182E52B5A3B2400E77EFD /* DontBeDeletePopupView.swift in Sources */, 2A5220F22B507FAE001510B7 /* NotificationTableViewCell.swift in Sources */, 3C2854FD2B3A9FD800369C99 /* ExampleViewController.swift in Sources */, diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index e96d5bb6..c4dd49d6 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -10,7 +10,7 @@ import UIKit import KakaoSDKAuth class SceneDelegate: UIResponder, UIWindowSceneDelegate { - + var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { @@ -34,6 +34,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { self.window?.rootViewController = navigationController } self.window?.makeKeyAndVisible() + self.checkAndUpdateIfNeeded() } } @@ -44,35 +45,81 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } } - + 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. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } - + func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } - + func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } - + func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. + self.checkAndUpdateIfNeeded() } - + func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } - - + + + func checkAndUpdateIfNeeded() { + AppStoreCheckManager().latestVersion { marketingVersion in + DispatchQueue.main.async { + guard let marketingVersion = marketingVersion else { + print("앱스토어 버전을 찾지 못했습니다.") + return + } + + let currentProjectVersion = AppStoreCheckManager.appVersion ?? "" + + let splitMarketingVersion = marketingVersion.split(separator: ".").map { $0 } + + let splitCurrentProjectVersion = currentProjectVersion.split(separator: ".").map { $0 } + + if splitCurrentProjectVersion.count > 0 && splitMarketingVersion.count > 0 { + + if splitCurrentProjectVersion[0] < splitMarketingVersion[0] { + self.showUpdateAlert(version: marketingVersion) + + } else if splitCurrentProjectVersion[1] < splitMarketingVersion[1] { + self.showUpdateAlert(version: marketingVersion) + + } else { + print("현재 최신버전입니다.") + } + } + } + } + } + + func showUpdateAlert(version: String) { + let alert = UIAlertController( + title: StringLiterals.VersionUpdate.versionTitle, + message: StringLiterals.VersionUpdate.versionMessage, + preferredStyle: .alert + ) + + let updateAction = UIAlertAction(title: "지금 업데이트", style: .default) { _ in + AppStoreCheckManager().openAppStore() + } + + let cancelAction = UIAlertAction(title: "나중에", style: .destructive, handler: nil) + + [ cancelAction, updateAction ].forEach { alert.addAction($0) } + window?.rootViewController?.present(alert, animated: true, completion: nil) + } } - diff --git a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift index 56fe0ed1..bc910b7d 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift +++ b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift @@ -27,7 +27,7 @@ enum StringLiterals { static let writeOnlyOneLink = "링크는 한 개까지만 삽입할 수 있어요." static let writeErrorLink = "아직 링크로 인식되지 않아요. 다시 확인해 주세요." } - + enum Login { static let title = "온화한 커뮤니티\nDON’T BE에서 만나요." } @@ -181,4 +181,9 @@ enum StringLiterals { static let loadingMessage7 = "Don’t be는 누구도 상처 받지 않고\n스트레스 받지 않는 커뮤니티를 만들려고 해요." static let loadingMessage8 = "저희는 Don’t be를 통해 온라인 환경이\n조금 더 온화해지기를 바라요." } + + enum VersionUpdate { + static let versionTitle = "v 1.1.0 업데이트 안내\nDon't be가 업데이트 되었습니다." + static let versionMessage = "•눌러서 바로 이동할 수 있는 링크를 삽입할 수 있어요.\n•내 글에 답글을 달거나 좋아요를 누른 상대의 프로필로 이동할 수 있어요.\n•그 외 자잘한 오류들을 해결했어요." + } } diff --git a/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift new file mode 100644 index 00000000..25cd9c64 --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift @@ -0,0 +1,42 @@ +// +// AppStoreCheckManager.swift +// DontBe-iOS +// +// Created by yeonsu on 4/24/24. +// + +import UIKit + +class AppStoreCheckManager { + + static let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + static let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String + static let appStoreOpenUrlString = "itms-apps://itunes.apple.com/app/apple-store/6475622329" + + func latestVersion(completion: @escaping (String?) -> Void) { + let appleID = "6475622329" + guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(appleID)&country=kr") else { + completion(nil) + return + } + + URLSession.shared.dataTask(with: url) { (data, response, error) in + guard let data = data, error == nil, + 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 { + completion(nil) + return + } + + completion(appStoreVersion) + }.resume() + } + + func openAppStore() { + guard let url = URL(string: AppStoreCheckManager.appStoreOpenUrlString) else { return } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } +}