fix: improve offline indicator accuracy with HTTP probe#387
Merged
Conversation
f9b8186 to
2e8c892
Compare
Replaces the simple event listener approach with an asymmetric strategy: - Initial state reads navigator.onLine. A false value is trusted immediately. A true value triggers a mount-time probe to catch misreported online status. - offline event: trusted immediately — this signal is reliable. - online event: verified by a lightweight HEAD probe before clearing the indicator, guarding against false positives. The probe targets siteApiRoot from the GBKit config, testing actual WordPress API reachability. Falls back to /favicon.ico in local dev environments. An AbortController guards in-flight probe callbacks against calls to setIsConnected after the component unmounts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ffline events in WebView
Android WebView does not fire online/offline events when OS network state
changes, unlike a full browser. Adds a ConnectivityManager.NetworkCallback
inside GutenbergView that monitors OS network state and dispatches
window.dispatchEvent(new Event('online'|'offline')) into the WebView —
a transparent polyfill requiring no host app changes.
Tracks the set of available networks so that onLost (which fires per-network,
not when all connectivity is gone) only signals offline when no networks
remain, preventing false offline flashes on devices with WiFi and cellular.
The callback is registered in onAttachedToWindow and unregistered in
onDetachedFromWindow. Adds the required ACCESS_NETWORK_STATE permission
to the library manifest (a normal permission; no runtime grant needed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2e8c892 to
84d32a2
Compare
…st data races `availableNetworks` is mutated from `ConnectivityManager.NetworkCallback` threads; wrap it in `Collections.synchronizedSet` to prevent `ConcurrentModificationException`. Mark `lastKnownConnectivity` as `@Volatile` so the main thread always reads the latest value written by the callback thread. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The siteApiRoot may be on a different origin without CORS headers. Using `mode: 'no-cors'` skips preflight for HEAD requests so a missing `Access-Control-Allow-Origin` header does not cause the probe to report offline incorrectly. The response is opaque, but only reachability (not the body) is needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Fixes the offline indicator not appearing in Android WebView, and improves its accuracy across all platforms.
Why?
Two issues:
online/offlineevents — a known long-standing WebView limitation. Unlike Chrome (a full browser with its own network stack), Android WebView does not synthesize these events when OS network state changes, so the offline banner never appeared.navigator.onLineand browseronline/offlineevents are unreliable on other platforms — they only confirm a network interface is active, not that the internet is reachable. Chrome is also known to not fire theofflineevent in all network loss scenarios.Fix CMM-1945. Follow up on #366 (comment).
How?
Android native polyfill
Adds a
ConnectivityManager.NetworkCallbackinsideGutenbergViewthat monitors OS network state and synthesizeswindow.dispatchEvent(new Event('online'|'offline'))into the WebView — a transparent polyfill requiring no host app changes. The callback is registered inonAttachedToWindowand unregistered inonDetachedFromWindow. Also adds the requiredACCESS_NETWORK_STATEpermission to the library manifest (a normal permission; no runtime grant needed).JS probe-based connectivity strategy
Replaces the simple event listener approach with an asymmetric strategy:
navigator.onLine. Afalsevalue is trusted immediately (definitive signal the device has no interface). Atruevalue triggers a mount-time probe to catch misreported online status before any event fires.offlineevent: trusted immediately — this signal is reliable.onlineevent: verified by a lightweightHEADprobe before clearing the indicator, guarding against false positives.The probe targets
siteApiRootfrom the GBKit config, testing actual WordPress API reachability. Falls back to/favicon.icoin local dev environments.Testing Instructions
GUTENBERG_EDITOR_URLfromlocal.properties.make buildto build the latest JavaScript.Accessibility Testing Instructions
The offline indicator uses
wp.a11y.speak()to announce connectivity loss to screen readers. Verify the announcement is made when going offline.Screenshots or screencast
Screen recording
android-working-offline.mp4
Screenshot