Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check whether there is an Internet connection available on Flutter app

People also ask

How do you check internet connection in Flutter?

To check the internet connection in Flutter, you need to add the connectivity plus plugin and then you can check the internet connection by manually calling its checkConnectivity method or listen to the network connectivity changes by calling its onConnectivityChanged.

Does Flutter run without internet?

If its first install flutter needs to get its dependencies. You do need an internet connection for this.

How do I check if my internet connection is stable?

To test your Internet stability, you'll need a computer on your network capable of issuing a "ping" command and receiving a response. Place the computer outside of your firewall or turn off any software firewalls that may be installed. It's also best to test your Internet through a cable connection and not Wi-Fi.


The connectivity plugin states in its docs that it only provides information if there is a network connection, but not if the network is connected to the Internet

Note that on Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi with no access.

You can use

import 'dart:io';
...
try {
  final result = await InternetAddress.lookup('example.com');
  if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
    print('connected');
  }
} on SocketException catch (_) {
  print('not connected');
}

For anyone else who lands here I'd like to add on to Günter Zöchbauer's answer this was my solution for implementing a utility to know if there's internet or not regardless of anything else.

Disclaimer:

I'm new to both Dart and Flutter so this may not be the best approach, but would love to get feedback.


Combining flutter_connectivity and Günter Zöchbauer's connection test

My requirements

I didn't want to have a bunch of repeated code anywhere I needed to check the connection and I wanted it to automatically update components or anything else that cared about the connection whenever there was a change.

ConnectionStatusSingleton

First we setup a Singleton. If you're unfamiliar with this pattern there's a lot of good info online about them. But the gist is that you want to make a single instance of a class during the application life cycle and be able to use it anywhere.

This singleton hooks into flutter_connectivity and listens for connectivity changes, then tests the network connection, then uses a StreamController to update anything that cares.

It looks like this:

import 'dart:io'; //InternetAddress utility
import 'dart:async'; //For StreamController/Stream

import 'package:connectivity/connectivity.dart';

class ConnectionStatusSingleton {
    //This creates the single instance by calling the `_internal` constructor specified below
    static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
    ConnectionStatusSingleton._internal();

    //This is what's used to retrieve the instance through the app
    static ConnectionStatusSingleton getInstance() => _singleton;

    //This tracks the current connection status
    bool hasConnection = false;

    //This is how we'll allow subscribing to connection changes
    StreamController connectionChangeController = new StreamController.broadcast();

    //flutter_connectivity
    final Connectivity _connectivity = Connectivity();

    //Hook into flutter_connectivity's Stream to listen for changes
    //And check the connection status out of the gate
    void initialize() {
        _connectivity.onConnectivityChanged.listen(_connectionChange);
        checkConnection();
    }

    Stream get connectionChange => connectionChangeController.stream;

    //A clean up method to close our StreamController
    //   Because this is meant to exist through the entire application life cycle this isn't
    //   really an issue
    void dispose() {
        connectionChangeController.close();
    }

    //flutter_connectivity's listener
    void _connectionChange(ConnectivityResult result) {
        checkConnection();
    }

    //The test to actually see if there is a connection
    Future<bool> checkConnection() async {
        bool previousConnection = hasConnection;

        try {
            final result = await InternetAddress.lookup('google.com');
            if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
                hasConnection = true;
            } else {
                hasConnection = false;
            }
        } on SocketException catch(_) {
            hasConnection = false;
        }

        //The connection status changed send out an update to all listeners
        if (previousConnection != hasConnection) {
            connectionChangeController.add(hasConnection);
        }

        return hasConnection;
    }
}

Usage

Initialization

First we have to make sure we call the initialize of our singleton. But only once. This parts up to you but I did it in my app's main():

void main() {
    ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
    connectionStatus.initialize();

    runApp(MyApp());

    //Call this if initialization is occuring in a scope that will end during app lifecycle
    //connectionStatus.dispose();   
}

In Widget or elsewhere

import 'dart:async'; //For StreamSubscription

...

class MyWidgetState extends State<MyWidget> {
    StreamSubscription _connectionChangeStream;

