Keep background apps alive, and notify from their unread count
The report was that a backgrounded site dies slowly and stops fetching. It did, for three separate reasons, and the first two fixes each traded one failure for another: Hiding inactive views lets WebKit suspend them, so nothing is hidden any more - every view keeps its size and stays in the window, and the active one is ordered on top. Telling a background page it was hidden then made Gmail throttle its own syncing; its unread count sat unchanged for two and a half minutes. That spoof is gone. Neither was enough on its own: a background page keeps its timers but loses the connection its updates arrive on, and WKWebView has no equivalent of Electron's backgroundThrottling. Background apps are now poked every 45s with the events a page uses to catch up after you return to a tab - it fetches without losing a half-written reply. Notifications now come from the unread count in the title rather than the site's notification code, which Gmail will not run while it believes you are looking at it. Measured: Gmail behind Odoo went 155 -> 157 untouched and raised "Gmail / 1 new". Also adds a background-app probe to Settings, which is what turned this from guesswork into measurement, and drops the nav's blocked-element count and the hide-element button.
This commit is contained in:
@@ -204,6 +204,44 @@ wrong at first:
|
||||
|
||||
Service-worker push is **not** covered — only notifications a page raises while it is open.
|
||||
|
||||
## Keeping background apps alive
|
||||
|
||||
The app is only worth having if a tool you are not looking at still tells you something
|
||||
arrived. Getting there took three wrong turns, and each one is why the code looks as it
|
||||
does:
|
||||
|
||||
1. **Hiding the inactive views.** The obvious way to switch apps, and it kills them:
|
||||
WebKit reads a hidden `NSView` as a page that is not visible, throttles its timers and
|
||||
eventually suspends it. Now nothing is hidden — every view keeps its full size and stays
|
||||
in the window, and the active one is simply ordered on top. Sibling views covering each
|
||||
other is not something WebKit tracks.
|
||||
|
||||
2. **Telling the page it was hidden.** The idea was that a page believing itself hidden
|
||||
would notify rather than stay quiet. It backfired: told it was hidden, Gmail throttled
|
||||
its *own* syncing, and its unread count sat unchanged for two and a half minutes. The
|
||||
spoof is gone. Pages are told nothing about visibility.
|
||||
|
||||
3. **Assuming that was enough.** It was not. A backgrounded page keeps running its timers
|
||||
but loses the long-lived connection its updates arrive on, and WKWebView offers no
|
||||
equivalent of Electron's `backgroundThrottling: false`. So every background app is
|
||||
**poked every 45 seconds** with the events a page uses to catch up when you return to a
|
||||
tab. It fetches as if you had just looked at it, and keeps its state — unlike a reload,
|
||||
which would throw away a half-written reply.
|
||||
|
||||
**Measured end to end:** Gmail behind Odoo went from 155 to 157 unread without being
|
||||
touched, and the app raised `Gmail / 1 new`.
|
||||
|
||||
### Unread counting
|
||||
|
||||
Notifications do not come from the site's own notification code, because Gmail declines to
|
||||
raise one while it believes you are looking at it — and with the visibility spoof gone, it
|
||||
always believes that. They come from the **unread count in the title**: `Inbox (12)`,
|
||||
`(3) Chat`. Every one of these tools publishes it, it cannot be switched off, and it never
|
||||
moves into a service worker this app cannot reach. A rise while the app is not the one on
|
||||
screen raises a banner; a fall is you reading things, and is not news.
|
||||
|
||||
The site's own notifications still work when they fire — both paths feed the same channel.
|
||||
|
||||
## Zoom
|
||||
|
||||
Per app, on a fixed ladder so ⌘0 returns to exactly 100% rather than to whatever a
|
||||
|
||||
Reference in New Issue
Block a user