이코노딩

[Flutter] connectivity_plus 네트워크 상태 읽기 본문

언어/Dart & Flutter

[Flutter] connectivity_plus 네트워크 상태 읽기

떼이로 2022. 11. 21. 16:19

▼자세한 내용▼

 https://pub.dev/packages/connectivity_plus/changelog

 

connectivity_plus | Flutter Package

Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS.

pub.dev

 

1. 설치

dependencies:
	connectivity_plus: ^3.0.2

pubspec.yalm 파일에 dependence해준 후 Pub get

import 'package:connectivity_plus/connectivity_plus.dart';

2. Example Code

먼저, 사용할 변수를 선언

//연결 상태 값
ConnectivityResult _connectionStatus = ConnectivityResult.none;
//연결
final Connectivity _connectivity = Connectivity();
//연결 상태 스트림
late StreamSubscription<ConnectivityResult> _connectivitySubscription;

변수를 선언해준 뒤 init와 dispose 함수 생성

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

    _connectivitySubscription =
        _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
  }

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

 스트림은 커넥트의 상태가 바뀔때마다 체크해줌, 플렛폼 메세지는 비동기.. 그래서 초기화가 필요하다

 // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initConnectivity() async {
    late ConnectivityResult result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      result = await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print('Couldn\'t check connectivity status  error: ${e}');
      return;
    }

    // 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 Future.value(null);
    }

    return _updateConnectionStatus(result);
  }

try와 catch를 이용해서 exception 잡아주고 result를 상태 업데이트 함수로 넘겨서 처리

Future<void> _updateConnectionStatus(ConnectivityResult result) async {
    setState(() {
      if(_connectionStatus == ConnectivityResult.mobile && result == ConnectivityResult.wifi){
        mobileToWifi();
      }else if(_connectionStatus == ConnectivityResult.wifi && result == ConnectivityResult.mobile){
        wifiToMobile();
      }
      _connectionStatus = result;
    });
    switch(result) {
      case ConnectivityResult.wifi: networkTest();
      break;
      case ConnectivityResult.mobile: networkTest();
      break;
      case ConnectivityResult.none: networkOutage();
      break;
    }
  }

총 4개의 알림으로 구분함.

모바일 데이터에서 와이파이로 바뀌었을 때 Snackbar 

와이파이에서 모바일데이터로 바뀌었을 때 Snackbar 

네트워크 끊겼을 때 AlertDialog 

까지는 쉽게 해결함

 

네트워크가 느릴 때 AlertDialog 뛰우고 싶은데...

지금은 http를 사용하여 http를 호출할 때 timeout을 줘서 반환값 확인해서 해보려고하는데,  계획이 바뀔 수 있어서 이 네트워크 속도를 측정하는 방법은 좀 더 고민을 해봐야할 것 같다.

3. 전체코드

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Network Alert Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ConnectivityResult _connectionStatus = ConnectivityResult.none;
  final Connectivity _connectivity = Connectivity();
  late StreamSubscription<ConnectivityResult> _connectivitySubscription;

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

    _connectivitySubscription =
        _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
  }

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

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initConnectivity() async {
    late ConnectivityResult result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      result = await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print('Couldn\'t check connectivity status  error: ${e}');
      return;
    }

    // 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 Future.value(null);
    }

    return _updateConnectionStatus(result);
  }

  Future<void> _updateConnectionStatus(ConnectivityResult result) async {
    setState(() {
      if(_connectionStatus == ConnectivityResult.mobile && result == ConnectivityResult.wifi){
        mobileToWifi();
      }else if(_connectionStatus == ConnectivityResult.wifi && result == ConnectivityResult.mobile){
        wifiToMobile();
      }
      _connectionStatus = result;
    });
    switch(result) {
      case ConnectivityResult.wifi: networkTest();
      break;
      case ConnectivityResult.mobile: networkTest();
      break;
      case ConnectivityResult.none: networkOutage();
      break;
    }
  }
  
  /*******인터넷 속도 측정(임시)*****/
  void networkTest() async{
    var r = await fetchPost().timeout(const Duration(seconds: 2));
    if(r.statusCode != 200){
      networkDelay();
    }
  }

  Future<http.Response> fetchPost() {
    Uri url = Uri.parse('data를 받아오는곳');
    return http.get(url);
  }
/*********************************/
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title),),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Text('네트워크 상태 : ${_connectionStatus.toString()}'),
            ElevatedButton(onPressed: (){networkOutage();},
                child: const Text('네트워크 끊김')),
            ElevatedButton(onPressed: (){networkDelay();},
                child: const Text('네트워크 지연')),
            ElevatedButton(onPressed: (){mobileToWifi();},
                child: const Text('모바일 --> 와이파이')),
            ElevatedButton(onPressed: (){wifiToMobile();},
                child: const Text('와이파이 --> 모바일')),
          ],
        ),
      ),
    );
  }
  ///Alert
  void networkDelay() {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
          content: SizedBox(
            height: 200,
            width: 200,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              crossAxisAlignment: CrossAxisAlignment.center,
              children:  [
                const Text('네트워크 지연'),
                const Text('네트워크 환경이 불안정합니다.'),
                ElevatedButton(onPressed: ()=> Navigator.pop(context),
                    child: const Text('확인'))
              ],
            ),
          ),
        );
      },
    );
  }
  ///Alert
  void networkOutage() {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
          content: SizedBox(
            height: 200,
            width: 200,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              crossAxisAlignment: CrossAxisAlignment.center,
              children:  [
                const Text('네트워크 끊김'),
                const Text('네트워크를 찾을수 없습니다.'),
                ElevatedButton(onPressed: ()=> Navigator.pop(context),
                    child: const Text('확인'))
              ],
            ),
          ),
        );
      },
    );
  }

  void mobileToWifi() {
    ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(50))
          ),
          content:  Text('네트워크가 와이파이로 변경되었습니다.'),
          duration:  Duration(seconds: 3),
        )
    );
  }
  void wifiToMobile() {
    ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(50))
          ),
          content: Text('네트워크가 모바일 데이터로 변경되었습니다.'),
          duration: Duration(seconds: 3),
        )
    );
  }
}

 

https://github.com/Inhochoi0201/connectivity_test

 

GitHub - Inhochoi0201/connectivity_test

Contribute to Inhochoi0201/connectivity_test development by creating an account on GitHub.

github.com