flutterasynchronousconnectionflutter-stateflutter-streambuilder

How can I achieve connection check globally across the flutter application?


I would like to make my flutter application to be able to check the connection status and prompt a warning if the wifi and mobile network is turned off. However, I want to make this globally across the application which means the application will constantly listen for network changes until the application is exited. I do not know how to achieve that. I use Provider as the state management for my project. The package I use for checking the network status are internet_connection_checker and connectivity_plus.

main.dart

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:provider/provider.dart';
import 'package:test/page/error.dart';
import 'package:test/routes.dart';
import 'package:test/service/connection_manager.dart';
import 'package:test/service/firebase_service.dart';
import 'package:test/firebase_options.dart';
import 'package:test/globals.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';


Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  await FirebaseService().initNotifications();
  await FirebaseService().initFirebaseRemoteConfig();

  int mainCount = 1;

  try {
    await deviceManager.getCurrentLocation();
    print('Main() is executed for $mainCount time(s)');
    mainCount ++;
  } catch(e) {
      print('Error getting current location: $e');
      try {
        await deviceManager.getLastestLocation();
      } catch (e) {
        print('Error getting latest location: $e');
      }
    }


  FlutterError.onError = (FlutterErrorDetails details) {
    runApp(const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: AppErrorScreen(),
    ));
  };


  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ConnectionManager()),
        ChangeNotifierProvider(create: (_) => Globals()),
      ],
      child: MyApp(),
    ),
  );
}



class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: AppRoute().route,
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      debugShowCheckedModeBanner: false,
    );
  }
}

connection.dart

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

class ConnectionManager with ChangeNotifier {
  final Connectivity _connectivity = Connectivity();
  bool _isConnected = false;
  late StreamSubscription<List<ConnectivityResult>> _subscription;

  bool get isConnected => _isConnected;

  ConnectionManager() {
    _subscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
    _checkInitialConnection();
  }





  Future<void> _checkInitialConnection() async {
    final List<ConnectivityResult> connectivityResult = await _connectivity.checkConnectivity();
    // await _updateConnectionStatus(connectivityResult);
  }

  Future<void> _updateConnectionStatus(List<ConnectivityResult> result) async {
    bool isConnected = false;

    if (result != ConnectivityResult.none) {
      try {
        final lookupResult = await InternetAddress.lookup('google.com');
        isConnected = lookupResult.isNotEmpty;
      } on SocketException catch (_) {
        isConnected = false;
      }
    }

    _isConnected = isConnected;
    notifyListeners();
  }

I have tried to make the connection check function into a stream however I am new to stream I am not quite sure how can I implement it across the application.


Solution

  • You can use it like this

    Packages

     connectivity_plus: "5.0.0"
     internet_connection_checker:
    

    Code

    import 'package:flutter/material.dart';
    import 'package:next_app_prototype/features/home/presentation/pages/home_page.dart';
    import 'package:provider/provider.dart';
    import 'dart:async';
    import 'dart:io';
    import 'package:connectivity_plus/connectivity_plus.dart';
    import 'package:internet_connection_checker/internet_connection_checker.dart';
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      runApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => ConnectionManager()),
          ],
          child: const MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Home'),
            ),
            body: Consumer<ConnectionManager>(
              builder: (context, connectionManager, child) {
                if (!connectionManager.isConnected) {
                  WidgetsBinding.instance.addPostFrameCallback((_) {
                    showDialog(
                      context: context,
                      builder: (context) => AlertDialog(
                        title: const Text('No Internet Connection'),
                        content: const Text('Please check your internet settings.'),
                        actions: <Widget>[
                          TextButton(
                            onPressed: () => Navigator.of(context).pop(),
                            child: const Text('OK'),
                          ),
                        ],
                      ),
                    );
                  });
                }
    
                return const HomeScreen();
              },
            ),
          ),
        );
      }
    }
    
    class HomeScreen extends StatefulWidget {
      const HomeScreen({super.key});
    
      @override
      State<HomeScreen> createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      @override
      Widget build(BuildContext context) {
        return const Center(child: Text('Home Page'));
      }
    }
    
    class ConnectionManager with ChangeNotifier {
      final Connectivity _connectivity = Connectivity();
      bool _isConnected = true;
      late StreamSubscription<ConnectivityResult> _subscription;
      late StreamSubscription<InternetConnectionStatus> _internetSubscription;
    
      bool get isConnected => _isConnected;
    
      ConnectionManager() {
        _subscription = _connectivity.onConnectivityChanged.listen(_updateConnectivityStatus);
        _internetSubscription = InternetConnectionChecker().onStatusChange.listen(_updateInternetStatus);
        _checkInitialConnection();
      }
    
      Future<void> _checkInitialConnection() async {
        final connectivityResult = await _connectivity.checkConnectivity();
        await _updateConnectivityStatus(connectivityResult);
        final internetResult = await InternetConnectionChecker().hasConnection;
        _updateInternetStatus(internetResult ? InternetConnectionStatus.connected : InternetConnectionStatus.disconnected);
      }
    
      Future<void> _updateConnectivityStatus(ConnectivityResult result) async {
        _isConnected = result != ConnectivityResult.none;
        if (_isConnected) {
          try {
            final lookupResult = await InternetAddress.lookup('google.com');
            _isConnected = lookupResult.isNotEmpty && lookupResult[0].rawAddress.isNotEmpty;
          } on SocketException catch (_) {
            _isConnected = false;
          }
        }
        notifyListeners();
      }
    
      Future<void> _updateInternetStatus(InternetConnectionStatus status) async {
        _isConnected = status == InternetConnectionStatus.connected;
        notifyListeners();
      }
    
      @override
      void dispose() {
        _subscription.cancel();
        _internetSubscription.cancel();
        super.dispose();
      }
    }