88 lines
3.3 KiB
Swift
88 lines
3.3 KiB
Swift
#if os(iOS)
|
|
import Foundation
|
|
import RemoteCore
|
|
import WatchBridgeCommon
|
|
import WatchConnectivity
|
|
|
|
@MainActor
|
|
private final class PhoneWCSessionSending: RelaySessionSending {
|
|
private let session: WCSession
|
|
|
|
init(session: WCSession) { self.session = session }
|
|
|
|
var activationState: RelayActivationState {
|
|
switch session.activationState {
|
|
case .notActivated: return .notActivated
|
|
case .inactive: return .inactive
|
|
case .activated: return .activated
|
|
@unknown default: return .inactive
|
|
}
|
|
}
|
|
|
|
var isReachable: Bool { session.isReachable }
|
|
func activate() { session.activate() }
|
|
func sendMessage(_ message: [String: Any],
|
|
replyHandler: @escaping ([String: Any]) -> Void,
|
|
errorHandler: @escaping (Error) -> Void) {
|
|
session.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
|
|
}
|
|
func updateApplicationContext(_ context: [String: Any]) throws {
|
|
try session.updateApplicationContext(context)
|
|
}
|
|
}
|
|
|
|
/// iPhone-side WCSession delegate. All UI-facing state changes are hopped to
|
|
/// the main actor; semantic command admission remains in the injected actor.
|
|
@MainActor
|
|
public final class PhoneWCSessionDelegate: NSObject, WCSessionDelegate {
|
|
public let bridge: PhoneRelayBridge
|
|
private let session: WCSession
|
|
|
|
public init(coordinator: any PhoneCommandCoordinating,
|
|
session: WCSession = .default) {
|
|
self.session = session
|
|
self.bridge = PhoneRelayBridge(session: PhoneWCSessionSending(session: session),
|
|
dependency: PhoneRelayDependency(coordinator: coordinator))
|
|
super.init()
|
|
session.delegate = self
|
|
bridge.activate()
|
|
}
|
|
|
|
nonisolated public func session(_ session: WCSession,
|
|
activationDidCompleteWith activationState: WCSessionActivationState,
|
|
error: Error?) {
|
|
Task { @MainActor [weak self] in self?.bridge.activationDidComplete(error: error) }
|
|
}
|
|
|
|
nonisolated public func sessionDidBecomeInactive(_ session: WCSession) {
|
|
Task { @MainActor [weak self] in self?.bridge.didBecomeInactive() }
|
|
}
|
|
|
|
nonisolated public func sessionDidDeactivate(_ session: WCSession) {
|
|
Task { @MainActor [weak self] in
|
|
guard let self else { return }
|
|
self.bridge.didDeactivate()
|
|
self.session.activate()
|
|
}
|
|
}
|
|
|
|
nonisolated public func sessionReachabilityDidChange(_ session: WCSession) {
|
|
Task { @MainActor [weak self] in self?.bridge.reachabilityDidChange() }
|
|
}
|
|
|
|
nonisolated public func session(_ session: WCSession,
|
|
didReceiveMessage message: [String: Any],
|
|
replyHandler: @escaping ([String: Any]) -> Void) {
|
|
let inbound = RelayInboundMessage(message: message, replyHandler: replyHandler)
|
|
Task { @MainActor [weak self, inbound] in
|
|
guard let self else {
|
|
inbound.reply.reply(relayErrorReply(RelayFailure(code: .unavailable)))
|
|
return
|
|
}
|
|
self.bridge.receive(message: inbound.message,
|
|
replyHandler: inbound.reply.reply)
|
|
}
|
|
}
|
|
}
|
|
#endif
|