A Pure Dart Utility library that checks for an Active Internet connection

Overview

🌍 Internet Connection Checker

Dart CI codecov style: very good analysis License: MIT

A Pure Dart Utility library that checks for an Active Internet connection by opening a socket to a list of specified addresses, each with individual port and timeout. Defaults are provided for convenience.

Note that this plugin is in beta and may still have a few issues. Feedback is welcome.

Table of contents

Description

Checks for an internet (data) connection, by opening a socket to a list of addresses.

The defaults of the plugin should be sufficient to reliably determine if the device is currently connected to the global network, e.i. has access to the Internet.

Note that you should not be using the current network status for deciding whether you can reliably make a network connection. Always guard your app code against timeouts and errors that might come from the network layer.

Quick start

InternetConnectionChecker() is actually a Singleton. Calling InternetConnectionChecker() is guaranteed to always return the same instance.

You can supply a new list to InternetConnectionChecker().addresses if you need to check different destinations, ports and timeouts. Also, each address can have its own port and timeout. See InternetAddressCheckOptions in the docs for more info.

First you need to [install it][install] (this is the preferred way)

Then you can start using the library:

bool result = await InternetConnectionChecker().hasConnection;
if(result == true) {
  print('YAY! Free cute dog pics!');
} else {
  print('No internet :( Reason:');
  print(InternetConnectionChecker().lastTryResults);
}

Purpose

The reason this package exists is that connectivity_plus package cannot reliably determine if a data connection is actually available. More info on its page here: https://pub.dev/packages/connectivity_plus

More info on the issue in general:

You can use this package in combination with connectivity_plus in the following way:

var isDeviceConnected = false;

var subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) async {
  if(result != ConnectivityResult.none) {
    isDeviceConnected = await InternetConnectionChecker().hasConnection;
  }
});

Note: remember to properly cancel the subscription when it's no longer needed. See connectivity_plus package docs for more info.

How it works

All addresses are pinged simultaneously. On successful result (socket connection to address/port succeeds) a true boolean is pushed to a list, on failure (usually on timeout, default 10 sec) a false boolean is pushed to the same list.

When all the requests complete with either success or failure, a check is made to see if the list contains at least one true boolean. If it does, then an external address is available, so we have data connection. If all the values in this list are false, then we have no connection to the outside world of cute cat and dog pictures, so hasConnection also returns false too.

This all happens at the same time for all addresses, so the maximum waiting time is the address with the highest specified timeout, in case it's unreachable.

I believe this is a reliable and fast method to check if a data connection is available to a device, but I may be wrong. I suggest you open an issue on the Github repository page if you have a better way of.

Defaults

The defaults are based on data collected from https://perfops.net/, https://www.dnsperf.com/#!dns-resolvers

Here's some more info about the defaults:

DEFAULT_ADDRESSES

... includes the top 3 globally available free DNS resolvers.

