fix(watch): 컴플리케이션이 워치 앱을 열지 않아도 갱신되도록 수정

- 워치 앱 시작(App.init) 시점에 WCSession 활성화: 백그라운드로 깨어나
  스냅숏을 받을 수 있도록 델리게이트를 미리 설정
- iPhone이 transferCurrentComplicationUserInfo 전용 채널로도 스냅숏 전송
  (전송 예산 고려: 측정 상태 변화 또는 30분 경과 시에만)
- 워치 didReceiveUserInfo 수신 → 캐시 저장 + 컴플리케이션 타임라인 갱신
- ComplicationStore.defaults 단일 인스턴스화

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
This commit is contained in:
songyc macbook 2026-07-10 14:44:48 +09:00
parent e5550eb106
commit 0cdb566ad5
4 changed files with 38 additions and 4 deletions

View File

@ -9,6 +9,12 @@ import SwiftUI
@main
struct Haru_DanimWatch_Watch_AppApp: App {
init() {
// .
//
WatchStore.shared.activate()
}
var body: some Scene {
WindowGroup {
ContentView()

View File

@ -113,6 +113,16 @@ extension WatchStore: WCSessionDelegate {
WatchStore.shared.apply(decoded)
}
}
/// iPhone .
/// + (apply)
nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
guard let data = userInfo[WatchSync.snapshotKey] as? Data,
let decoded = WatchSnapshot.decode(data) else { return }
Task { @MainActor in
WatchStore.shared.apply(decoded)
}
}
}
// MARK: - ( )

View File

@ -15,9 +15,7 @@ import WidgetKit
// MARK: -
nonisolated enum ComplicationStore {
static var defaults: UserDefaults {
UserDefaults(suiteName: "group.com.yechan.HaruDanim") ?? .standard
}
static let defaults: UserDefaults = UserDefaults(suiteName: "group.com.yechan.HaruDanim") ?? .standard
static func snapshot() -> WatchSnapshot? {
guard let data = defaults.data(forKey: WatchSync.cachedSnapshotKey) else { return nil }

View File

@ -113,13 +113,33 @@ final class WatchSyncManager: NSObject {
return snapshot
}
/// ( )
private var lastComplicationStateKey = ""
private var lastComplicationPushAt = Date.distantPast
/// ( )
func pushSnapshot() {
guard WCSession.isSupported() else { return }
let session = WCSession.default
guard session.activationState == .activated, session.isPaired, session.isWatchAppInstalled else { return }
guard let data = makeSnapshot().encoded() else { return }
let snapshot = makeSnapshot()
guard let data = snapshot.encoded() else { return }
// applicationContext:
try? session.updateApplicationContext([WatchSync.snapshotKey: data])
pushForComplicationIfNeeded(session: session, snapshot: snapshot, data: data)
}
/// .
/// 30
private func pushForComplicationIfNeeded(session: WCSession, snapshot: WatchSnapshot, data: Data) {
guard session.isComplicationEnabled else { return }
let stateKey = "\(snapshot.runningName ?? "")|\(snapshot.extraRunningCount)|\(snapshot.isPremium)"
let now = Date.now
guard stateKey != lastComplicationStateKey
|| now.timeIntervalSince(lastComplicationPushAt) > 30 * 60 else { return }
lastComplicationStateKey = stateKey
lastComplicationPushAt = now
session.transferCurrentComplicationUserInfo([WatchSync.snapshotKey: data])
}
// MARK: