reach

pub package License: MIT

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.

Libraries

reach