Search code examples
firebaseflutterconnectionstream-builder

How do you check internet ACCESS continously in flutter.dart, not connection


how do you continously check internet access? I was able to show if wifi is connectected or mobile data. However, not all connection would have internet access.

 import 'package:connectivity/connectivity.dart';

var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
  // I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
  // I am connected to a wifi network.
}

This is currently the code im using. I was hoping how someone could check continously of internet access?


Solution

  • Here is the way you can build Network Aware applications

    High level overview

    1. Create a service that listen to Connectivity change events, for
      example wifi, mobile and none (offline). This service will emit
      NewtorkStatus (our custom class) into a stream every time the
      Connectivity changes.

    2. Create consumer for the above NetworkStatus stream that will be
      notified everytime the NetworkStatus changes.

    3. Based on the network status rebuild the HomeScreen to show either
      online or offline contents.

    Sounds tricky but its actually easy to implement, we will be using connectivity & provider package to our rescue.

    Firstly configure our project to use above dependencies, edit pubspec.yaml to include the dependencies -

    dependencies:
      flutter:
        sdk: flutter
      connectivity: ^3.0.6
      provider: ^6.0.1
    

    Run $ pub get you synchronise all the dependencies.

    Now we will create our own NewtorkStatusService this service will use NetworkStatus enumeration with two states Online & Offline to notify the Connectivity state.

    network_status_service.dart

    enum NetworkStatus { 
      Online, 
      Offline 
    }
    

    Now our NetworkStatusService will use the Connectivity package to get status of current connection status (wifi, mobile, none) and based on that it will emit a new NetworkStatus to stream. Our final NetworkStatusService would look something like this -

    network_status_service.dart

    import 'dart:async';
    import 'package:connectivity/connectivity.dart';
    
    enum NetworkStatus { Online, Offline }
    
    class NetworkStatusService {
      StreamController<NetworkStatus> networkStatusController =
          StreamController<NetworkStatus>();
    
      NetworkStatusService() {
        Connectivity().onConnectivityChanged.listen((status){
          networkStatusController.add(_getNetworkStatus(status));
        });
      }
    
      NetworkStatus _getNetworkStatus(ConnectivityResult status) {
        return status == ConnectivityResult.mobile || status == ConnectivityResult.wifi ? NetworkStatus.Online : NetworkStatus.Offline;
      }
    }
    

    Now we will create our won custom widget that will return either an onlineChild or offlineChild based on NetworkStatus value. Here we will use provider package to get NetworkStatus. I would look something like this -

    network_aware_widget.dart

    import 'package:flutter/material.dart';
    import 'package:flutter_network_aware_app/services/network_status_service.dart';
    import 'package:fluttertoast/fluttertoast.dart';
    import 'package:provider/provider.dart';
    
    class NetworkAwareWidget extends StatelessWidget {
      final Widget onlineChild;
      final Widget offlineChild;
    
      const NetworkAwareWidget({Key? key, required this.onlineChild, required this.offlineChild})
          : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        NetworkStatus networkStatus = Provider.of<NetworkStatus>(context);
        if (networkStatus == NetworkStatus.Online) {
          return onlineChild;
        } else {
          _showToastMessage("Offline");
          return offlineChild;
        }
      }
    
      void _showToastMessage(String message){
        Fluttertoast.showToast(
            msg: message,
            toastLength: Toast.LENGTH_LONG,
            gravity: ToastGravity.BOTTOM,
            timeInSecForIosWeb: 1
        );
      }
    }
    

    Here I am also using the FlutterToast to show toast message (just to add some interactivity to app)

    Now's the fun part we will bring all the pieces together to make our app respond to NetworkStatus value. We will use out custom made widget inside a StreamProvider widget. The StreamProvider will subscribe on the NewtorkStatusService networkStatusController stream and trigger a build on child components every time the NetworkStatus changes to Online or Offline. Here's how it will look -

    home.dart

    import 'package:flutter/material.dart';
    import 'package:flutter_network_aware_app/services/network_status_service.dart';
    import 'package:flutter_network_aware_app/ui/components/network_aware_widget.dart';
    import 'package:provider/provider.dart';
    
    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            centerTitle: true,
            title: Text("Network Aware App"),
          ),
          body: StreamProvider<NetworkStatus>(
            create: (context) =>
                NetworkStatusService().networkStatusController.stream,
            child: NetworkAwareWidget(
              onlineChild: Container(
                child: Center(
                  child: Text(
                    "I am online",
                    style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w600),
                  ),
                ),
              ),
              offlineChild: Container(
                child: Center(
                  child: Text(
                    "No internet connection!",
                    style: TextStyle(
                        color: Colors.grey[400],
                        fontWeight: FontWeight.w600,
                        fontSize: 20.0),
                  ),
                ),
              ),
            ),
          ),
        );
      }
    }
    

    As you can see we are wrapping our NetworkAwareWidget inside a StreamProvider of NetworkStatus. StreamProvider also makes sure that on create it will subscribe to the NetworkStatusService controller stream.

    Finally our app starting point main.dart will look something like this -

    main.dart

    import 'package:flutter/material.dart';
    import 'package:flutter_network_aware_app/ui/screens/home_screen.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Flutter Demo',
            debugShowCheckedModeBanner: false,
            theme: ThemeData.dark().copyWith(primaryColor: Colors.blue),
            home: Home());
      }
    }
    

    The application would work as follows -

    Online Offline Demo

    I hope this helps you to build you own network aware app and components!