Skip to content

Commit 3c2eaf1

Browse files
committed
[feat] #173 버전 체크 로직 추가
1 parent 5e7ba2a commit 3c2eaf1

File tree

6 files changed

+135
-8
lines changed

6 files changed

+135
-8
lines changed

Projects/CoreKit/Sources/Data/DTO/Version/VersionResponse.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@
88
import Foundation
99

1010
public struct VersionResponse: Decodable {
11-
public let recentVersion: String
11+
public let results: [VersionDTO]
12+
}
13+
14+
public struct VersionDTO: Decodable {
15+
public let version: String
16+
public let trackId: Int
1217
}
1318

1419
extension VersionResponse {
15-
static let mock: Self = Self(recentVersion: "1.0.0")
20+
static let mock: Self = Self(results: [VersionDTO(version: "1.0.0", trackId: 2415354644)])
1621
}

Projects/CoreKit/Sources/Data/Network/Version/VersionEndpoint.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ public enum VersionEndpoint {
1616

1717
extension VersionEndpoint: TargetType {
1818
public var baseURL: URL {
19-
return Constants.serverURL.appendingPathComponent(Constants.versionPath, conformingTo: .url)
19+
let bundleID = Bundle.main.bundleIdentifier ?? ""
20+
let countryCode = Locale.current.language.region?.identifier ?? ""
21+
return URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleID)&country=\(countryCode)")!
2022
}
2123

2224
public var path: String {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// VersionResponse+Extension.swift
3+
// Domain
4+
//
5+
// Created by 김민호 on 12/30/24.
6+
//
7+
8+
import Foundation
9+
10+
import CoreKit
11+
12+
public extension VersionResponse {
13+
func toDomain() -> Version {
14+
return .init(
15+
self.results.first?.version ?? "",
16+
trackId: self.results.first?.trackId ?? 0
17+
)
18+
}
19+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// Version.swift
3+
// Domain
4+
//
5+
// Created by 김민호 on 12/30/24.
6+
//
7+
8+
import Foundation
9+
10+
public struct Version: Comparable {
11+
let major: Int
12+
let minor: Int
13+
let patch: Int
14+
public let trackId: Int
15+
16+
public init(_ version: String, trackId: Int) {
17+
let components = version.split(separator: ".").compactMap { Int($0) }
18+
self.major = components.count > 0 ? components[0] : 0
19+
self.minor = components.count > 1 ? components[1] : 0
20+
self.patch = components.count > 2 ? components[2] : 0
21+
self.trackId = trackId
22+
}
23+
24+
public static func < (
25+
lhs: Version,
26+
rhs: Version
27+
) -> Bool {
28+
if lhs.major != rhs.major {
29+
return lhs.major < rhs.major
30+
}
31+
return lhs.minor < rhs.minor
32+
}
33+
34+
public static func == (
35+
lhs: Version,
36+
rhs: Version
37+
) -> Bool {
38+
return lhs.major == rhs.major &&
39+
lhs.minor == rhs.minor
40+
}
41+
42+
}

Projects/Feature/FeatureLogin/Sources/Splash/SplashFeature.swift

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import Foundation
88

99
import ComposableArchitecture
1010
import CoreKit
11+
import Domain
1112
import Util
13+
import UIKit
1214

1315
@Reducer
1416
public struct SplashFeature {
@@ -21,10 +23,13 @@ public struct SplashFeature {
2123
var authClient
2224
@Dependency(KeychainClient.self)
2325
var keychain
26+
@Dependency(VersionClient.self)
27+
var versionClient
2428
/// - State
2529
@ObservableState
26-
public struct State: Equatable {
30+
public struct State {
2731
@Shared(.appStorage("isNeedSessionDeleted")) var isNeedSessionDeleted: Bool = true
32+
@Presents var alert: AlertState<Action.Alert>?
2833
public init() {}
2934
}
3035
/// - Action
@@ -36,18 +41,26 @@ public struct SplashFeature {
3641
case delegate(DelegateAction)
3742

3843
@CasePathable
39-
public enum View: Equatable {
44+
public enum View: BindableAction, Equatable {
45+
case binding(BindingAction<State>)
4046
case onAppear
4147
}
4248
public enum InnerAction: Equatable {
4349
case 키_제거
50+
case 앱스토어_알림_활성화(trackId: Int)
51+
}
52+
public enum AsyncAction: Equatable { case 없음 }
53+
@CasePathable
54+
public enum ScopeAction {
55+
case alert(PresentationAction<Alert>)
4456
}
45-
public enum AsyncAction: Equatable { case doNothing }
46-
public enum ScopeAction: Equatable { case doNothing }
4757
public enum DelegateAction: Equatable {
4858
case loginNeeded
4959
case autoLoginSuccess
5060
}
61+
public enum Alert {
62+
case 앱스토어_이동(trackId: Int)
63+
}
5164
}
5265
/// initiallizer
5366
public init() {}
@@ -73,17 +86,34 @@ public struct SplashFeature {
7386
}
7487
/// - Reducer body
7588
public var body: some ReducerOf<Self> {
89+
BindingReducer(action: \.view)
7690
Reduce(self.core)
91+
.ifLet(\.$alert, action: \.scope.alert)
7792
}
7893
}
7994
//MARK: - FeatureAction Effect
8095
private extension SplashFeature {
8196
/// - View Effect
8297
func handleViewAction(_ action: Action.View, state: inout State) -> Effect<Action> {
8398
switch action {
99+
case .binding:
100+
return .none
101+
84102
case .onAppear:
85103
return .run { [isNeedSessionDeleted = state.isNeedSessionDeleted] send in
86104
try await self.clock.sleep(for: .milliseconds(2000))
105+
/// Version Check
106+
let response = try await versionClient.버전체크().toDomain()
107+
guard
108+
let info = Bundle.main.infoDictionary,
109+
let currentVersion = info["CFBundleShortVersionString"] as? String else { return }
110+
let appStoreVersion = response
111+
let nowVersion = Version(currentVersion, trackId: response.trackId)
112+
113+
if nowVersion < appStoreVersion {
114+
await send(.inner(.앱스토어_알림_활성화(trackId: response.trackId)))
115+
return
116+
}
87117
if isNeedSessionDeleted {
88118
guard let platform = userDefaults.stringKey(.authPlatform) else {
89119
print("platform이 없어서 벗어남")
@@ -161,6 +191,18 @@ private extension SplashFeature {
161191
await userDefaults.removeString(.authPlatform)
162192
await isNeedSessionDeleted.withLock { $0 = false }
163193
}
194+
195+
case let .앱스토어_알림_활성화(trackId):
196+
state.alert = .init(title: {
197+
TextState("업데이트")
198+
}, actions: {
199+
ButtonState(role: .none, action: .앱스토어_이동(trackId: trackId)) {
200+
TextState("앱스토어 이동")
201+
}
202+
}, message: {
203+
TextState("최신버전의 포킷으로 업데이트가 필요합니다.")
204+
})
205+
return .none
164206
}
165207
}
166208
/// - Async Effect
@@ -169,10 +211,25 @@ private extension SplashFeature {
169211
}
170212
/// - Scope Effect
171213
func handleScopeAction(_ action: Action.ScopeAction, state: inout State) -> Effect<Action> {
214+
switch action {
215+
case let .alert(.presented(.앱스토어_이동(trackId))):
216+
if let url = URL(string: "https://apps.apple.com/app/id\(trackId)"),
217+
UIApplication.shared.canOpenURL(url) {
218+
UIApplication.shared.open(url, options: [:], completionHandler: nil)
219+
}
220+
return .none
221+
222+
case .alert:
223+
return .none
224+
}
172225
return .none
173226
}
174227
/// - Delegate Effect
175228
func handleDelegateAction(_ action: Action.DelegateAction, state: inout State) -> Effect<Action> {
176229
return .none
177230
}
231+
232+
func versionCheck() -> Effect<Action> {
233+
return .none
234+
}
178235
}

Projects/Feature/FeatureLogin/Sources/Splash/SplashView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import ComposableArchitecture
1313
@ViewAction(for: SplashFeature.self)
1414
public struct SplashView: View {
1515
/// - Properties
16-
public let store: StoreOf<SplashFeature>
16+
@Perception.Bindable
17+
public var store: StoreOf<SplashFeature>
1718
/// - Initializer
1819
public init(store: StoreOf<SplashFeature>) {
1920
self.store = store
@@ -44,6 +45,7 @@ public extension SplashView {
4445
.pokit(.bg(.brand))
4546
.ignoresSafeArea()
4647
}
48+
.alert($store.scope(state: \.alert, action: \.scope.alert))
4749
.onAppear { send(.onAppear) }
4850
}
4951
}

0 commit comments

Comments
 (0)