11import WatchConnectivity
22import Combine
33import Networking
4+ import protocol WooFoundation. Analytics
45import class WooFoundation. CurrencySettings
56
67/// Type that syncs the necessary dependencies to the watch session.
@@ -10,6 +11,8 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
1011 /// Current WatchKit Session
1112 private let watchSession : WCSession
1213
14+ private let analytics : Analytics
15+
1316 /// Subscriptions store for combine publishers
1417 ///
1518 private var subscriptions = Set < AnyCancellable > ( )
@@ -34,16 +37,15 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
3437 ///
3538 @Published var account : Account ?
3639
37- /// Tracks if the current watch session is active or not
38- ///
39- @Published private var isSessionActive : Bool = false
40-
4140 /// Toggle this value to force a credentials sync.
4241 ///
4342 @Published private var syncTrigger = false
4443
45- init ( watchSession: WCSession = WCSession . default, storedDependencies: WatchDependencies ? ) {
44+ init ( watchSession: WCSession = WCSession . default,
45+ storedDependencies: WatchDependencies ? ,
46+ analytics: Analytics = ServiceLocator . analytics) {
4647 self . watchSession = watchSession
48+ self . analytics = analytics
4749 super. init ( )
4850
4951 self . storeID = storedDependencies? . storeID
@@ -80,9 +82,7 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
8082 let ( storeID, storeName, credentials, currencySettings) = required
8183 let ( enablesCrashReports, account) = configuration
8284
83- guard let storeID, let storeName, let credentials else {
84- return nil
85- }
85+ guard let storeID, let storeName, let credentials else { return nil }
8686
8787 return . init( storeID: storeID,
8888 storeName: storeName,
@@ -95,16 +95,30 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
9595 . debounce ( for: 0.5 , scheduler: DispatchQueue . main)
9696
9797 // Syncs the dependencies to the paired counterpart when the session becomes available.
98- Publishers . CombineLatest3 ( watchDependencies , $isSessionActive , $syncTrigger)
99- . sink { [ watchSession] dependencies, isSessionActive , forceSync in
98+ watchDependencies . combineLatest ( $syncTrigger)
99+ . sink { [ weak self , watchSession] dependencies, forceSync in
100100
101101 // Do not update the context if the session is not active, the watch is not paired or the watch app is not installed.
102- guard isSessionActive, watchSession. isPaired, watchSession. isWatchAppInstalled else { return }
102+ guard watchSession. activationState == . activated,
103+ watchSession. isPaired,
104+ watchSession. isWatchAppInstalled else {
105+ self ? . analytics. track (
106+ . watchSyncingFailed,
107+ properties: [
108+ " session_active " : watchSession. activationState == . activated,
109+ " session_paired " : watchSession. isPaired,
110+ " watch_app_installed " : watchSession. isWatchAppInstalled
111+ ] ,
112+ error: SyncError . watchSessionInactiveOrNotPaired
113+ )
114+ return
115+ }
103116
104117 do {
105118
106119 // If dependencies is nil, send an empty dictionary. This is most likely a logged out state
107120 guard let dependencies else {
121+ self ? . analytics. track ( . watchSyncingFailed, withError: SyncError . noDependenciesFound)
108122 return try watchSession. updateApplicationContext ( [ : ] )
109123 }
110124
@@ -118,9 +132,11 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
118132
119133 try watchSession. updateApplicationContext ( jsonObject)
120134 } else {
135+ self ? . analytics. track ( . watchSyncingFailed, withError: SyncError . encodingApplicationContextFailed)
121136 DDLogError ( " ⛔️ Unable to encode watch dependencies for synchronization. Resulting object is not a dictionary " )
122137 }
123138 } catch {
139+ self ? . analytics. track ( . watchSyncingFailed, withError: error)
124140 DDLogError ( " ⛔️ Error synchronizing credentials into watch session: \( error) " )
125141 }
126142 }
@@ -129,7 +145,6 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
129145
130146 func session( _ session: WCSession , activationDidCompleteWith activationState: WCSessionActivationState , error: Error ? ) {
131147 DDLogInfo ( " 🔵 WatchSession activated \( activationState) " )
132- self . isSessionActive = activationState == . activated
133148 }
134149
135150 func sessionDidBecomeInactive( _ session: WCSession ) {
@@ -138,7 +153,6 @@ final class WatchDependenciesSynchronizer: NSObject, WCSessionDelegate {
138153
139154 func sessionDidDeactivate( _ session: WCSession ) {
140155 // Try to guarantee an active session
141- self . isSessionActive = false
142156 watchSession. activate ( )
143157 }
144158}
@@ -149,13 +163,12 @@ extension WatchDependenciesSynchronizer {
149163 /// This is in order to not duplicate tracks configuration which involve quite a lot of information to be transmitted to the watch.
150164 ///
151165 func session( _ session: WCSession , didReceiveUserInfo userInfo: [ String : Any ] = [ : ] ) {
152-
153166 // The user info could contain a track event. Send it if we found one.
154167 guard let rawEvent = userInfo [ WooConstants . watchTracksKey] as? String ,
155168 let analyticEvent = WooAnalyticsStat ( rawValue: rawEvent) else {
156169 return DDLogError ( " ⛔️ Unsupported watch tracks event: \( userInfo) " )
157170 }
158- ServiceLocator . analytics. track ( analyticEvent)
171+ analytics. track ( analyticEvent)
159172 }
160173}
161174
@@ -173,7 +186,14 @@ extension WatchDependenciesSynchronizer {
173186 guard message [ WooConstants . watchSyncKey] as? Bool == true else {
174187 return DDLogError ( " ⛔️ Unsupported sync request message: \( message) " )
175188 }
176-
177189 syncTrigger. toggle ( )
178190 }
179191}
192+
193+ extension WatchDependenciesSynchronizer {
194+ enum SyncError : Error {
195+ case watchSessionInactiveOrNotPaired
196+ case noDependenciesFound
197+ case encodingApplicationContextFailed
198+ }
199+ }
0 commit comments