Files
coach-ios/ios/App/App/CoachLiveBridge.swift
Sylvain b2e9836b95 feat(ios): plugin Capacitor CoachLiveBridge (Phase 3) — relais WCSession -> /live
CAPPlugin + CAPBridgedPlugin (jsName CoachLiveBridge). Active WCSession au load(),
reçoit didReceiveMessage (temps réel) + didReceiveUserInfo (lot bufferisé) et
relaie au JS via notifyListeners("liveSample"). Enregistré dans
MainViewController.capacitorDidLoad(). Méthode getStatus pour debug JS. Build OK.

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

81 lines
2.8 KiB
Swift

// CoachLiveBridge.swift
// Plugin Capacitor (côté iPhone) : reçoit les samples de séance poussés par
// l'app watchOS CoachWatch via WatchConnectivity et les relaie au JS via
// l'event "liveSample" (consommé par la page web /live).
//
// Enregistrement : MainViewController.capacitorDidLoad() ->
// bridge?.registerPluginInstance(CoachLiveBridgePlugin())
//
// Usage JS :
// const CoachLiveBridge = registerPlugin('CoachLiveBridge');
// CoachLiveBridge.addListener('liveSample', (s) => { ... });
// // s.heartRate, s.activeEnergyKcal, s.distanceMeters, s.elapsedSec, s.ts
import Foundation
import Capacitor
import WatchConnectivity
@objc(CoachLiveBridgePlugin)
public class CoachLiveBridgePlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "CoachLiveBridgePlugin"
public let jsName = "CoachLiveBridge"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "getStatus", returnType: CAPPluginReturnPromise)
]
override public func load() {
super.load()
guard WCSession.isSupported() else {
CAPLog.print("⚡️ CoachLiveBridge: WCSession non supporté sur cet appareil")
return
}
let session = WCSession.default
session.delegate = self
session.activate()
}
@objc func getStatus(_ call: CAPPluginCall) {
let session = WCSession.default
call.resolve([
"supported": WCSession.isSupported(),
"activated": session.activationState == .activated,
"paired": session.isPaired,
"watchAppInstalled": session.isWatchAppInstalled,
"reachable": session.isReachable
])
}
private func emit(_ sample: [String: Any]) {
DispatchQueue.main.async { [weak self] in
self?.notifyListeners("liveSample", data: sample)
}
}
}
extension CoachLiveBridgePlugin: WCSessionDelegate {
public func session(_ session: WCSession,
activationDidCompleteWith activationState: WCSessionActivationState,
error: Error?) {}
public func sessionDidBecomeInactive(_ session: WCSession) {}
public func sessionDidDeactivate(_ session: WCSession) {
// Réactiver pour les sessions futures (ex. changement d'Apple Watch).
WCSession.default.activate()
}
// Temps réel : un sample envoyé via sendMessage.
public func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
emit(message)
}
// Livraison différée : lot de samples envoyé via transferUserInfo.
public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
if let samples = userInfo["samples"] as? [[String: Any]] {
for sample in samples { emit(sample) }
} else {
emit(userInfo)
}
}
}