Harden Apple Watch snapshot synchronization
This commit is contained in:
@@ -85,6 +85,12 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
|
||||
func sceneBecameActive() {
|
||||
restoreSnapshot()
|
||||
guard WCSession.isSupported() else { return }
|
||||
let session = WCSession.default
|
||||
session.activate()
|
||||
if session.activationState == .activated {
|
||||
receive(session.receivedApplicationContext, session: session, authoritative: true)
|
||||
}
|
||||
}
|
||||
|
||||
func sceneBecameInactive() {
|
||||
@@ -108,7 +114,11 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
}
|
||||
}
|
||||
|
||||
private func receive(_ applicationContext: [String: Any], session: WCSession) {
|
||||
private func receive(
|
||||
_ applicationContext: [String: Any],
|
||||
session: WCSession,
|
||||
authoritative: Bool = false
|
||||
) {
|
||||
try? core.syncStarted()
|
||||
guard var snapshot = applicationContext[Self.snapshotKey] as? Data else {
|
||||
try? core.syncFinished()
|
||||
@@ -117,7 +127,11 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
}
|
||||
defer { snapshot.resetBytes(in: 0..<snapshot.count) }
|
||||
do {
|
||||
let update = try core.applySnapshot(snapshot: snapshot)
|
||||
let update = if authoritative {
|
||||
try core.applyAuthoritativeSnapshot(snapshot: snapshot)
|
||||
} else {
|
||||
try core.applySnapshot(snapshot: snapshot)
|
||||
}
|
||||
switch update.persistence {
|
||||
case .keep:
|
||||
break
|
||||
@@ -128,20 +142,25 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
}
|
||||
refreshPresentation()
|
||||
guard !update.receipt.isEmpty else { return }
|
||||
let acknowledgement = [Self.receiptKey: update.receipt]
|
||||
if session.isReachable {
|
||||
session.sendMessage(acknowledgement, replyHandler: nil) { _ in
|
||||
session.transferUserInfo(acknowledgement)
|
||||
}
|
||||
} else {
|
||||
session.transferUserInfo(acknowledgement)
|
||||
}
|
||||
acknowledge(update.receipt, through: session)
|
||||
} catch {
|
||||
try? core.syncFailed()
|
||||
refreshPresentation()
|
||||
}
|
||||
}
|
||||
|
||||
private func acknowledge(_ receipt: Data, through session: WCSession) {
|
||||
let acknowledgement = [Self.receiptKey: receipt]
|
||||
for transfer in session.outstandingUserInfoTransfers
|
||||
where transfer.userInfo[Self.receiptKey] != nil {
|
||||
transfer.cancel()
|
||||
}
|
||||
session.transferUserInfo(acknowledgement)
|
||||
if session.isReachable {
|
||||
session.sendMessage(acknowledgement, replyHandler: nil) { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
func refreshPresentation(at date: Date = .now) {
|
||||
presentation = try? core.presentationAt(
|
||||
unixSeconds: UInt64(date.timeIntervalSince1970)
|
||||
@@ -160,7 +179,11 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
self.refreshPresentation()
|
||||
return
|
||||
}
|
||||
self.receive(session.receivedApplicationContext, session: session)
|
||||
self.receive(
|
||||
session.receivedApplicationContext,
|
||||
session: session,
|
||||
authoritative: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +192,7 @@ private final class WatchSnapshotTransport: NSObject, ObservableObject, WCSessio
|
||||
didReceiveApplicationContext applicationContext: [String: Any]
|
||||
) {
|
||||
Task { @MainActor [weak self] in
|
||||
self?.receive(applicationContext, session: session)
|
||||
self?.receive(applicationContext, session: session, authoritative: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user