Repository navigation
Description
Bug Report
Plugin(s)
@capacitor/network 8.0.1 (same code on main at 87c0bb8 and in 9.0.0-alpha.2)
Capacitor Version
@capacitor/core: 8.5.3
@capacitor/android: 8.5.3
@capacitor/network: 8.0.1
compileSdk 36, minSdk 24
Platform(s)
Android
Current Behavior
-
The network callback ignores its arguments and re-queries the active network.
onCapabilitiesChangeddrops theNetworkCapabilitiesit receives (Network.java:29-32);NetworkPluginthen callsgetNetworkStatus()(NetworkPlugin.java:84-86), which callsgetActiveNetwork()twice andgetNetworkCapabilities()(Network.java:77-78). TheConnectivityManager.NetworkCallbackreference says not to call synchronousConnectivityManagermethods from inside callbacks, because the result can be out of date relative to the callback; the arguments passed in are the source of truth.onLostalso emitsnonefor any lost network without checking it was the current default (Network.java:22-26, NetworkPlugin.java:25-29). -
Every capability change emits an event, even when nothing reported changed. There is no comparison with the last emitted status (NetworkPlugin.java:84-86).
onCapabilitiesChangedfires for signal strength and link bandwidth updates, so listeners get repeatednetworkStatusChangeevents with an identical{ connected, connectionType }. Registering the callback on each resume also delivers an immediate callback, so every resume emits too. This was acknowledged as a bug in [Android] networkStatusChange-event fires when app becomes active capacitor#1492 (labeledtype: bug, diagnosed as the onResume registration) and reported again in networkStatusChange event fires after on app resume #1014 and [Bug]: networkStatusChange is triggering the event when changing the wifi frequency #2138; all were closed in backlog cleanup without a fix. -
No events before the first resume.
load()only sets the listener (NetworkPlugin.java:22-35);startMonitoring()is only called fromhandleOnResume(NetworkPlugin.java:59). -
Unguarded register/unregister.
startMonitoring/stopMonitoringcallregisterDefaultNetworkCallback/unregisterNetworkCallbackwith no registered-state check (Network.java:114-123). Android throwsIllegalArgumentExceptionwhen unregistering a callback that isn't registered or registering one twice, so a pause without a preceding resume, or a repeated pause, can crash. Not reproduced; possibly related to @capacitor/network crashing on Android 14(SDK 34) for Samsung and Google pixel devices. #2107.
Expected Behavior
- Status in callbacks comes from the callback's own
Network/NetworkCapabilities. networkStatusChangefires only whenconnectedorconnectionTypeactually changes.- Monitoring starts when the plugin loads.
- Register/unregister can't throw on lifecycle ordering.
Code Reproduction
No sample app needed beyond the plugin's own example:
import { Network } from '@capacitor/network';
Network.addListener('networkStatusChange', s => console.log('event', Date.now(), JSON.stringify(s)));- Run on a device connected to Wi-Fi.
- Walk away from the router and back (or move between rooms) so the signal level changes, without disconnecting.
- Logcat shows repeated
networkStatusChangeevents, each with{"connected":true,"connectionType":"wifi"}. - Background and foreground the app (open the notification shade, a permission dialog, or the app switcher): one more identical event per resume.
Other Technical Details
A PR follows. It keeps connected = VALIDATED && INTERNET and keeps getStatus() querying the active network as today. It doesn't change the public API.
Related open items, not duplicated by the PR: #2563 / #2606 (ANR from ConnectivityManager calls on the main thread in handleOnResume), #2564 (captive portal / limited state), #2555 (metered / constrained flags).
Additional Context
Prior reports: ionic-team/capacitor#1492, #1014, #2138, #2107.
Activity