reach
A lightweight, robust Dart & Flutter utility to verify actual internet connectivity, not just network interface connection.
reach combines active hardware/network interface monitoring with non-intrusive TCP socket probes to distinguish between being connected to a Wi-Fi router vs. actually having functional internet access.
Features
- Real Internet Verification: Probes active hosts via socket handshake rather than relying solely on network adapter state.
- Debouncing Built-In: Avoids false positives and rapid flickering during network switches or Wi-Fi flapping.
- Automatic Retries: Continuously retries in the background when connected to a gateway without internet access.
- Low Overhead: Opens and immediately destroys TCP handshakes without sending HTTP payloads or consuming heavy bandwidth.
- Stale State Management: Uses request generation tokens to safely discard outdated probe results during fast network changes.
Getting Started
Add reach to your pubspec.yaml:
dependencies:
reach: ^1.0.0
Then run:
flutter pub get
Usage
Basic Setup
Create a Reach instance, start listening, and react to connection state changes:
import 'package:reach/reach.dart';
void main() {
final reach = Reach()..start();
// Stream true internet availability changes
reach.stream.listen((bool isOnline) {
if (isOnline) {
print('Connected to the internet');
} else {
print('No internet access');
}
});
}
Custom Configuration
You can customize probe endpoints, timeout limits, debounce durations, and periodic re-check schedules:
final reach = Reach(
host: '1.1.1.1', // Target server (Cloudflare DNS by default)
port: 443, // Target port
timeout: const Duration(seconds: 3), // Socket connection timeout
retryGap: const Duration(seconds: 5), // Delay between retries when link exists but no internet
debounce: const Duration(seconds: 1), // Delay before probing after connectivity changes
recheckInterval: const Duration(minutes: 2), // Periodic probe interval when online (optional)
);
reach.start();
On-Demand Check
Check the current status synchronously or execute a one-off probe before critical actions (e.g., submitting a payment or syncing data):
// Get last cached status
if (reach.current == true) {
// Proceed with cached status
}
// Perform an immediate, active probe
final bool isOnline = await reach.check();
if (isOnline) {
await uploadUserData();
}
Integration in Flutter UI
Using Reach with a StreamBuilder inside a Flutter application:
import 'package:flutter/material.dart';
import 'package:reach/reach.dart';
class NetworkAwareWidget extends StatefulWidget {
const NetworkAwareWidget({super.key});
@override
State<NetworkAwareWidget> createState() => _NetworkAwareWidgetState();
}
class _NetworkAwareWidgetState extends State<NetworkAwareWidget> {
late final Reach _reach;
@override
void initState() {
super.initState();
_reach = Reach()..start();
}
@override
void dispose() {
_reach.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
stream: _reach.stream,
builder: (context, snapshot) {
final isOnline = snapshot.data ?? _reach.current ?? false;
return Container(
color: isOnline ? Colors.green : Colors.red,
padding: const EdgeInsets.all(8.0),
child: Text(
isOnline ? 'Online' : 'Offline',
style: const TextStyle(color: Colors.white),
),
);
},
);
}
}
API Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
host |
String |
'1.1.1.1' |
Host IP or domain used for socket verification. |
port |
int |
443 |
Target port for probing. |
timeout |
Duration |
3 seconds |
Connection timeout before marking probe as failed. |
retryGap |
Duration |
5 seconds |
Interval between retries when network link exists without internet. |
debounce |
Duration |
1 second |
Delay before probing after interface state change. |
recheckInterval |
Duration? |
null |
Periodic probe interval while connected. |
Cleanup
Always dispose of the Reach instance when it is no longer needed to cancel active timers and free stream resources:
reach.dispose();
License
This project is licensed under the MIT License - see the LICENSE file for details.