pocket-casts-ios icon indicating copy to clipboard operation
pocket-casts-ios copied to clipboard

[Watch] After being idle for many days, the watch sync reproduces all user's actions

Open leandroalonso opened this issue 1 year ago • 7 comments

From our Beta Slack:

think it is weird that the watch app, even if it goes in a kind of sleep mode when I don’t use it for days or weeks, that it would run through all the episodes I played. Why doesn’t the app only get the current data from the player and presents it. I only use the watch app as a remote when i don’t have my phone nearby, sometimes I check the new episodes and add a few to up next. But that running through all the last played episodes is completely unnecessary and the app has to get all the data from the phone to present what I was listening to. It doesn’t just go through the episodes you play, I can also see it simulating the pauses I did throughout that period as well. It’s like everything got cached and is playing catch-up. It’s very strange.

leandroalonso avatar Feb 12 '24 13:02 leandroalonso

I wonder if this is the watch syncing from the server, or processing update messages from the phone via WatchManager. Based on the description it sounds like the latter and that somehow the progress update messages are queued and then rapidly flushed to the watch when the watch app is opened. Looking at the code I don't think this is possible though, unless there is an iOS / WatchOS bug:

https://github.com/Automattic/pocket-casts-ios/blob/c6e376e696a8ff5845eb7c4a274d8874ef4b613a/podcasts/WatchManager.swift#L393-L394

rviljoen avatar Feb 12 '24 13:02 rviljoen

This happens for me aswell. I reported this behavior already in the past. Hopefully you can find a fix. Your support pointed at my old Apple Watch Series 4 to be the reason. But happens now with the Ultra 2 aswell.

BKrnk1337 avatar Feb 15 '24 00:02 BKrnk1337

I did some more digging on this issue, and can now reproduce it with some consistency:

  • Open phone app
  • Press play on episode
  • Open watch app (if not opened automatically) and navigate to Phone->Now Playing
  • Put watch to sleep (I take it off and put face down)
  • Perform several actions on phone: play, pause, skip forward, backward, etc.
  • Open watch app on phone. You should see a replay of most events in chronological order

For the Phone portion of the watch app, we send regular updates from the phone to update the state. This is different to the Watch portion, which plays independently from the phone and updates it state based on the progress of the audio engine on the watch. We send the updates from here:

https://github.com/Automattic/pocket-casts-ios/blob/0a8cb3187ad4028aa857a4dfc2a1e4e7b94c9697/podcasts/WatchManager.swift#L388-L394

Even when the watch is face down, its state remains .activated and hence updates are sent while the watch screen is off.

We send the update using WCSession.updateApplicationContext. The documentation from Apple is here. The documentation suggests that the phone app can send multiple contexts, but that only the last one is considered:

This method replaces the previous dictionary that was set, so you should use this method to communicate state changes or to deliver data that is updated frequently anyway. For example, this method is well suited for updating your app’s glance. You may call this method when the counterpart is not currently reachable.

However, in practice I'm seeing that most (if not all) contexts are delivered, which explains the behaviour we are seeing where the app seems to replay all the other actions and state changes since last interaction. I added some debugging code to the watch to confirm that this is indeed happening:

2024-08-26 19:26:13 Received application context last updated: Optional(2024-08-26 19:25:35 +0000) 2024-08-26 19:26:13 Received application context last updated: Optional(2024-08-26 19:25:40 +0000) 2024-08-26 19:26:13 Received application context last updated: Optional(2024-08-26 19:25:54 +0000)

Above we can see that at 19:26:13, the watch received 3 context updates at the same time, for actions performed at 19:25:35, 19:25:40 and 19:25:54 respectively (last updated was set in the phone app when the context was generated).

I have not yet found a solution to this problem, and have not found many similar reports online. There is however this 7-year old report which explains exactly what we are seeing.

For now I am just documenting my findings while pondering ways to work around what seems to be a long-standing watchOS SDK issue or design decision.

rviljoen avatar Aug 26 '24 20:08 rviljoen

Currently testing this workaround:

  • Only send state to watch when session.isReachable
  • When sessionReachabilityDidChange(_ session: WCSession) is called, send current state to watch if session.isReachable

Will run it for a few days and report back.

rviljoen avatar Aug 26 '24 21:08 rviljoen

I have had this happen as well!

lawruhl avatar Aug 26 '24 23:08 lawruhl

@rviljoen thank you for digging into it.

From my point of view, this is one of the most annoying behaviours when using the Watch app. I open the app exactly because I want to use it now, but sometimes I have to wait a very long time until all the old episodes have been „played through“. I notice that pauses, forward rewinds and jump back are also replicated.

BKrnk1337 avatar Aug 28 '24 14:08 BKrnk1337

There's a user report of this issue in zen-8665388, with logs sent if needed

azollafox avatar Sep 01 '24 13:09 azollafox