Address Provider Info
1.1.1.1 CloudFlare https://1.1.1.1
1.0.0.1 CloudFlare https://1.1.1.1
8.8.8.8 Google https://developers.google.com/speed/public-dns/
8.8.4.4 Google https://developers.google.com/speed/public-dns/
208.67.222.222 OpenDNS https://use.opendns.com/
208.67.220.220 OpenDNS https://use.opendns.com/
static final List<AddressCheckOptions> DEFAULT_ADDRESSES =
      List<AddressCheckOptions>.unmodifiable(
    <AddressCheckOptions>[
      AddressCheckOptions(
        InternetAddress(
          '1.1.1.1', // CloudFlare
          type: InternetAddressType.IPv4,
        ),
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
      AddressCheckOptions(
        InternetAddress(
          '2606:4700:4700::1111', // CloudFlare
          type: InternetAddressType.IPv6,
        ),
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
      AddressCheckOptions(
        InternetAddress(
          '8.8.4.4', // Google
          type: InternetAddressType.IPv4,
        ),
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
      AddressCheckOptions(
        InternetAddress(
          '2001:4860:4860::8888', // Google
          type: InternetAddressType.IPv6,
        ),
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
      AddressCheckOptions(
        InternetAddress(
          '208.67.222.222', // OpenDNS
          type: InternetAddressType.IPv4,
        ), // OpenDNS
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
      AddressCheckOptions(
        InternetAddress(
          '2620:0:ccc::2', // OpenDNS
          type: InternetAddressType.IPv6,
        ), // OpenDNS
        port: DEFAULT_PORT,
        timeout: DEFAULT_TIMEOUT,
      ),
    ],
  );

DEFAULT_PORT

... is 53.

A DNS server listens for requests on port 53 (both UDP and TCP). So all DNS requests are sent to port 53 ...

More info:

static const int DEFAULT_PORT = 53;

DEFAULT_TIMEOUT

... is 10 seconds.

static const Duration DEFAULT_TIMEOUT = Duration(seconds: 10);

DEFAULT_INTERVAL

... is 10 seconds. Interval is the time between automatic checks. Automatic checks start if there's a listener attached to onStatusChange, thus remember to cancel unneeded subscriptions.

checkInterval (which controls how often a check is made) defaults to this value. You can change it if you need to perform checks more often or otherwise.

static const Duration DEFAULT_INTERVAL = const Duration(seconds: 10);
...
Duration checkInterval = DEFAULT_INTERVAL;

Usage

Example:

import 'package:internet_connection_checker/internet_connection_checker.dart';

main() async {
  // Simple check to see if we have internet
  print("The statement 'this machine is connected to the Internet' is: ");
  print(await InternetConnectionChecker().hasConnection);
  // returns a bool

  // We can also get an enum value instead of a bool
  print("Current status: ${await InternetConnectionChecker().connectionStatus}");
  // prints either InternetConnectionStatus.connected
  // or InternetConnectionStatus.disconnected

  // This returns the last results from the last call
  // to either hasConnection or connectionStatus
  print("Last results: ${InternetConnectionChecker().lastTryResults}");

  // actively listen for status updates
  // this will cause InternetConnectionChecker to check periodically
  // with the interval specified in InternetConnectionChecker().checkInterval
  // until listener.cancel() is called
  var listener = InternetConnectionChecker().onStatusChange.listen((status) {
    switch (status) {
      case InternetConnectionStatus.connected:
        print('Data connection is available.');
        break;
      case InternetConnectionStatus.disconnected:
        print('You are disconnected from the internet.');
        break;
    }
  });

  // close listener after 30 seconds, so the program doesn't run forever
  await Future.delayed(Duration(seconds: 30));
  await listener.cancel();
}

Note: Remember to dispose of any listeners, when they're not needed to prevent memory leaks, e.g. in a StatefulWidget's dispose() method:

...
@override
void dispose() {
  listener.cancel();
  super.dispose();
}
...

See example folder for more examples.

Features and bugs

Please file feature requests and bugs at the issue tracker.

Comments
  • Modify testing logic to immediately return if any of the simultaneous pings succeed

    Modify testing logic to immediately return if any of the simultaneous pings succeed

    Currently the logic is "All addresses are pinged simultaneously. ... When all the requests complete with either success or failure, a check is made to see if the list contains at least one true boolean.". However if any of the hosts slow to respond (for example for some reason CloudFlare DNSes don't respond (https://github.com/komapeb/data_connection_checker/issues/10#issuecomment-736704451) then we have to wait a timeout (10 seconds, which is excruciating for a user, given that some pings may have already succeeded). In my opinion if any of the pings succeed then the test could already cut short any other pings and return immediately.

    opened by MrCsabaToth 13
  • Edit defaults

    Edit defaults

    I have been testing the package and I think it would be interesting to allow editing of the default values. The main problem I found is that I have to keep the user waiting 10 seconds to notify them that they have no internet. It would be very useful to be able to edit this default value

    opened by adri195 4
  • Ability to provide a host name instead of IP address

    Ability to provide a host name instead of IP address

    Status

    READY

    Breaking Changes

    YES (AddressCheckOptions constructor)

    Description

    I wanted to use reachability of HTTP(S) for www.msftncsi.com as a means of checking connectivity, as it seems that in some rare cases, the DNS TCP connection may be blocked (see several issues mentioning getting false status even though they have a connection, and we have a client that has also experienced a similar issue).

    The rationale for using a hostname is, that it is not guaranteed that the IP address where the HTTP service is hosted, is not going to change in the future (for DNS this isn't a concern, as the servers are expected to not change). Additionally, using a hostname also provides a DNS reachability test for free.

    I've added a hostname field to AddressCheckOptions and extended the checking routine to include a lookup, if a hostname is provided. The positional argument address is now a named, optional argument.

    Since the API has changed (for users that have already added custom addresses), this is a breaking change.

    Other comments

    This PR only includes the hostname support, however I believe it would be useful to also include some well known HTTP servers in the default addresses list, in order to provide better compatibility out-of-the-box. I've chosen www.msftncsi.com for our app, as per the recommendation in https://superuser.com/a/769248.

    Possibly additional documentation may be required before this can be considered shippable.

    Type of Change

    • [x] ✨ New feature (non-breaking change which adds functionality)
    • [ ] πŸ› οΈ Bug fix (non-breaking change which fixes an issue)
    • [x] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] βœ… Build configuration change
    • [ ] πŸ“ Documentation
    • [ ] πŸ—‘οΈ Chore
    opened by gampixi 3
  • Chore: Update connectionStatus' doc comment

    Chore: Update connectionStatus' doc comment

    Remove true, since it doesn't return a bool.

    Status

    READY

    Breaking Changes

    NO

    Description

    Remove true from doc comment of connectionStatus method, since it doesn't return a bool.

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] πŸ› οΈ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] βœ… Build configuration change
    • [x] πŸ“ Documentation
    • [x] πŸ—‘οΈ Chore
    opened by AleksandarSavic95 3
  • Web Platform Support

    Web Platform Support

    Status

    READY

    Breaking Changes

    YES

    Description

    Changes

    • Using universal_io package to resolve #15 and resolve #1 (i.e. InternetAddress not supported in web)
    • Added universal_html and flutter packages
    • Using kIsWeb to identify a web platform

    Problem

    • Socket.connect is not implemented for web platform in universal_io package

    Solution

    • Using
      html.window.navigator.onLine
      

      to get connection status for web

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] πŸ› οΈ Bug fix (non-breaking change which fixes an issue)
    • [x] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [x] 🧹 Code refactor
    • [ ] βœ… Build configuration change
    • [ ] πŸ“ Documentation
    • [ ] πŸ—‘οΈ Chore
    opened by OutdatedGuy 2
  • Allow custom timeout, interval and addresses

    Allow custom timeout, interval and addresses

    Status

    READY

    Breaking Changes

    NO

    Description

    Allow custom timeout, interval and addresses

    Type of Change

    • [x] ✨ New feature (non-breaking change which adds functionality)
    • [ ] πŸ› οΈ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] βœ… Build configuration change
    • [x] πŸ“ Documentation
    • [ ] πŸ—‘οΈ Chore
    opened by jopmiddelkamp 2
  • iOS Crash, physical device and simulator

    iOS Crash, physical device and simulator

    Each time I try to run it on iOS this happened:

    Connecting to the VM Service is taking longer than expected... Still attempting to connect to the VM Service... If you do NOT see the Flutter application running, it might have crashed. The device logs (e.g. from adb or XCode) might have more details. If you do see the Flutter application running on the device, try re-running with --host-vmservice-port to use a specific port known to be available. Exception attempting to connect to the VM Service: SocketException: OS Error: Connection refused, errno = 61, address = 127.0.0.1, port = 51655 This was attempt #50. Will retry in 0:00:01.600000. Exception attempting to connect to the VM Service: SocketException: OS Error: Connection refused, errno = 61, address = 127.0.0.1, port = 51819 This was attempt #100. Will retry in 0:00:01.600000.

    If I try again:

    [+1684 ms] Observatory URL on device: http://127.0.0.1:63790/gFnOkvXor3Y=/ [ +10 ms] Caching compiled dill [ +136 ms] Connecting to service protocol: http://127.0.0.1:63790/gFnOkvXor3Y=/ [ +74 ms] Fail to connect to service protocol: http://127.0.0.1:63790/gFnOkvXor3Y=/: HttpException: Connection closed before full header was received, uri = http://127.0.0.1:63790/gFnOkvXor3Y=/ws [ +2 ms] Error connecting to the service protocol: failed to connect to http://127.0.0.1:63790/gFnOkvXor3Y=/ [ +5 ms] "flutter run" took 134,135ms. [ +11 ms] #0 throwToolExit (package:flutter_tools/src/base/common.dart:10:3) #1 RunCommand.runCommand (package:flutter_tools/src/commands/run.dart:669:9) #2 FlutterCommand.run. (package:flutter_tools/src/runner/flutter_command.dart:1125:27) #3 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) #4 CommandRunner.runCommand (package:args/command_runner.dart:209:13) #5 FlutterCommandRunner.runCommand. (package:flutter_tools/src/runner/flutter_command_runner.dart:288:9) #6 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) #7 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:236:5) #8 run.. (package:flutter_tools/runner.dart:62:9) #9 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) #10 main (package:flutter_tools/executable.dart:92:3) [ +402 ms] ensureAnalyticsSent: 213ms [ +1 ms] Running shutdown hooks [ ] Shutdown hooks complete [ ] exiting with code 2

    It works fine on Android, I also tried on other projects and it works on iOS, I don't know if is a problem with other dependency.

    Edit: Ok, I think this dependency is the problem: flutter_html: ^2.1.2 I've tried on a new project with only two dependencies, no code, and it crash.

    opened by Glexium 2
  • Fixes #12 and Fixes #14

    Fixes #12 and Fixes #14

    Trying to end the test immediately when any of the pings succeed

    Status

    READY

    Breaking Changes

    NO

    Description

    This turned out to be a one keyword change, removing an await so far. I have 6 AWS EC2 IP address for connection test in my app, and some of them started to act up. This caused me 10 seconds default delay. By removing the await there's no more wait. I tried to test the counter case: I put my phone into airplane mode and then the data check determines no connection. So it seems I'm not breaking any functionality. The IPv6 address addition is based on https://github.com/komapeb/data_connection_checker/issues/13#issuecomment-732534075.

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [x] πŸ› οΈ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] βœ… Build configuration change
    • [ ] πŸ“ Documentation
    • [ ] πŸ—‘οΈ Chore
    opened by MrCsabaToth 2
  • Returns false in release build

    Returns false in release build

    InternetConnectionChecker().onStatusChange.listen((event) { final hasInternet = event == InternetConnectionStatus.connected; }); In the above snippet, hasInternet works fine in debug build but keeps returning false in release build even though there is internet connection.

    opened by oltoch 1
  • .hasconnection property doesn't trigger .onStatusChange stream

    .hasconnection property doesn't trigger .onStatusChange stream

    I use a StreamProvider connected to onStatusChange stream with a low Interval. Also in some cases i want to check instantly if app has connection. When i check hasconnection property it says current status of connection but it doesnt feed a value for the stream. Is is possible to feed stream when checking connection status or should i change my algorithm?

    final onlineStatusProvider =
        StreamProvider.autoDispose<ConnectionStatus>((ref) async* {
      InternetConnectionChecker().checkInterval = Duration(seconds: 60);
      await for (final value in InternetConnectionChecker().onStatusChange) {
        yield value == InternetConnectionStatus.connected
            ? ConnectionStatus.online
            : ConnectionStatus.offline;
      }
    });
    

    When I call InternetConnectionChecker().hasConnection; somewhere in application it doesn't trigger onStatusChange stream.

    opened by akyunus 1
  • Add IPv6 hosts to the default addresses

    Add IPv6 hosts to the default addresses

    Some users reported that Apple store submissions may fail or in certain cases the connection check may fail if there are no IPv6 addresses to check among the hosts (see https://github.com/komapeb/data_connection_checker/issues/13). Thereby I propose to add IPv6 versions of the 3 DNS server tested to the default configuration.

    opened by MrCsabaToth 0
  • Why does it wait for all requests to complete if only one needs to be successful?

    Why does it wait for all requests to complete if only one needs to be successful?

    From the README.md:

    When all the requests complete with either success or failure, a check is made to see if the list contains at least one true boolean.

    Returning once a single result is positive could decrease the waiting time:

    This all happens at the same time for all addresses, so the maximum waiting time is the address with the highest specified timeout, in case it's unreachable.

    opened by jakobhec 1
  • Connection checker returning false even there is network connection.

    Connection checker returning false even there is network connection.

    So there is the huge problem, when user have low network signal or when have some kind of slower network. Connection checker returning false but in real, user have the network. Any solution?

    opened by Tomman85 3
  • Three requests at the same time

    Three requests at the same time

    The current code makes three requests to 3 different addresses at the same time which is pretty data-consuming, isn't it better to wait for a request to finish, and if it's a failure, try the next? image

    ` Future get hasConnection async { final Completer result = Completer(); int length = addresses.length;

    for (final AddressCheckOptions addressOptions in addresses) {
      // ignore: unawaited_futures
      isHostReachable(addressOptions).then(
        (AddressCheckResult request) {
          length -= 1;
          if (!result.isCompleted) {
            if (request.isSuccess) {
              result.complete(true);
            } else if (length == 0) {
              result.complete(false);
            }
          }
        },
      );
    }
    
    return result.future;
    

    }`

    A small tweak to this function will do the trick. Thank you.

    opened by AhmedEzio47 1
  • SocketException (SocketException: Connection failed (OS Error: Network is unreachable, errno = 101), address = 2620:0:ccc::2, port = 53

    SocketException (SocketException: Connection failed (OS Error: Network is unreachable, errno = 101), address = 2620:0:ccc::2, port = 53

    Shows this error.. has anyone gone through this

    static final InternetConnectionChecker _instance = InternetConnectionChecker.createInstance();

    /// Ping a single address. See [AddressCheckOptions] for /// info on the accepted argument. Future isHostReachable( AddressCheckOptions options, ) async { Socket? sock; try { sock = await Socket.connect(

    opened by Rodrigossff91 1
  • hasConnection return false for some internet provider

    hasConnection return false for some internet provider

    Hi, I from Indonesia and I tried this lib is working normal until I found error always return false for 1 internet provider the name is "tri"(https://tri.co.id/), even there is mobile connection (can browsing, chat, etc). thanks

    opened by eggysudianto 0
Releases(0.0.1+3)
A utility library to automate mobile emulators.

emulators A utility library to automate mobile emulators. Can be used to automate screenshots on multiple devices. Example project https://github.com/

Tim 21 Nov 13, 2022
Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.

Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.

Google 905 Jan 2, 2023
A Dart testing utility for asserting that some code emits a compilation error.

A Dart testing utility for asserting that some code emits a compilation error.

Remi Rousselet 32 Dec 11, 2022
A simple Flutter / Dart Utility class for converting complex objects to uri and query string

A simple Flutter / Dart Utility class for converting complex or nested objects to uri and query strings you can follow the the article on how this cla

Opata Joshua 5 Sep 7, 2022
Uproot(uprt) is a multi-platform (Windows, MacOs, and Linux) command line utility written in Dart to convert a router's DHCP IP Reservations between routers

UPROOT Uproot(uprt) is a multi-platform (Windows, MacOs, and Linux) command line utility written in Dart to convert a router's DHCP IP Reservations be

GeekVisit 73 Jan 1, 2023
Contains utility functions and classes in the style of dart:collection to make working with collections easier

The collection package for Dart contains a number of separate libraries with utility functions and classes that makes working with collections easier.

Dart 273 Dec 27, 2022
A pure dart package to apply useful rate limiting strategies on regular functions.

Rate limiting is a strategy for limiting an action. It puts a cap on how often someone can repeat an action within a certain timeframe. Using rate_limiter we made it easier than ever to apply these strategies on regular dart functions.

Stream 24 Dec 14, 2022
A pure Dart implementation of the Pusher Channels Client

pusher_channels is a pure Dart pusher channels client. This client is work in progress and it is unstable. Usage A simple usage example: import 'packa

Indaband 7 Nov 6, 2022
A flutter utility to easily create flavors in your flutter application

Flutter Flavorizr A flutter utility to easily create flavors in your flutter application Getting Started Let's start by setting up our environment in

Angelo Cassano 268 Jan 1, 2023
CLI utility to manage MC Server installations

CLI utility to manage MC server installations. Features Install required JDKs Download server files Generate start scripts (with optimized JVM flags)

Michael Rittmeister 14 Nov 18, 2022
Utility to process H264 profile-level-id values

h264_profile_level_id Dart utility to process H264 profile-level-id values based on Google's libwebrtc C++ code. API import 'package:h264_profile_leve

Ibragim Abbasov 2 Apr 22, 2022
πŸ” πŸ‘€ CLI utility to check last-visit of your CodeForces friends & much more, πŸš€ powered by CodeForces API

JoJo ?? ?? CLI utility to check last-visit of your CodeForces friends & much more, ?? powered by CodeForces API Features Online Friends All Friends Pr

Tirth 5 Jul 20, 2020
A Dart library to parse Portable Executable (PE) format

pefile A Dart library to parse Portable Executable (PE) format Usage A simple usage example: var pe = pefile.parse('C:\\Windows\\System32\\notepad.exe

null 4 Sep 12, 2022
An alternative random library for Dart.

Randt Randt library for Dart... Description Use Randt to get a random integer from a list, generate random integer in a specific range and generate ra

Bangladesh Coding Soldierz 3 Nov 21, 2021
The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

null 2 Oct 8, 2021
A comprehensive, cross-platform path manipulation library for Dart.

A comprehensive, cross-platform path manipulation library for Dart. The path package provides common operations for manipulating paths: joining, split

Dart 159 Dec 29, 2022
A fast algorithm for finding polygon pole of inaccessibility implemented as a Dart library.

polylabel Dart port of https://github.com/mapbox/polylabel. A fast algorithm for finding polygon pole of inaccessibility implemented as a Dart library

AndrΓ© Sousa 2 Nov 13, 2021
Dart library for unescaping HTML-encoded strings

html_unescape A Dart library for unescaping HTML-encoded strings. Supports: Named Character References (Β ) 2099 of them Decimal Character Referen

Filip Hracek 36 Dec 20, 2022
This is a dart library covering nearly 100% of the latest Planning Center public API.

Planning Center API for Dart Planning Center is an online platform for church management. It provides multiple apps for things like check-ins, service

null 1 Oct 6, 2022