    bool isOffline = false;

    @override
    initState() {
        super.initState();

        ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
        _connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
    }

    void connectionChanged(dynamic hasConnection) {
        setState(() {
            isOffline = !hasConnection;
        });
    }

    @override
    Widget build(BuildContext ctxt) {
        ...
    }
}

Hope somebody else finds this useful!


Example github repo: https://github.com/dennmat/flutter-connectiontest-example

Toggle airplane mode in the emulator to see the result


Null Safe code:

  • One time check:

    Create this method:

    Future<bool> hasNetwork() async {
      try {
        final result = await InternetAddress.lookup('example.com');
        return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
      } on SocketException catch (_) {
        return false;
      }
    }
    

    Usage:

    bool isOnline = await hasNetwork();
    
  • Setting up a listener:

    Add the following dependency to your pubspec.yaml file.

    connectivity_plus: ^2.0.2
    

    Full code:

    void main() => runApp(MaterialApp(home: HomePage()));
    
    class HomePage extends StatefulWidget {
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      Map _source = {ConnectivityResult.none: false};
      final MyConnectivity _connectivity = MyConnectivity.instance;
    
      @override
      void initState() {
        super.initState();
        _connectivity.initialise();
        _connectivity.myStream.listen((source) {
          setState(() => _source = source);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        String string;
        switch (_source.keys.toList()[0]) {
          case ConnectivityResult.mobile:
            string = 'Mobile: Online';
            break;
          case ConnectivityResult.wifi:
            string = 'WiFi: Online';
            break;
          case ConnectivityResult.none:
          default:
            string = 'Offline';
        }
    
        return Scaffold(
          body: Center(child: Text(string)),
        );
      }
    
      @override
      void dispose() {
        _connectivity.disposeStream();
        super.dispose();
      }
    }
    
    class MyConnectivity {
      MyConnectivity._();
    
      static final _instance = MyConnectivity._();
      static MyConnectivity get instance => _instance;
      final _connectivity = Connectivity();
      final _controller = StreamController.broadcast();
      Stream get myStream => _controller.stream;
    
      void initialise() async {
        ConnectivityResult result = await _connectivity.checkConnectivity();
        _checkStatus(result);
        _connectivity.onConnectivityChanged.listen((result) {
          _checkStatus(result);
        });
      }
    
      void _checkStatus(ConnectivityResult result) async {
        bool isOnline = false;
        try {
          final result = await InternetAddress.lookup('example.com');
          isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty;
        } on SocketException catch (_) {
          isOnline = false;
        }
        _controller.sink.add({result: isOnline});
      }
    
      void disposeStream() => _controller.close();
    }
    

Screenshot:

enter image description here

Credit to : connectivity_plus and Günter Zöchbauer


I found that just using the connectivity package was not enough to tell if the internet was available or not. In Android it only checks if there is WIFI or if mobile data is turned on, it does not check for an actual internet connection . During my testing, even with no mobile signal ConnectivityResult.mobile would return true.

With IOS my testing found that the connectivity plugin does correctly detect if there is an internet connection when the phone has no signal, the issue was only with Android.

The solution I found was to use the data_connection_checker package along with the connectivity package. This just makes sure there is an internet connection by making requests to a few reliable addresses, the default timeout for the check is around 10 seconds.

My finished isInternet function looked a bit like this:

  Future<bool> isInternet() async {
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile) {
      // I am connected to a mobile network, make sure there is actually a net connection.
      if (await DataConnectionChecker().hasConnection) {
        // Mobile data detected & internet connection confirmed.
        return true;
      } else {
        // Mobile data detected but no internet connection found.
        return false;
      }
    } else if (connectivityResult == ConnectivityResult.wifi) {
      // I am connected to a WIFI network, make sure there is actually a net connection.
      if (await DataConnectionChecker().hasConnection) {
        // Wifi detected & internet connection confirmed.
        return true;
      } else {
        // Wifi detected but no internet connection found.
        return false;
      }
    } else {
      // Neither mobile data or WIFI detected, not internet connection found.
      return false;
    }
  }

The if (await DataConnectionChecker().hasConnection) part is the same for both mobile and wifi connections and should probably be moved to a separate function. I've not done that here to leave it more readable.

This is my first Stack Overflow answer, hope it helps someone.


Using

dependencies:
  connectivity: ^0.4.2

what we got from resouces is

      import 'package:connectivity/connectivity.dart';

      Future<bool> check() async {
        var connectivityResult = await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.mobile) {
          return true;
        } else if (connectivityResult == ConnectivityResult.wifi) {
          return true;
        }
        return false;
      }

