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>
77 lines
2.5 KiB
Swift
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() }
|
|
}
|
|
}
|
|
}
|