Skip to content

Commit a877efa

Browse files
authored
#240 merge: PR Merge
[Feat] #237 - 목표 걸음 수 달성 시 푸시알림 구현 및 관련 로직 SceneDelegate로 이관
2 parents ea3d5ea + b66b1f8 commit a877efa

File tree

48 files changed

+694
-284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+694
-284
lines changed

Walkie-iOS/.package.resolved

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"originHash" : "434e6874234260de72f92c8a7a78ffc2b0be6dcf595eba9d81ef583c1d81f71e",
2+
"originHash" : "8c3e485804de5dc2d14505d69859c0cd7cd3d8ba82f4862dcfeab25f2b8f66a1",
33
"pins" : [
44
{
55
"identity" : "abseil-cpp-binary",
@@ -109,6 +109,15 @@
109109
"version" : "2.24.4"
110110
}
111111
},
112+
{
113+
"identity" : "kingfisher",
114+
"kind" : "remoteSourceControl",
115+
"location" : "https://github.com/onevcat/Kingfisher",
116+
"state" : {
117+
"revision" : "2015fda791daa72c8058619545a593bf8c1dd59f",
118+
"version" : "8.5.0"
119+
}
120+
},
112121
{
113122
"identity" : "leveldb",
114123
"kind" : "remoteSourceControl",

Walkie-iOS/Project.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ let project = Project(
8282
"UISceneConfigurations": [:]
8383
],
8484
"BGTaskSchedulerPermittedIdentifiers": [
85-
"com.walkie.ios.step"
85+
"com.walkie.ios.step",
86+
"com.walkie.ios.step-goal"
8687
],
8788
"UIBackgroundModes": [
8889
"fetch",
@@ -126,6 +127,7 @@ let project = Project(
126127
],
127128
settings: .settings(
128129
base: [
130+
"IPHONEOS_DEPLOYMENT_TARGET": "18.0",
129131
"ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS": "YES",
130132
"MARKETING_VERSION": settingVersion,
131133
"OTHER_LDFLAGS": "-ObjC",
@@ -162,6 +164,7 @@ let project = Project(
162164
],
163165
settings: .settings(
164166
base: [
167+
"IPHONEOS_DEPLOYMENT_TARGET": "18.0",
165168
"ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS": "YES",
166169
"TARGETED_DEVICE_FAMILY": "1",
167170
"MARKETING_VERSION": settingVersion
@@ -185,7 +188,12 @@ let project = Project(
185188
]
186189
),
187190
sources: "WalkieCommon/Sources/**",
188-
resources: "WalkieCommon/Resources/**"
191+
resources: "WalkieCommon/Resources/**",
192+
settings: .settings(
193+
base: [
194+
"IPHONEOS_DEPLOYMENT_TARGET": "18.0"
195+
]
196+
)
189197
),
190198
]
191199
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "ic_egg_broken.png",
5+
"idiom" : "universal",
6+
"scale" : "1x"
7+
},
8+
{
9+
"filename" : "[email protected]",
10+
"idiom" : "universal",
11+
"scale" : "2x"
12+
},
13+
{
14+
"filename" : "[email protected]",
15+
"idiom" : "universal",
16+
"scale" : "3x"
17+
}
18+
],
19+
"info" : {
20+
"author" : "xcode",
21+
"version" : 1
22+
}
23+
}
1.32 KB
Loading
2.71 KB
Loading
4.1 KB
Loading

Walkie-iOS/Walkie-iOS/Sources/App/AppDelegate.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,42 @@
88
import Foundation
99
import Firebase
1010
import UserNotifications
11+
import BackgroundTasks
12+
import UIKit
1113

1214
class AppDelegate: NSObject, UIApplicationDelegate {
15+
1316
func application(
1417
_ application: UIApplication,
1518
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
1619
) -> Bool {
1720
FirebaseApp.configure()
1821
UNUserNotificationCenter.current().delegate = self
19-
20-
let _: UNAuthorizationOptions = [.alert, .badge, .sound]
2122
application.registerForRemoteNotifications()
2223
Messaging.messaging().delegate = self
2324

25+
registerBackgroundTasks()
26+
2427
return true
2528
}
29+
30+
func application(
31+
_ application: UIApplication,
32+
configurationForConnecting connectingSceneSession: UISceneSession,
33+
options: UIScene.ConnectionOptions
34+
) -> UISceneConfiguration {
35+
let sceneConfiguration = UISceneConfiguration(
36+
name: "Default Configuration",
37+
sessionRole: connectingSceneSession.role
38+
)
39+
sceneConfiguration.delegateClass = SceneDelegate.self
40+
return sceneConfiguration
41+
}
42+
43+
private func registerBackgroundTasks() {
44+
BGTaskManager.shared.registerBackgroundTasks(.step)
45+
BGTaskManager.shared.registerBackgroundTasks(.stepGoal)
46+
}
2647
}
2748

