Skip to content

fix(network): fresh getStatus on iOS; callback-driven, deduplicated events on Android - #2622

Open
kcjonson wants to merge 2 commits into
ionic-team:mainfrom
kcjonson:fix/network-status-events
Open

kcjonson wants to merge 2 commits into
ionic-team:mainfrom
kcjonson:fix/network-status-events

Conversation

@kcjonson

Copy link
Copy Markdown

Description

iOS: getStatus() now reads the reachability flags synchronously instead of returning the value stored by the last callback. The SCNetworkReachability implementation stays; moving to NWPathMonitor belongs with #2555, which already adds one.

Android:

  • onCapabilitiesChanged builds the status from the NetworkCapabilities it's given instead of re-querying getActiveNetwork()/getNetworkCapabilities(). onAvailable only reads capabilities itself on API 24-25, where onCapabilitiesChanged isn't guaranteed to follow. onLost for a network that's no longer the default is ignored.
  • networkStatusChange is only emitted when connected or connectionType changes, so signal strength / bandwidth updates and the callback delivered on every re-registration no longer produce duplicate events.
  • The callback is registered in load(), so events arrive before the first resume. Pause/resume still unregister/re-register, and both are now no-ops when already in that state, so unregisterNetworkCallback can't throw when nothing is registered. Losing the connection while paused is still reported on resume (fix(network): fire networkStatusChanged if network lost while app paused #1655).
  • getStatus() still queries the active network, and connected is still VALIDATED && INTERNET. No public API changes.

Change Type

  • Fix
  • Feature
  • Refactor
  • Breaking Change
  • Documentation
  • Other (CI, chores, etc.)

Rationale / Problems Fixed

Closes #2620
Closes #2621

On iOS, getStatus() only re-read the flags when they were nil, so a call right after a network change returned the previous state until the next callback landed.

On Android, the ConnectivityManager.NetworkCallback reference warns against calling synchronous ConnectivityManager methods from inside a callback, since the answer can already be out of sync with the callback; the arguments are the source of truth. The plugin did exactly that, and also emitted on every capability change, which is the long-standing duplicate-event report (ionic-team/capacitor#1492, #1014, #2138).

Tests or Reproductions

What ran, locally on macOS against @capacitor/core/ios/android 8.5.3:

  • npm run verify:ios (xcodebuild build -scheme CapacitorNetwork -destination generic/platform=iOS, Xcode 27.1): build succeeded.
  • npm run verify:android (gradlew clean build test after npm run set-settings-gradle-for-monorepo, JDK 21): build, lint, and unit tests passed. The only unit test in the module is the placeholder ExampleUnitTest, so this proves it compiles and lints, not the behavior.
  • npm run build (docgen, tsc, rollup): passed, README unchanged.
  • npm run lint: eslint and prettier clean; swiftlint reports the same two existing warnings in Reachability.swift as main, nothing new.

Not run: the iOS XCTest target, and nothing on a simulator, emulator, or device. The repro steps in #2620 and #2621 need no sample app.

Screenshots / Media

Platforms Affected

  • Android
  • iOS
  • Web

Notes / Comments

Captive-portal / limited-connectivity reporting is left to #2564 and constrained/expensive exposure to #2555; this only fixes the existing fields.

#2606 also changes handleOnResume/handleOnPause in NetworkPlugin.java (moving the ConnectivityManager calls off the main thread), so the two will conflict there. This PR leaves getNetworkStatus() as it is on main to keep the overlap to that one file. It also removes the getNetworkStatus() call from handleOnPause, which is one of the main-thread binder calls #2563 is about.

getStatus() returned the flags stored by the last reachability callback and
only read them synchronously when they were nil, so a call made right after a
network change could return the previous state.
…e events

- Build the status from the NetworkCapabilities passed to onCapabilitiesChanged
  instead of re-querying the active network inside the callback.
- Ignore onLost for a network that is no longer the default.
- Only emit networkStatusChange when connected or connectionType changes.
- Register the callback at load so events arrive before the first resume.
- Make register/unregister no-ops when already in that state.
@kcjonson
kcjonson marked this pull request as ready for review October 22, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant