Skip to content

Commit

Permalink
[Feat/#243] 앱 강제 업데이트 기능 구현
Browse files Browse the repository at this point in the history
- 업데이트 판단: 현재 기기의 앱 버전과 앱스토어 버전을 비교해서, 앱스토어 버전이 크다면 업데이트
- 업데이트 체크 시점: 앱 시작될 경우, ScenePhase가 .active될 경우
- 알랏 틴트 색상 강제 적용
  • Loading branch information
JINi0S committed Feb 6, 2025
1 parent d204079 commit 17d52b4
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 3 deletions.
4 changes: 4 additions & 0 deletions ILSANG.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
607FCC332C01AA7300BB2D04 /* SubmitAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FCC322C01AA7300BB2D04 /* SubmitAlertView.swift */; };
608EBF9F2C39C17F00B862CC /* Dictionary++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608EBF9E2C39C17F00B862CC /* Dictionary++.swift */; };
608EBFA12C39C5BB00B862CC /* String++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608EBFA02C39C5BB00B862CC /* String++.swift */; };
6090A5F52D53AC3300A01429 /* AppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6090A5F42D53AC3300A01429 /* AppVersionManager.swift */; };
60924DC92C48C00E00221072 /* Quest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60924DC82C48C00E00221072 /* Quest.swift */; };
60943FE62C0A38FB00C8A714 /* ApprovalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60943FE52C0A38FB00C8A714 /* ApprovalViewModel.swift */; };
609A76D92CFC50C7009F4567 /* QuestImageWithTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 609A76D82CFC50C7009F4567 /* QuestImageWithTagView.swift */; };
Expand Down Expand Up @@ -213,6 +214,7 @@
607FCC322C01AA7300BB2D04 /* SubmitAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmitAlertView.swift; sourceTree = "<group>"; };
608EBF9E2C39C17F00B862CC /* Dictionary++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary++.swift"; sourceTree = "<group>"; };
608EBFA02C39C5BB00B862CC /* String++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String++.swift"; sourceTree = "<group>"; };
6090A5F42D53AC3300A01429 /* AppVersionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionManager.swift; sourceTree = "<group>"; };
60924DC82C48C00E00221072 /* Quest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Quest.swift; sourceTree = "<group>"; };
60943FE52C0A38FB00C8A714 /* ApprovalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApprovalViewModel.swift; sourceTree = "<group>"; };
609A76D82CFC50C7009F4567 /* QuestImageWithTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestImageWithTagView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -337,6 +339,7 @@
600D83A22C7B1F7E005C93E2 /* Manager */ = {
isa = PBXGroup;
children = (
6090A5F42D53AC3300A01429 /* AppVersionManager.swift */,
600D83A32C7B1FA4005C93E2 /* PaginationManager.swift */,
6053345B2D31182500599159 /* XpLevelCalculator.swift */,
);
Expand Down Expand Up @@ -950,6 +953,7 @@
A1868C442C09B6C50020BF16 /* ChallengeDetailView.swift in Sources */,
6044B71D2C32B6A4002C13A0 /* UIImage++.swift in Sources */,
607FCBD42BFA648000BB2D04 /* Tab.swift in Sources */,
6090A5F52D53AC3300A01429 /* AppVersionManager.swift in Sources */,
6011891F2C3E94380070F2AD /* AuthUser.swift in Sources */,
60299E312CBFFF160039663F /* TransferableUIImage.swift in Sources */,
A1FF91722C257E9A00F03E4B /* User.swift in Sources */,
Expand Down
45 changes: 45 additions & 0 deletions ILSANG/Sources/Manager/AppVersionManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// AppVersionManager.swift
// ILSANG
//
// Created by Lee Jinhee on 2/5/25.
//

import UIKit

final class AppVersionManager {
static let shared = AppVersionManager()
private let appStoreOpenUrlStr = "itms-apps://itunes.apple.com/app/apple-store/6504427618"

private init() { }

func isUpdateAvailable() async throws -> Bool {
guard let info = Bundle.main.infoDictionary,
let currentVersion = info["CFBundleShortVersionString"] as? String, // 현재 버전 가져오기
let identifier = info["CFBundleIdentifier"] as? String, // 앱 번들아이디 가져오기
let url = URL(string: "http://itunes.apple.com/kr/lookup?bundleId=\(identifier)") else {
throw VersionError.invalidBundleInfo
}

let (data, _) = try await URLSession.shared.data(from: url) // 비동기 네트워크 요청
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], // 네트워크 응답 파싱
let result = (json["results"] as? [[String: Any]])?.first,
let appStoreVersion = result["version"] as? String else {
throw VersionError.invalidResponse
}

return currentVersion.compare(appStoreVersion, options: .numeric) == .orderedAscending // 현재 앱의 버전과 앱스토어 버전을 비교해서 업데이트 가능 여부 반환
}

// 앱 스토어로 이동
func openAppStore() {
guard let url = URL(string: appStoreOpenUrlStr) else { return }
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}

enum VersionError: Error {
case invalidResponse, invalidBundleInfo
}
35 changes: 32 additions & 3 deletions ILSANG/Sources/Views/ILSANGApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ struct ILSANGApp: App {
@State private var isTutorialVisible = Bool()
@State private var isSplashScreenVisible = true

// 강제 업데이트 관련
@State private var needUpdate = false
@Environment(\.scenePhase) var scenePhase

init() {
setTabBarAppearance()
setAppearance()
}

var body: some Scene {
Expand All @@ -32,6 +36,16 @@ struct ILSANGApp: App {
})
}
}
.alert("업데이트 알림", isPresented: $needUpdate, actions: {
Button("업데이트") { AppVersionManager.shared.openAppStore() }
}, message: {
Text("일상이 새롭게 업데이트되었습니다!\n변화된 일상을 만나보세요.")
})
.onChange(of: scenePhase, { _, newValue in
if newValue == .active {
Task { await checkAndUpdateVersionIfNeeded() }
}
})
.onChange(of: isLogin, { _, newValue in // 로그인 후 튜토리얼 UI 표시
if newValue {
isTutorialVisible = true
Expand All @@ -53,17 +67,32 @@ struct ILSANGApp: App {
let _ = await UserService.shared.login()
}

// 3. 스플래시 화면 종료
// 3. 업데이트 확인
await checkAndUpdateVersionIfNeeded()

// 4. 스플래시 화면 종료
isSplashScreenVisible = false
}

func setTabBarAppearance() {
private func checkAndUpdateVersionIfNeeded() async {
do {
needUpdate = try await AppVersionManager.shared.isUpdateAvailable()
} catch {
Log("버전 확인 중 오류 발생: \(error)")
}
}

func setAppearance() {
// 탭바
let appearance = UITabBarAppearance()
appearance.backgroundColor = UIColor(.white)
appearance.shadowColor = UIColor(.grayDD)
appearance.stackedItemPositioning = .centered
UITabBar.appearance().standardAppearance = appearance
UITabBar.appearance().scrollEdgeAppearance = appearance

// 틴트 컬러 적용
UIView.appearance().tintColor = UIColor(named: "AccentColor") // 파란색으로 버튼이 보여지는 문제 방지 (Alert에서 문제 발생)
}
}

Expand Down

0 comments on commit 17d52b4

Please sign in to comment.