// // PhoneSync.swift // Keging // // 워치 연동 (iOS 측, WatchConnectivity) — 워치에서 완주한 기록을 받아 병합하고, // 아이폰이 깨운 심박 세션의 저장 결과(saved/failed)를 WatchHeartRateBridge에 전달한다. // 세팅은 기기별 독립(2026-09-03, 7차 — 기기마다 진동 질감이 달라 각자 최적화)이라 push/응답하지 않는다. // 첫 화면 연결 배지는 폐지(2026-09-05) — 워치 사용 여부는 시작 후 startWatchApp 결과로 판정. // 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() } /// 미러링이 안 붙은 채 폰이 단독으로 넘어갈 때 — 워치가 열어 둔 세션이 남지 않게 폐기 명령 /// (sendMessage가 안 닿으면 큐로 — 늦게라도 정리된다) func sendMirrorDiscard() { guard WCSession.isSupported() else { return } let session = WCSession.default guard session.activationState == .activated, session.isPaired, session.isWatchAppInstalled else { return } let payload: [String: Any] = [WatchBridgeResult.commandKey: WatchBridgeResult.discard] if session.isReachable { session.sendMessage(payload, replyHandler: nil) { _ in session.transferUserInfo(payload) } } else { session.transferUserInfo(payload) } } private nonisolated func handle(_ payload: [String: Any]) { if let data = payload["record"] as? Data, let record = try? JSONDecoder().decode(SessionRecord.self, from: data) { Task { @MainActor in RecordStore.shared.append(record) } } if let result = payload[WatchBridgeResult.key] as? String { let saved = result == WatchBridgeResult.saved Task { @MainActor in WatchHeartRateBridge.shared.handleSaveResult(saved: saved) } } } // MARK: WCSessionDelegate nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {} nonisolated func sessionDidBecomeInactive(_ session: WCSession) {} nonisolated func sessionDidDeactivate(_ session: WCSession) { session.activate() } nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) { handle(userInfo) } nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any]) { handle(message) } nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) { handle(message) replyHandler([:]) } }