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>
81 lines
2.8 KiB
Swift
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)
|
|
}
|
|
}
|
|
}
|