Future is little problematic for me, we have to implement it every single time like :

check().then((intenet) {
      if (intenet != null && intenet) {
        // Internet Present Case
      }
      // No-Internet Case
    });

So to solve this problem i have created a class Which accept a function with boolean isNetworkPresent parameter like this

methodName(bool isNetworkPresent){}

And the Utility Class is

import 'package:connectivity/connectivity.dart';

class NetworkCheck {
  Future<bool> check() async {
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile) {
      return true;
    } else if (connectivityResult == ConnectivityResult.wifi) {
      return true;
    }
    return false;
  }

  dynamic checkInternet(Function func) {
    check().then((intenet) {
      if (intenet != null && intenet) {
        func(true);
      }
      else{
    func(false);
  }
    });
  }
}

And to use connectivity-check utilty

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

i will use this syntax

NetworkCheck networkCheck = new NetworkCheck();
networkCheck.checkInternet(fetchPrefrence)

I've created a package that (I think) deals reliably with this issue.

The package on pub.dev

The package on GitHub

Discussion is very welcome. You can use the issues tracker on GitHub.


I no longer think this below is a reliable method:


Wanna add something to @Oren's answer: you should really add one more catch, which will catch all other exceptions (just to be safe), OR just remove the exception type altogether and use a catch, that deals with all of the exceptions:

Case 1:

try {
  await Firestore.instance
    .runTransaction((Transaction tx) {})
    .timeout(Duration(seconds: 5));
  hasConnection = true;
} on PlatformException catch(_) { // May be thrown on Airplane mode
  hasConnection = false;
} on TimeoutException catch(_) {
  hasConnection = false;
} catch (_) {
  hasConnection = false;
}

or even simpler...

Case 2:


try {
  await Firestore.instance
    .runTransaction((Transaction tx) {})
    .timeout(Duration(seconds: 5));
  hasConnection = true;
} catch (_) {
  hasConnection = false;
}

I made a base class for widget state

Usage instead of State<LoginPage> use BaseState<LoginPage> then just use the boolean variable isOnline

Text(isOnline ? 'is Online' : 'is Offline')

First, add connectivity plugin:

dependencies:
  connectivity: ^0.4.3+2

Then add the BaseState class

import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';

import 'package:connectivity/connectivity.dart';
import 'package:flutter/widgets.dart';

/// a base class for any statful widget for checking internet connectivity
abstract class BaseState<T extends StatefulWidget> extends State {

  void castStatefulWidget();

  final Connectivity _connectivity = Connectivity();

  StreamSubscription<ConnectivityResult> _connectivitySubscription;

  /// the internet connectivity status
  bool isOnline = true;

  /// initialize connectivity checking
  /// Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initConnectivity() async {
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print(e.toString());
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) {
      return;
    }

    await _updateConnectionStatus().then((bool isConnected) => setState(() {
          isOnline = isConnected;
        }));
  }

  @override
  void initState() {
    super.initState();
    initConnectivity();
    _connectivitySubscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult result) async {
      await _updateConnectionStatus().then((bool isConnected) => setState(() {
            isOnline = isConnected;
          }));
    });
  }

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

  Future<bool> _updateConnectionStatus() async {
    bool isConnected;
    try {
      final List<InternetAddress> result =
          await InternetAddress.lookup('google.com');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        isConnected = true;
      }
    } on SocketException catch (_) {
      isConnected = false;
      return false;
    }
    return isConnected;
  }
}

And you need to cast the widget in your state like this

@override
  void castStatefulWidget() {
    // ignore: unnecessary_statements
    widget is StudentBoardingPage;
  }