rx_connectivity_checker 1.0.0
rx_connectivity_checker: ^1.0.0 copied to clipboard
A robust, reactive Dart/Flutter package for monitoring network connectivity.
rx_connectivity_checker #
A robust, reactive, and high-performance federated Flutter library for monitoring network connectivity.
Beyond monitoring local connection states, this library verifies end-to-end internet access through active network probes. Validation is triggered by three distinct events:
- Platform Change Events — a probe fires immediately when the system detects a network interface change (e.g. switching from Wi-Fi to Cellular).
- Periodic Polling — automated checks run at a configurable interval to catch "silent" losses (e.g. a router losing its uplink while Wi-Fi remains connected).
- Manual Triggers — one-off checks can be requested programmatically for critical operations such as a high-priority API submission.
Features #
- Federated Architecture — native implementations for Android, iOS, macOS, Windows, and Linux.
- True Reachability — distinguishes between "connected to a network" and "having internet access."
- Performance Optimised — throttled pipeline and single-check-at-a-time concurrency guard prevent redundant probes.
- Modern Web Support — WASM-ready using
package:webanddart:js_interopwith intelligent CORS-aware probes. - Energy Efficient — leverages native system observers (
NWPathMonitor,ConnectivityManager,DBus, NLM) to trigger checks only when necessary. - Cold Observables — internal timers and observers only start when the stream has active listeners.
- Zombie-Connection Detection — periodic background checks catch cases where a device is locally connected but has no actual internet access.
- Manual Check Support —
checkConnectivity()performs an immediate one-off check and deduplicates against any in-flight periodic check. - Testing Friendly — full dependency injection via
IHttpClientandReachabilityValidatoreliminates the need for real network access in tests.
Installation #
Add rx_connectivity_checker to your pubspec.yaml:
dependencies:
rx_connectivity_checker: ^1.0.0
Then run:
flutter pub get
Usage #
Basic setup #
Initialise the checker with a reliable endpoint. Google's generate_204 is the default — it is fast, lightweight, and returns no body.
final connectivityChecker = ConnectivityChecker(
url: 'https://connectivitycheck.gstatic.com/generate_204',
checkFrequency: const Duration(seconds: 30),
checkSlowConnection: true, // maps timeouts to ConnectivityStatus.slow (see platform notes below)
);
Reactive UI updates #
Use connectivityStream to rebuild your UI whenever the network state changes. The stream always emits ConnectivityStatus.unknown immediately on subscription, followed by the first real result.
StreamBuilder<ConnectivityStatus>(
stream: connectivityChecker.connectivityStream,
initialData: ConnectivityStatus.unknown,
builder: (context, snapshot) {
final status = snapshot.data ?? ConnectivityStatus.unknown;
return Column(
children: [
Icon(
status == ConnectivityStatus.online ? Icons.wifi : Icons.wifi_off,
color: status == ConnectivityStatus.online ? Colors.green : Colors.red,
),
Text('Status: ${status.name}'),
],
);
},
)
Manual one-off checks #
For critical actions (like submitting a form), perform an immediate check. If a periodic check is already in flight, this awaits that result rather than firing a duplicate probe.
final status = await connectivityChecker.checkConnectivity();
if (status == ConnectivityStatus.online) {
await apiService.uploadData();
}
Dependency injection (testing) #
ConnectivityChecker accepts an IHttpClient so you can swap in a mock during tests:
class MockHttpClient implements IHttpClient {
@override
Future<http.Response> get(Uri url, {Map<String, String>? headers}) async {
return http.Response('', 204);
}
}
final checker = ConnectivityChecker(client: MockHttpClient());
ConnectivityStatus #
| Value | Meaning |
|---|---|
online |
Remote endpoint responded with a 2xx status code. |
offline |
Endpoint unreachable or returned a non-2xx response. |
slow |
Request timed out and checkSlowConnection is true (not available on Windows — see below). |
unknown |
Initial state before the first check completes. |
Platform-specific behaviour #
Important: platform behaviour differs in one significant way. Read the Windows row carefully if you set
checkSlowConnection: true.
| Platform | Timeout maps to | checkSlowConnection honoured |
Native signal source |
|---|---|---|---|
| Android | slow or offline |
✅ Yes | ConnectivityManager / NetworkCallback |
| iOS / macOS | slow or offline |
✅ Yes | NWPathMonitor |
| Linux | slow or offline |
✅ Yes | NetworkManager via D-Bus |
| Windows | always offline |
❌ No — silently ignored | INetworkListManager (NLM COM) |
| Web | slow or offline |
✅ Yes | window online/offline events |
Windows rationale: The Windows networking stack rarely exhibits the degraded "slow" states typical of mobile connections. A request timeout on Windows strongly indicates an offline state or a blocked route. Consequently, ConnectivityStatus.slow is never emitted on Windows regardless of the checkSlowConnection setting.
Web limitation: The web implementation uses the browser's native fetch() API. IHttpClient injection and custom headers are not supported on web — passing either has no effect. Use a native platform build if you need header or client injection.
Platform support & native mechanisms #
| Platform | Mechanism | Details |
|---|---|---|
| Android | ConnectivityManager |
Uses NetworkCallback for real-time state tracking. |
| iOS / macOS | NWPathMonitor |
Native Swift implementation with event deduplication. |
| Linux | D-Bus / NetworkManager |
Subscribes to StateChanged signals on the system bus. |
| Windows | INetworkListManager |
C++ COM interop for high-performance desktop tracking. |
| Web | fetch API |
Uses cors mode; a CORS rejection is treated as reachable since the server responded. |
Platform setup #
Android #
Add the following permissions to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
iOS / macOS #
No additional permissions are required for iOS.
For macOS, enable the network client entitlement in both macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:
<key>com.apple.security.network.client</key>
<true/>
Windows #
The Windows implementation uses COM interop. No manifest changes are required for standard Win32 apps. For MSIX / packaged apps, declare the internetClient capability in Package.appxmanifest:
<Capability Name="internetClient" />
Ensure your build environment targets C++20 or later (required by the plugin's CMakeLists.txt).
Linux #
The Linux implementation communicates with NetworkManager via D-Bus. Most modern distributions (Ubuntu, Fedora, etc.) ship NetworkManager by default — no additional setup is required.
Web (CORS) #
The web implementation uses mode: cors. If the fetch succeeds the endpoint is reachable. If the server responds with a CORS rejection (e.g. TypeError), the browser still contacted the server — the validator treats this as online. A true network failure (DNS error, no route) sets navigator.onLine to false and is correctly reported as offline.
Example #
A complete, runnable example is in the example/ directory. It demonstrates:
- implementing a global connectivity listener
- handling
ConnectivityStatus.slowstates - using manual triggers before form submissions
cd example
flutter run
Contributing #
Contributions are welcome. For bugs or feature requests, please file them on the GitHub Issue Tracker.