fix(watch-connectivity): improve WCSession lifecycle and message reliability
This commit is contained in:
@@ -3,21 +3,20 @@ import WatchConnectivity
|
||||
|
||||
class PhoneConnector: NSObject, ObservableObject, WCSessionDelegate {
|
||||
static let shared = PhoneConnector()
|
||||
private var workoutManager: WorkoutManager?
|
||||
var workoutManager: WorkoutManager? {
|
||||
didSet {
|
||||
if let pending = pendingWorkouts {
|
||||
pending.forEach { workoutManager?.addWorkoutFromPhone($0) }
|
||||
pendingWorkouts = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
private var pendingWorkouts: [StoredWorkout]?
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
func setup(workoutManager: WorkoutManager) {
|
||||
self.workoutManager = workoutManager
|
||||
if WCSession.isSupported() {
|
||||
let session = WCSession.default
|
||||
session.delegate = self
|
||||
session.activate()
|
||||
}
|
||||
}
|
||||
|
||||
// Send completed workout data to phone
|
||||
static func sendCompletedWorkout(_ laps: [[String: Any]], duration: TimeInterval, workoutId: String) {
|
||||
let message: [String: Any] = [
|
||||
@@ -29,7 +28,8 @@ class PhoneConnector: NSObject, ObservableObject, WCSessionDelegate {
|
||||
|
||||
if WCSession.default.isReachable {
|
||||
WCSession.default.sendMessage(message, replyHandler: nil) { error in
|
||||
print("Failed to send: \(error)")
|
||||
print("[PhoneConnector] sendMessage failed, falling back to transferUserInfo: \(error)")
|
||||
WCSession.default.transferUserInfo(message)
|
||||
}
|
||||
} else {
|
||||
WCSession.default.transferUserInfo(message)
|
||||
@@ -39,32 +39,66 @@ class PhoneConnector: NSObject, ObservableObject, WCSessionDelegate {
|
||||
// MARK: - WCSessionDelegate
|
||||
|
||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||
print("WatchConnectivity activated: \(activationState.rawValue)")
|
||||
print("[PhoneConnector] Activated: state=\(activationState.rawValue), isReachable=\(session.isReachable)")
|
||||
}
|
||||
|
||||
func sessionReachabilityDidChange(_ session: WCSession) {
|
||||
print("[PhoneConnector] Reachability changed: isReachable=\(session.isReachable)")
|
||||
}
|
||||
|
||||
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
|
||||
print("[PhoneConnector] didReceiveMessage (no reply)")
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.handleMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
|
||||
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
|
||||
print("[PhoneConnector] didReceiveMessage (with reply)")
|
||||
replyHandler(["status": "received"])
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.handleMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any]) {
|
||||
print("[PhoneConnector] didReceiveUserInfo")
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.handleMessage(userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleMessage(_ message: [String: Any]) {
|
||||
guard let type = message["type"] as? String else { return }
|
||||
guard let type = message["type"] as? String else {
|
||||
print("[PhoneConnector] No type in message: \(message.keys)")
|
||||
return
|
||||
}
|
||||
|
||||
print("[PhoneConnector] Received message type: \(type)")
|
||||
|
||||
switch type {
|
||||
case "workoutPlan":
|
||||
if let data = try? JSONSerialization.data(withJSONObject: message),
|
||||
let workout = try? JSONDecoder().decode(StoredWorkout.self, from: data) {
|
||||
workoutManager?.addWorkoutFromPhone(workout)
|
||||
guard let data = try? JSONSerialization.data(withJSONObject: message) else {
|
||||
print("[PhoneConnector] Failed to serialize message")
|
||||
return
|
||||
}
|
||||
print("[PhoneConnector] JSON data: \(String(data: data, encoding: .utf8) ?? "nil")")
|
||||
|
||||
do {
|
||||
let workout = try JSONDecoder().decode(StoredWorkout.self, from: data)
|
||||
print("[PhoneConnector] Decoded workout: \(workout.name ?? "nil"), sets: \(workout.sets.count)")
|
||||
if let manager = workoutManager {
|
||||
manager.addWorkoutFromPhone(workout)
|
||||
} else {
|
||||
print("[PhoneConnector] workoutManager not set, queuing workout")
|
||||
if pendingWorkouts == nil { pendingWorkouts = [] }
|
||||
pendingWorkouts?.append(workout)
|
||||
}
|
||||
} catch {
|
||||
print("[PhoneConnector] Decode error: \(error)")
|
||||
}
|
||||
default:
|
||||
break
|
||||
print("[PhoneConnector] Unknown type: \(type)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user