8

I use this code for check internet. and I wrap this function into initState also. Snack bar always displays when internet not available. But after connecting to the internet, the snack bar is not disappeared. I can't use connectivity plugin because they said on Android, the plugin does not guarantee connection to the Internet.

 checking1(TextEditingController usernameController, BuildContext context,
      String _url, GlobalKey<ScaffoldState> _scaffoldKey) async {
    try {
      final result = await InternetAddress.lookup('google.com');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        usernameController.text == '' ?
        showDialog(...some code...) :
        usernameValidation(usernameController.text, context, _url);
      }
    }
    on SocketException
    catch (_) {
      _showSnackBar(_scaffoldKey);
    }
  }

4 Answers4

16

enter image description here

Full example demonstrating a listener of the internet connectivity and its source.

Original post

import 'dart:async';
import 'dart:io';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: HomePage()));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Map _source = {ConnectivityResult.none: false};
  MyConnectivity _connectivity = MyConnectivity.instance;

  @override
  void initState() {
    super.initState();
    _connectivity.initialise();
    _connectivity.myStream.listen((source) {
      setState(() => _source = source);
    });
  }

  @override
  Widget build(BuildContext context) {
    String status = "Offline";
    switch (_source.keys.toList()[0]) {
      case ConnectivityResult.none:
        status = "Offline";
        break;
      case ConnectivityResult.mobile:
        status = "Mobile: Online";
        break;
      case ConnectivityResult.wifi:
        status = "WiFi: Online";
        break;
      case ConnectivityResult.ethernet:
        status = "Ethernet: Online";
        break;
    }

    return Scaffold(
      appBar: AppBar(title: Text("Internet")),
      body: Center(child: Text(status)),
    );
  }

  @override
  void dispose() {
    _connectivity.disposeStream();
    super.dispose();
  }
}

class MyConnectivity {
  MyConnectivity._internal();

  static final MyConnectivity _instance = MyConnectivity._internal();

  static MyConnectivity get instance => _instance;

  Connectivity connectivity = Connectivity();

  StreamController 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');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        isOnline = true;
      } else {
        isOnline = false;
      }
    } on SocketException catch (_) {
      isOnline = false;
    }
    controller.sink.add({result: isOnline});
  }

  void disposeStream() => controller.close();
}
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
  • var result = await Connectivity().checkConnectivity(); giving me error like "ConnectivityService: Neither user 11177 nor current process has android.permission.ACCESS_NETWORK_STATE., null)" Can anybody help ? – Jay Mungara Sep 18 '19 at 05:33
  • @JayMungara I am not able to get the partial error, have you added the `ACCESS_NETWORK_STATE` permission to your `AndroidManifest.xml` file? – CopsOnRoad Sep 18 '19 at 06:34
  • @JayMungara It would help if you can share the screenshot of the error. – CopsOnRoad Sep 18 '19 at 06:39
  • Checkout the issue here https://github.com/flutter/flutter/issues/40731 – Jay Mungara Sep 18 '19 at 06:42
  • @JayMungara Did you run my code, is it working? Are you seeing any error in it? And if yes, I'll be happy to assist you on Stackoverflow itself (not Github), if you can ask a question, and share its link with me. – CopsOnRoad Sep 18 '19 at 06:44
  • Can you please tell me what is the meaning of doing this "MyConnectivity._internal(); static final MyConnectivity _instance = MyConnectivity._internal();" ? – Jay Mungara Nov 04 '19 at 05:23
  • @JayMungara That's done on purpose to make sure we have a singleton class `MyConnectivity` – CopsOnRoad Nov 04 '19 at 14:45
  • We could have done it using static final MyConnectivity _instance = MyConnectivity() i think. right? – Jay Mungara Nov 04 '19 at 18:00
  • @JayMungara Yes, you can do that but that won't be singleton anymore, since you can easily get access to `MyConnectivity()` constructor from outside. – CopsOnRoad Nov 05 '19 at 08:08
  • Interesting how the above code doesn't look like it actually uses the result argument. So is that used to perhaps do some extra things to the connectivity result, but isn't actually required to do a lookup with? – mafiOSo Jul 07 '20 at 00:04
8

Another option also can be this package: https://pub.dartlang.org/packages/flutter_offline that deal with this issue really straightforward.

You need first to import the package 'package:flutter_offline/flutter_offline.dart';

After that you include the OfflineBuilder on Widget build(BuildContext context) and it will read all all stream changes from ConnectivityResult continuously.

Like the example on the link or like the following one

      @override
  Widget build(BuildContext context) {
    return OfflineBuilder(

        debounceDuration: Duration.zero,
        connectivityBuilder: (
            BuildContext context,
            ConnectivityResult connectivity,
            Widget child,
            ) {
          if (connectivity == ConnectivityResult.none) {

            return Scaffold(
              appBar: AppBar(
                title: const Text('Home'),
              ),
              body: Center(child: Text('Please check your internet connection!')),
            );
          }
          return child;
        },


        child: Scaffold(
          resizeToAvoidBottomPadding: false,
          appBar: AppBar(
              title: Text("Home")
          ),
          body: new Column(
            children: <Widget>[
              new Container(
                decoration: new BoxDecoration(color: Theme.of(context).cardColor),
                child: _buildTxtSearchBox(),
              ),
              new Divider(height: 10.0),
              new FloatingActionButton.extended(
                icon: Icon(Icons.camera_alt),
              ),
              new Container(
              ... 
              ),
            ],
          ),
          floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
          drawer: MenuDrawer(),
        )
    );
  }
nike
  • 715
  • 2
  • 8
  • 14
  • 1
    this looks nice, but im confused why there has to be a child property instead of just returning the widget inside the builder. that way, all widgets can get access to the connectivity result – chitgoks Jul 02 '20 at 08:55
6

The connectivity package will do what you want. It has an onConnectivityChanged stream which you can subscribe to. This will notify your app when the connectivity state changes. But just because your device is connected to a network doesn't mean it can access your server and be connected. So a DNS lookup would be a good idea before then updating the internal state of your application.

https://pub.dartlang.org/documentation/connectivity/latest/connectivity/Connectivity-class.html

Simon
  • 10,932
  • 50
  • 49
2

I find this to be reliable & more convincing :

Future<bool> connectivityChecker() async {
  var connected = false;
  print("Checking internet...");
  try {
    final result = await InternetAddress.lookup('google.com');
    final result2 = await InternetAddress.lookup('facebook.com');
    final result3 = await InternetAddress.lookup('microsoft.com');
    if ((result.isNotEmpty && result[0].rawAddress.isNotEmpty) ||
        (result2.isNotEmpty && result2[0].rawAddress.isNotEmpty) ||
        (result3.isNotEmpty && result3[0].rawAddress.isNotEmpty)) {
      print('connected..');
      connected = true;
    } else {
      print("not connected from else..");
      connected = false;
    }
  } on SocketException catch (_) {
    print('not connected...');
    connected = false;
  }
  return connected;
}

Based on the bool value of connected returned, I'd run a timer based loop to check for internet again & again till its connected. Open to any suggestions

Adrian Karr
  • 137
  • 2
  • 13