// // PhoneSync.swift // Keging // // 워치 연동 (iOS 측) — 세트 구성을 워치로 보내고, 워치에서 완주한 기록을 받는다 // import WatchConnectivity final class PhoneSync: NSObject, WCSessionDelegate { static let shared = PhoneSync() private override init() { super.init() } func activate() { guard WCSession.isSupported() else { return } let session = WCSession.default session.delegate = self session.activate() SettingsStore.shared.onConfigChange = { [weak self] config in self?.pushConfig(config) } } func pushConfig(_ config: WorkoutConfig) { guard WCSession.isSupported(), WCSession.default.activationState == .activated else { return } guard let data = try? JSONEncoder().encode(config) else { return } try? WCSession.default.updateApplicationContext(["config": data]) } // MARK: WCSessionDelegate nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { guard activationState == .activated else { return } Task { @MainActor in PhoneSync.shared.pushConfig(SettingsStore.shared.config) } } nonisolated func sessionDidBecomeInactive(_ session: WCSession) {} nonisolated func sessionDidDeactivate(_ session: WCSession) { session.activate() } /// 워치가 닿게 되면 최신 세팅을 재푸시 — 변경 시점에 전송이 유실됐어도 여기서 복구 nonisolated func sessionReachabilityDidChange(_ session: WCSession) { guard session.isReachable else { return } Task { @MainActor in PhoneSync.shared.pushConfig(SettingsStore.shared.config) } } /// 워치 앱이 열릴 때 보내는 세팅 요청 — 폰 앱이 꺼져 있어도 시스템이 깨워서 응답한다 nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) { guard message["request"] as? String == "config" else { replyHandler([:]) return } Task { @MainActor in let data = (try? JSONEncoder().encode(SettingsStore.shared.config)) ?? Data() replyHandler(["config": data]) } } nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) { guard let data = userInfo["record"] as? Data, let record = try? JSONDecoder().decode(SessionRecord.self, from: data) else { return } Task { @MainActor in RecordStore.shared.append(record) } } }