2849
extension AppDelegate: UNUserNotificationCenterDelegate {

Walkie-iOS/Walkie-iOS/Sources/App/Coordinator/CoordinatorImpl/AppCoordinator.swift

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import Observation
1414

1515
extension Notification.Name {
1616
static let reissueFailed = Notification.Name("reissueFailed")
17+
static let appDidEnterBackground = Notification.Name("appDidEnterBackground")
18+
static let appWillEnterForeground = Notification.Name("appWillEnterForeground")
1719
}
1820

1921
@Observable
@@ -54,13 +56,33 @@ final class AppCoordinator: Coordinator, ObservableObject {
5456
self.diContainer = diContainer
5557
self.remoteConfigManager = remoteConfigManager
5658
initializeCoordinator()
59+
bindNotifications()
60+
}
61+
62+
private func bindNotifications() {
5763
NotificationCenter.default
5864
.publisher(for: .reissueFailed)
5965
.receive(on: DispatchQueue.main)
6066
.sink { [weak self] _ in
6167
self?.changeToSplash()
6268
}
6369
.store(in: &cancellables)
70+
71+
NotificationCenter.default
72+
.publisher(for: .appDidEnterBackground)
73+
.receive(on: DispatchQueue.main)
74+
.sink { [weak self] _ in
75+
self?.executeBackgroundActions()
76+
}
77+
.store(in: &cancellables)
78+
79+
NotificationCenter.default
80+
.publisher(for: .appWillEnterForeground)
81+
.receive(on: DispatchQueue.main)
82+
.sink { [weak self] _ in
83+
self?.executeForegroundActions()
84+
}
85+
.store(in: &cancellables)
6486
}
6587

6688
private func initializeCoordinator() {
@@ -357,25 +379,16 @@ final class AppCoordinator: Coordinator, ObservableObject {
357379
stepCoordinator?.stopStepUpdates()
358380
}
359381

360-
func handleStepRefresh(task: BGAppRefreshTask) {
361-
stepCoordinator?.handleStepRefresh(task: task)
362-
}
363-
364382
func executeForegroundActions() {
365383
if UserManager.shared.hasUserToken {
366-
// 포그라운드 실시간 걸음 수 추적 시작
367384
self.startStepUpdates()
368-
// 백그라운드 스케줄링 모두 취소
369385
BGTaskManager.shared.cancelAll()
370386
}
371387
}
372388

373389
func executeBackgroundActions() {
374390
if UserManager.shared.hasUserToken {
375-
// 포그라운드 실시간 걸음 수 추적 종료
376391
self.stopStepUpdates()
377-
// 백그라운드 작업 스케줄링
378-
BGTaskManager.shared.scheduleAppRefresh(.step)
379392
}
380393
}
381394
}

Walkie-iOS/Walkie-iOS/Sources/App/Coordinator/CoordinatorImpl/StepCoordinator.swift

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77

88
import Combine
9-
import BackgroundTasks
9+
import Foundation
1010
import Observation
1111

1212
@Observable
@@ -25,7 +25,6 @@ final class StepCoordinator {
2525
private let updateStepForegroundUseCase: UpdateStepForegroundUseCase
2626
private let checkHatchConditionUseCase: CheckHatchConditionUseCase
2727
private let updateEggStepUseCase: UpdateEggStepUseCase
28-
private let updateStepBackgroundUseCase: UpdateStepBackgroundUseCase
2928
private let stepStatusStore: StepStatusStore
3029

3130
// MARK: - AppCoordinator
@@ -38,7 +37,6 @@ final class StepCoordinator {
3837
self.updateStepForegroundUseCase = diContainer.resolveUpdateStepForegroundUseCase()
3938
self.checkHatchConditionUseCase = diContainer.resolveCheckHatchConditionUseCase()
4039
self.updateEggStepUseCase = diContainer.resolveUpdateEggStepUseCase()
41-
self.updateStepBackgroundUseCase = diContainer.resolveUpdateStepBackgroundUseCase()
4240
self.stepStatusStore = diContainer.stepStatusStore
4341
}
4442

@@ -117,33 +115,4 @@ final class StepCoordinator {
117115
updateStepForegroundUseCase.stop()
118116
cancellables.removeAll()
119117
}
120-
121-
// MARK: - Background 걸음 수 측정
122-
func handleStepRefresh(task: BGAppRefreshTask) {
123-
task.expirationHandler = {
124-
print("⏳ 백그라운드 테스크 만료 ⏳")
125-
task.setTaskCompleted(success: false)
126-
}
127-
128-
if stepStatusStore.getNeedStep() > 10000 {
129-
task.setTaskCompleted(success: true)
130-
print("⏳ 백그라운드 걸음 수 업데이트 및 스케줄링 하지 않음 : 알 없음 ⏳")
131-
return
132-
}
133-
134-
updateStepBackgroundUseCase.execute()
135-
print("⏳ 백그라운드 걸음 수 업데이트 완료 ⏳")
136-
task.setTaskCompleted(success: true)
137-
138-
if checkHatchCondition() {
139-
print("⏳ 백그라운드 걸음 수 업데이트 스케줄링 중단 : 부화 조건 달성, 푸시 알림 전송 ⏳")
140-
NotificationManager.shared.scheduleNotification(
141-
title: NotificationLiterals.eggHatch.title,
142-
body: NotificationLiterals.eggHatch.body
143-
)
144-
} else {
145-
print("⏳ 백그라운드 걸음 수 업데이트 스케줄링 ⏳")
146-
BGTaskManager.shared.scheduleAppRefresh(.step)
147-
}
148-
}
149118
}

Walkie-iOS/Walkie-iOS/Sources/App/Manager/BGTaskManager.swift

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,37 @@ import BackgroundTasks
1111
final class BGTaskManager {
1212
static let shared = BGTaskManager()
1313

14+
private var stepRefreshHandler: ((BGAppRefreshTask) -> Void)?
15+
private var stepGoalHandler: ((BGAppRefreshTask) -> Void)?
16+
1417
public init() {}
1518

16-
// 백그라운드 작업 등록
17-
func registerBackgroundTasks(_ task: WalkieBackgroundTask, action: @escaping (BGAppRefreshTask) async -> Void) {
18-
BGTaskScheduler.shared.register(forTaskWithIdentifier: task.rawValue, using: nil) { task in
19+
func registerBackgroundTasks(_ task: WalkieBackgroundTask) {
20+
BGTaskScheduler.shared.register(forTaskWithIdentifier: task.rawValue, using: nil) { [weak self] task in
1921
guard let refreshTask = task as? BGAppRefreshTask else { return }
20-
print("⏳ 백그라운드 테스크 작업 시작 : \(task)")
21-
Task {
22-
await action(refreshTask)
22+
print("⏳ 백그라운드 테스크 작업 시작 : \(task.identifier)")
23+
24+
switch task.identifier {
25+
case WalkieBackgroundTask.step.rawValue:
26+
if let handler = self?.stepRefreshHandler {
27+
handler(refreshTask)
28+
} else {
29+
print("⚠️ step 핸들러가 설정되지 않았습니다 ⚠️")
30+
refreshTask.setTaskCompleted(success: false)
31+
}
32+
case WalkieBackgroundTask.stepGoal.rawValue:
33+
if let handler = self?.stepGoalHandler {
34+
handler(refreshTask)
35+
} else {
36+
print("⚠️ stepGoal 핸들러가 설정되지 않았습니다 ⚠️")
37+
refreshTask.setTaskCompleted(success: false)
38+
}
39+
default:
40+
break
2341
}
2442
}
2543
}
2644

27-
// 가벼운 작업 바로 스케줄링
2845
func scheduleAppRefresh(_ task: WalkieBackgroundTask) {
2946
let request = BGAppRefreshTaskRequest(identifier: task.rawValue)
3047
request.earliestBeginDate = Date(timeIntervalSinceNow: .leastNonzeroMagnitude)
@@ -38,9 +55,19 @@ final class BGTaskManager {
3855

3956
func cancelAll() {
4057
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: WalkieBackgroundTask.step.rawValue)
58+
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: WalkieBackgroundTask.stepGoal.rawValue)
59+
}
60+
61+
func setStepRefreshHandler(_ handler: @escaping (BGAppRefreshTask) -> Void) {
62+
stepRefreshHandler = handler
63+
}
64+
65+
func setStepGoalHandler(_ handler: @escaping (BGAppRefreshTask) -> Void) {
66+
stepGoalHandler = handler
4167
}
4268
}
4369

4470
enum WalkieBackgroundTask: String {
4571
case step = "com.walkie.ios.step"
72+
case stepGoal = "com.walkie.ios.step-goal"
4673
}

0 commit comments

Comments
 (0)