Skip to content

Commit

Permalink
[Feat] #225 - 앱 업데이트 체크 로직 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
hyesuuou committed Jan 25, 2024
1 parent e9bb3f9 commit b5a9afb
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 116 deletions.
56 changes: 52 additions & 4 deletions iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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 */; };
Expand Down Expand Up @@ -224,6 +227,9 @@
09F6718F29CB6AB400708725 /* OnboardingFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFooterView.swift; sourceTree = "<group>"; };
09F6719429CBFCD200708725 /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
09F6719629CC81B500708725 /* DetailAchievementCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailAchievementCollectionViewCell.swift; sourceTree = "<group>"; };
155E45522B5BB8AC008628E7 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = API_KEY.plist; sourceTree = "<group>"; };
155E45682B5FF2EE008628E7 /* FirebaseUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseUtil.swift; sourceTree = "<group>"; };
155E456C2B62B1A1008628E7 /* UpdateCheckViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCheckViewController.swift; sourceTree = "<group>"; };
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 = "<group>"; };
3B027A79299C31B500BEB65C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -301,7 +307,6 @@
6CA208352A1957CA001C4247 /* AuthAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPI.swift; sourceTree = "<group>"; };
6CA208392A195906001C4247 /* AuthResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResponseDTO.swift; sourceTree = "<group>"; };
6CA2B7BA2A222D2300A9E549 /* ValueOnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueOnboardingViewController.swift; sourceTree = "<group>"; };
6CBE702C2A5AA29E00A7EC30 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = API_KEY.plist; sourceTree = "<group>"; };
6CC54C192A28C3AE00AAD76D /* value.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = value.json; sourceTree = "<group>"; };
6CD4F8B929AA493600CCC740 /* RecommendActionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendActionHeaderView.swift; sourceTree = "<group>"; };
6CD4F8BB29AA494300CCC740 /* RecommendActionFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendActionFooterView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -594,13 +600,45 @@
path = ViewControllers;
sourceTree = "<group>";
};
155E45642B5FF089008628E7 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
155E45672B5FF2DE008628E7 /* External */ = {
isa = PBXGroup;
children = (
155E45682B5FF2EE008628E7 /* FirebaseUtil.swift */,
);
path = External;
sourceTree = "<group>";
};
155E456A2B62B17D008628E7 /* UpdateCheck */ = {
isa = PBXGroup;
children = (
155E456B2B62B18F008628E7 /* ViewControllers */,
);
path = UpdateCheck;
sourceTree = "<group>";
};
155E456B2B62B18F008628E7 /* ViewControllers */ = {
isa = PBXGroup;
children = (
155E456C2B62B1A1008628E7 /* UpdateCheckViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
};
3B027A6B299C31B500BEB65C = {
isa = PBXGroup;
children = (
3B710A5B2A62D4AB00E95620 /* Settings.bundle */,
3BDE6157299EDD02001CCEA9 /* .swiftlint.yml */,
3B027A76299C31B500BEB65C /* iOS-NOTTODO */,
3B027A75299C31B500BEB65C /* Products */,
155E45642B5FF089008628E7 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -681,6 +719,7 @@
3B027A90299C33CA00BEB65C /* Network */ = {
isa = PBXGroup;
children = (
155E45672B5FF2DE008628E7 /* External */,
093DB0312A1468F100ECA5F6 /* Service */,
093DB02F2A1468CE00ECA5F6 /* DataModel */,
093DB02B2A14687300ECA5F6 /* API */,
Expand All @@ -692,6 +731,7 @@
3B027A97299C343D00BEB65C /* Presentation */ = {
isa = PBXGroup;
children = (
155E456A2B62B17D008628E7 /* UpdateCheck */,
3B03D0D32B0F157700302872 /* NotificatoinDialog */,
09F6717E29CAD68100708725 /* Onboarding */,
3B027A9B299C348800BEB65C /* Achievement */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -1170,6 +1210,7 @@
0943A9F42A531D0000614761 /* Amplitude */,
09C8602C2AB14B4800C4F4B1 /* FSCalendar */,
3B2B59432AEB814B00B4619A /* FirebaseMessaging */,
155E45652B5FF089008628E7 /* FirebaseRemoteConfig */,
);
productName = "iOS-NOTTODO";
productReference = 3B027A74299C31B500BEB65C /* iOS-NOTTODO.app */;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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" */;
Expand Down
112 changes: 2 additions & 110 deletions iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Amplitude

import Firebase
import FirebaseMessaging
import FirebaseRemoteConfig

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
Expand All @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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)
}
}
}
}
3 changes: 1 addition & 2 deletions iOS-NOTTODO/iOS-NOTTODO/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,7 +52,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}

extension SceneDelegate {

func changeRootViewControllerTo(_ viewController: UIViewController) {
guard let window = window else { return }

Expand Down
3 changes: 3 additions & 0 deletions iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ struct I18N {
최신 업데이트가 있습니다.
업데이트하시겠습니까?
"""
static func forceUpdateAlert(newVersion: String) -> String {
return "낫투두의 새로운 버전이 있습니다. \(newVersion)버전 으로 업데이트 해주세요."
}
static let later = "나중에"
static let notiDialogTitle = """
알림을 허용하면
Expand Down
47 changes: 47 additions & 0 deletions iOS-NOTTODO/iOS-NOTTODO/Network/External/FirebaseUtil.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading

0 comments on commit b5a9afb

Please sign in to comment.