From 722d489ef8cc36e6a87474726edfd908b7b48c10 Mon Sep 17 00:00:00 2001 From: yeonsu Date: Wed, 24 Apr 2024 19:16:47 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[Feat]=20#181=20-=20AppStore=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EC=B2=B4=ED=81=AC=20=EC=BD=94=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DontBe-iOS.xcodeproj/project.pbxproj | 12 +++++++ .../Global/Shared/AppStoreCheckManager.swift | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift 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/Global/Shared/AppStoreCheckManager.swift b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift new file mode 100644 index 00000000..27ff692d --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift @@ -0,0 +1,36 @@ +// +// 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() -> String? { + let appleID = "6475622329" + guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(6475622329)&country=kr"), + 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 + } + + // 앱 스토어로 이동 -> urlStr 에 appStoreOpenUrlString 넣으면 이동 + func openAppStore() { + guard let url = URL(string: AppStoreCheckManager.appStoreOpenUrlString) else { return } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } +} From 7b2e94a99e2298e102ff16cf26ceef1232178323 Mon Sep 17 00:00:00 2001 From: yeonsu Date: Wed, 24 Apr 2024 19:47:08 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[Feat]=20#181=20-=20=EC=95=B1=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=ED=99=95=EC=9D=B8=20=ED=9B=84=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EB=9D=84=EC=9A=B0=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application/SceneDelegate.swift | 67 ++++++++++++++++--- .../Global/Shared/AppStoreCheckManager.swift | 26 ++++--- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index e96d5bb6..6a687b7c 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 { + self.showUpdateAlert(version: marketingVersion) + } + } + } + } + } + + func showUpdateAlert(version: String) { + let alert = UIAlertController( + title: "v 1.1.0 업데이트 안내\nDon't be가 업데이트 되었습니다.", + message: "•눌러서 바로 이동할 수 있는 링크를 삽입할 수 있어요.\n•내 글에 답글을 달거나 좋아요를 누른 상대의 프로필로 이동할 수 있어요.\n•그 외 자잘한 오류들을 해결했어요.", + 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/Shared/AppStoreCheckManager.swift b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift index 27ff692d..25cd9c64 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift +++ b/DontBe-iOS/DontBe-iOS/Global/Shared/AppStoreCheckManager.swift @@ -10,23 +10,29 @@ 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() -> String? { + func latestVersion(completion: @escaping (String?) -> Void) { let appleID = "6475622329" - guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(6475622329)&country=kr"), - 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 + guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(appleID)&country=kr") else { + completion(nil) + return } - return appStoreVersion + + 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() } - // 앱 스토어로 이동 -> urlStr 에 appStoreOpenUrlString 넣으면 이동 func openAppStore() { guard let url = URL(string: AppStoreCheckManager.appStoreOpenUrlString) else { return } if UIApplication.shared.canOpenURL(url) { From 1b9a5e309e91b909fdc2e0c793f2d2ade7392e14 Mon Sep 17 00:00:00 2001 From: yeonsu Date: Wed, 24 Apr 2024 19:49:26 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[Feat]=20#181=20-=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=20Literals=EB=A1=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift | 4 ++-- DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index 6a687b7c..ad179856 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -108,8 +108,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func showUpdateAlert(version: String) { let alert = UIAlertController( - title: "v 1.1.0 업데이트 안내\nDon't be가 업데이트 되었습니다.", - message: "•눌러서 바로 이동할 수 있는 링크를 삽입할 수 있어요.\n•내 글에 답글을 달거나 좋아요를 누른 상대의 프로필로 이동할 수 있어요.\n•그 외 자잘한 오류들을 해결했어요.", + title: StringLiterals.VersionUpdate.versionTitle, + message: StringLiterals.VersionUpdate.versionMessage, preferredStyle: .alert ) diff --git a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift index 9afe2f44..16d99d65 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift +++ b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift @@ -24,7 +24,7 @@ enum StringLiterals { static let writePopupCancleButtonTitle = "취소" static let writePopupConfirmButtonTitle = "삭제" } - + enum Login { static let title = "온화한 커뮤니티\nDON’T BE에서 만나요." } @@ -178,4 +178,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•그 외 자잘한 오류들을 해결했어요." + } } From 7b90879dcdb5d37691d3cebf085a60eb34668dca Mon Sep 17 00:00:00 2001 From: yeonsu Date: Wed, 24 Apr 2024 20:29:36 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[=08Delete]=20#181=20-=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index ad179856..173e34b4 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -99,7 +99,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { self.showUpdateAlert(version: marketingVersion) } else { - self.showUpdateAlert(version: marketingVersion) + print("현재 최신버전입니다.") } } } From 41950b906eb733735f1f3a672916a9de03707c01 Mon Sep 17 00:00:00 2001 From: yeonsu Date: Wed, 24 Apr 2024 20:30:17 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[Feat]=20#181=20-=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index 173e34b4..c4dd49d6 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -91,7 +91,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let splitCurrentProjectVersion = currentProjectVersion.split(separator: ".").map { $0 } if splitCurrentProjectVersion.count > 0 && splitMarketingVersion.count > 0 { - + if splitCurrentProjectVersion[0] < splitMarketingVersion[0] { self.showUpdateAlert(version: marketingVersion) @@ -122,4 +122,4 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { [ cancelAction, updateAction ].forEach { alert.addAction($0) } window?.rootViewController?.present(alert, animated: true, completion: nil) } - } +}