Files
coach-ios/ios/App/CoachWatch/ConnectivityManager.swift
Sylvain 5864cfcbef feat(watchos): ConnectivityManager (WCSession) — envoi des samples vers l'iPhone
sendMessage si iPhone joignable, sinon buffer + transferUserInfo (livraison
différée). Délégué WCSession hors-main, hop vers main pour @Published isReachable,
buffer sérialisé sur file dédiée. Build watchsimulator OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:11:58 +02:00

77 lines
2.5 KiB
Swift

import Foundation
import WatchConnectivity
/// Envoie les samples de séance vers l'iPhone.
/// - `sendMessage` quand l'iPhone est joignable (temps réel)
/// - sinon buffer + `transferUserInfo` (livraison différée garantie)
final class ConnectivityManager: NSObject, ObservableObject {
static let shared = ConnectivityManager()
@Published private(set) var isReachable = false
private let queue = DispatchQueue(label: "ch.hypnotruck.coach.connectivity")
private var buffer: [[String: Any]] = []
private override init() {
super.init()
guard WCSession.isSupported() else { return }
let session = WCSession.default
session.delegate = self
session.activate()
}
func sendSample(_ payload: [String: Any]) {
queue.async {
let session = WCSession.default
guard session.activationState == .activated else {
self.buffer.append(payload)
return
}
if session.isReachable {
session.sendMessage(payload, replyHandler: nil) { [weak self] _ in
// échec d'envoi temps réel -> bascule en livraison différée
self?.queue.async {
self?.buffer.append(payload)
self?.flushLocked()
}
}
} else {
self.buffer.append(payload)
self.flushLocked()
}
}
}
/// À appeler sur `queue` uniquement.
private func flushLocked() {
guard !buffer.isEmpty else { return }
let session = WCSession.default
guard session.activationState == .activated else { return }
session.transferUserInfo(["samples": buffer])
buffer.removeAll()
}
private func updateReachable(_ value: Bool) {
DispatchQueue.main.async { [weak self] in self?.isReachable = value }
}
}
extension ConnectivityManager: WCSessionDelegate {
func session(_ session: WCSession,
activationDidCompleteWith activationState: WCSessionActivationState,
error: Error?) {
updateReachable(session.isReachable)
if activationState == .activated {
queue.async { [weak self] in self?.flushLocked() }
}
}
func sessionReachabilityDidChange(_ session: WCSession) {
let reachable = session.isReachable
updateReachable(reachable)
if reachable {
queue.async { [weak self] in self?.flushLocked() }
}
}
}