Flutter 앱에서 사용 가능한 인터넷 연결이 있는지 확인


89

실행할 네트워크 호출이 있습니다. 하지만 그 전에 장치가 인터넷에 연결되어 있는지 확인해야합니다.

이것이 내가 지금까지 한 일입니다.

  var connectivityResult = new Connectivity().checkConnectivity();// User defined class
    if (connectivityResult == ConnectivityResult.mobile ||
        connectivityResult == ConnectivityResult.wifi) {*/
    this.getData();
    } else {
      neverSatisfied();
    }

위의 방법이 작동하지 않습니다.

답변:


174

연결 네트워크 연결이있는 경우,하지만 네트워크가 인터넷에 연결되어 있지 않은 경우에만 정보를 제공하는 자사의 문서에서 상태를 플러그인

Android에서는 인터넷 연결이 보장되지 않습니다. 예를 들어 앱은 Wi-Fi에 액세스 할 수 있지만 액세스 권한이없는 VPN 또는 호텔 Wi-Fi 일 수 있습니다.

당신이 사용할 수있는

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

2
내가 오류를 얻고있다 "isNotEmpty는 InternetAddress 내부에 선언되지 않았습니다"
Rissmon 수레 쉬

2
이것은 백그라운드에서 달성 될 수 있습니까? 실행 대기 중이고 인터넷을 기다리는 작업 대기열이 있지만 앱이 닫힌 것처럼?
Vidor Vistrom 2010 년

54
google.com은 중국 내에서 액세스 할 수 없으므로 중국에서 사용하는 경우 예제가 중단됩니다. 잠재 고객을 늘리려면 google.com을 사용하지 말고 대신 example.com을 사용하세요. 최종 결과 = await InternetAddress.lookup ( 'example.com');
otboss

4
이것은 if (result.isNotEmpty && result[0].rawAddress.isNotEmpty)Wi-Fi가 있지만 인터넷에 연결되지 않은 경우에는 작동하지 않습니다 .
Denn 2019-04-26

5
아, 네, 완전히 잊어 버렸습니다! 실제로 계속 사용할 수 있다고 생각 합니다. 다음에 await추가 할 수 있습니다 . .timeoutlookup()
Michel Feinstein

67

여기에 착륙하는 다른 사람에게는 Günter Zöchbauer의 답변에 추가하고 싶습니다. 이것은 인터넷이 있는지 여부를 알기 위해 유틸리티를 구현하는 내 솔루션이었습니다.

부인 성명:

저는 Dart와 Flutter를 처음 사용하므로 이것이 최선의 접근 방식은 아니지만 피드백을 받고 싶습니다.


flutter_connectivity와 Günter Zöchbauer의 연결 테스트 결합

내 요구 사항

연결을 확인해야하는 곳에서 반복되는 코드를 많이 갖고 싶지 않았고 변경 사항이있을 때마다 구성 요소 나 연결에 관심이있는 다른 항목을 자동으로 업데이트하기를 원했습니다.

ConnectionStatusSingleton

먼저 Singleton을 설정합니다. 이 패턴에 익숙하지 않은 경우 온라인에 많은 좋은 정보가 있습니다. 그러나 요점은 응용 프로그램 수명주기 동안 클래스의 단일 인스턴스를 만들고 어디서나 사용할 수 있다는 것입니다.

이 싱글 톤 flutter_connectivity은 연결 변경 사항에 연결하여 수신 한 다음 네트워크 연결을 테스트 한 다음를 사용하여 StreamController관심있는 모든 항목을 업데이트합니다.

다음과 같이 보입니다.

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;
    }
}

용법

초기화

먼저 싱글 톤의 초기화를 호출해야합니다. 하지만 한 번만. 이 부분은 당신에게 달려 있지만 내 앱에서 해냈습니다 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();   
}

에서 Widget또는 다른 곳에서

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) {
        ...
    }
}

다른 누군가가 유용하다고 생각하기를 바랍니다!


github 저장소의 예 : https://github.com/dennmat/flutter-connectiontest-example

결과를 보려면 에뮬레이터에서 비행기 모드를 전환하세요.


2
코드를 테스트했는데 도움이 될만한 정보가 더 필요합니다.
dennmat

3
아, 알겠습니다. 따라서 향후 참조를 위해 게시중인 오류는 오류가 발생했다고 생각하는 파일을 열려고하는 편집기 일뿐입니다. 실제 오류는 편집기 디버그 콘솔 / 스택 추적 패널에서 사용할 수 있습니다. 그래서 나는 runApp이 전체 프로그램 수명 동안 실행될 것이라고 가정했습니다. 이것이 주된 것처럼 여기에서는 dispose가 실제로 필요하지 않으므로 위와 같이 connectionStatus.dispose()설정한다고 가정 하여 제거하십시오 main(). 게시물을 업데이트하고 github 예제에 링크합니다.
dennmat

1
Wi-Fi 또는 셀룰러가 전환되고 있는지 감지하려면 Flutter 연결 만 필요합니다. 이 래퍼는 전환이 발생한 후 연결을 확인합니다. 그러나 모든 네트워크 변경 사항을 알리지는 않습니다. 에뮬레이터를 사용하는 경우 비행기 모드를 전환하는 것이 인터넷 연결을 끊는 가장 쉬운 방법입니다. 실제 장치를 사용하는 경우 데이터가있는 모바일 네트워크에 여전히 연결되어 있지 않은지 확인해야합니다.
dennmat

1
이에 대한 몇 가지 옵션이 있으며 위의 내용을 수정하여 타이머를 사용하여 자주 테스트 할 수 있습니다. 또는 타이머 유틸리티를 사용하여 자주 테스트하십시오. 참조 : api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html 또 다른 옵션은 요청을 보낼 때마다 연결을 테스트하는 것입니다. 웹 소켓과 같은 것을 찾고있는 것처럼 보이지만. 어쨌든 행운을 빕니다
dennmat

2
위젯의 dispose () 함수에서 구독을 취소해야하지 않나요? 이 작업은 다음과 같은 다른 StreamController 예제에서 수행됩니다. stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren

36

여기에 이미지 설명 입력

인터넷 연결 및 해당 소스의 청취자를 보여주는 전체 예제입니다.

신용 : 연결 및 Günter Zöchbauer

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 string;
    switch (_source.keys.toList()[0]) {
      case ConnectivityResult.none:
        string = "Offline";
        break;
      case ConnectivityResult.mobile:
        string = "Mobile: Online";
        break;
      case ConnectivityResult.wifi:
        string = "WiFi: Online";
    }

    return Scaffold(
      appBar: AppBar(title: Text("Internet")),
      body: Center(child: Text("$string", style: TextStyle(fontSize: 36))),
    );
  }

  @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();
}

firebase를 통해 SDK가 가능합니까?
LOG_TAG

@LOG_TAG Firebase를 사용할 필요는 없습니다.
CopsOnRoad

1
@CopsOnRoad 정말 감사합니다. 당신은 내 시간을 절약했습니다.
Nimisha Ranipa

맵 _source = {ConnectivityResult.none : false}; 여기에서 "false"를 사용한 이유
Faruk AYDIN

@CopsOnRoad 감사합니다! 이 방법을 사용했지만이 방법은 처음으로 NoInternetConnection을 제공합니다! 왜 먼저 나에게 없음을 주나요? 이것은 내 디버그 인쇄입니다 : connectivityResult.none connectivityResult.wifi connectivityResult.wifi.
Faruk AYDIN

19

사용

dependencies:
  connectivity: ^0.4.2

자원 에서 얻은 것은

      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;
      }

미래는 저에게 거의 문제가되지 않습니다. 우리는 매번 다음과 같이 구현해야합니다.

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

그래서이 문제를 해결하기 위해 나는 이와 같은 부울 isNetworkPresent 매개 변수로 함수를 받아들이는 클래스를 만들었습니다.

methodName(bool isNetworkPresent){}

그리고 유틸리티 클래스는

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);
  }
    });
  }
}

그리고 연결 확인 유틸리티를 사용하려면

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

이 구문을 사용하겠습니다

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

17

연결을 사용하는 것만으로도 패키지를 것만으로는 인터넷을 사용할 수 있는지 여부를 알 수 없습니다. Android에서는 WIFI가 있는지 또는 모바일 데이터가 켜져 있는지 만 확인하며 실제 인터넷 연결은 확인하지 않습니다. 테스트 중에 모바일 신호가 없어도 ConnectivityResult.mobile은 true를 반환합니다.

IOS를 사용하여 테스트에 따르면 전화에 신호가 없을 때 인터넷 연결이 있는지 연결 플러그인이 올바르게 감지하는 것으로 나타 났으며 문제는 Android에서만 발생했습니다.

내가 찾은 해결책 은 연결 패키지와 함께 data_connection_checker 패키지 를 사용하는 입니다. 이것은 몇 개의 신뢰할 수있는 주소를 요청하여 인터넷 연결이 있는지 확인합니다. 기본 검사 시간 제한은 약 10 초입니다.

내 완성 된 isInternet 기능은 다음과 같습니다.

  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;
    }
  }

if (await DataConnectionChecker().hasConnection)부분은 모바일 및 Wi-Fi 연결 모두에서 동일하며 별도의 기능으로 이동해야합니다. 더 읽기 쉽게하기 위해 여기에서 그렇게하지 않았습니다.

이것은 나의 첫 번째 Stack Overflow 답변입니다. 누군가에게 도움이되기를 바랍니다.


1
stackoverflow에 오신 것을 환영합니다. await DataConnectionChecker().hasConnection처음에 사용하는 것보다 장점이 무엇인지 궁금합니다 .
herbert

2
유일한 이유는 IOS에서 연결 패키지가 연결이 없다는 것을 거의 즉시 알 수 있기 때문입니다. data_connection_checker 패키지를 방금 사용한 경우 IOS의 앱은 false를 반환하기 전에 약 10 초 동안 HTTP 요청이 시간 초과 될 때까지 기다려야합니다. 그러나 이것은 어떤 경우에는 받아 들일 수 있습니다. 연결 패키지는 또한 내가 여기서 알 필요는 없지만 알아두면 유용 할 수있는 WIFI 또는 모바일 데이터를 사용 중인지 알 수 있습니다.
abernee

이것은 위의 코드에서 약간의 구문 수정으로 완벽하게 작동합니다. 1. 유형이 소문자이기 때문에 Future <Bool>을 future <bool>)로 변경해야합니다. 2. 네 번째 마지막 return 문에 세미콜론 (;)을 추가합니다.
TDM

감사합니다 TDM, 수정 사항으로 답변을 편집했습니다.
abernee

6

이 문제를 안정적으로 처리하는 패키지를 만들었습니다.

pub.dev의 패키지

GitHub의 패키지

토론은 매우 환영합니다. GitHub에서 문제 추적기를 사용할 수 있습니다.


나는 더 이상 이것이 신뢰할만한 방법이라고 생각하지 않습니다.


@ Oren 's 에 무언가를 추가하고 싶습니다. 대답 . 다른 모든 예외를 잡을 수있는 catch를 하나 더 추가해야합니다 (안전을 위해). 또는 예외 유형을 모두 제거하고 모든 예외를 처리하는 catch를 사용해야합니다.

사례 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;
}

또는 더 간단합니다 ...

사례 2 :


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

5

위젯 상태에 대한 기본 클래스를 만들었습니다.

대신 사용 State<LoginPage>사용 BaseState<LoginPage> 후 바로 부울 변수를 사용 isOnline

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

먼저 연결 플러그인을 추가합니다.

dependencies:
  connectivity: ^0.4.3+2

그런 다음 BaseState 클래스를 추가합니다.

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;
  }
}

그리고 다음과 같이 상태에서 위젯을 캐스팅해야합니다.

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

2
이 수업을 어떻게 사용할 수 있습니까?
DolDurma

@DolDurma 그냥 추가하고 가져온 다음 State <LoginPage> 대신 BaseState <LoginPage>를 사용하고 부울 변수 isOnline을 사용하십시오.
amorenew

이 코드로 나는에서 valiables를 얻을 수 없습니다 widget. 예를 들면 : RegisterBloc get _registerBloc => widget.registerBloc;나는이 오류를 얻을 error: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29):이 구현 참조class _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
DolDurma

이 정보가 충분하지 않기 때문에 @DolDurma 나는 문제가 GitHub의 샘플없이 확실하지 무슨 생각
amorenew

1
이 REPO을 확인하고 내가 사용하는 방법을 보여주세요 is_online콘솔에 로그인 할 수 github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma

3

@dennmatt의 답변InternetAddress.lookup따라 인터넷 연결이 꺼져 있어도 성공적인 결과를 반환 할 수 있음을 발견했습니다. 시뮬레이터에서 가정용 WiFi에 연결 한 다음 라우터의 케이블을 분리하여 테스트했습니다. 그 이유는 라우터가 도메인 조회 결과를 캐시하므로 조회 요청마다 DNS 서버를 쿼리 할 필요가 없기 때문이라고 생각합니다.

어쨌든 나와 같은 Firestore를 사용하는 경우 try-SocketException-catch 블록을 빈 트랜잭션으로 바꾸고 TimeoutExceptions를 catch 할 수 있습니다.

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;
}

또한 previousConnectionasync intenet-check 이전에 설정되어 있으므로 이론적 checkConnection()으로 짧은 시간에 여러 번 호출하면 hasConnection=true한 행에 여러 개가있을 수도 있고 여러 개가있을 수도 있습니다 hasConnection=false. @dennmatt가 의도적으로 수행했는지 여부는 확실하지 않지만 사용 사례에는 부작용이 없었습니다 ( setState같은 값으로 두 번만 호출되었습니다).


3

연결 : 패키지는 실제 인터넷 연결을 보장하지 않습니다 (인터넷 액세스없이 Wi-Fi 연결 일 수도 있음).

문서에서 인용 :

Android에서는 인터넷 연결이 보장되지 않습니다. 예를 들어 앱은 Wi-Fi에 액세스 할 수 있지만 액세스 권한이없는 VPN 또는 호텔 Wi-Fi 일 수 있습니다.

정말로 www 인터넷 연결을 확인해야한다면 더 나은 선택이 될 것입니다.

data_connection_checker 패키지


1

여기 내 솔루션이 있습니다. 인터넷 연결과 데이터 연결을 확인합니다.

먼저 pubsec.yaml에 종속성을 추가하십시오.
dependencies:        
    data_connection_checker:
그리고 여기에 내 솔루션의 main.dart가 있습니다.
import 'dart:async';

import 'package:data_connection_checker/data_connection_checker.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Data Connection Checker",
      home: HomePage(),
    );
  }
}

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

class _HomePageState extends State<HomePage> {
  StreamSubscription<DataConnectionStatus> listener;

  var Internetstatus = "Unknown";

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
//    _updateConnectionStatus();
      CheckInternet();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    listener.cancel();
    super.dispose();
  }

  CheckInternet() async {
    // Simple check to see if we have internet
    print("The statement 'this machine is connected to the Internet' is: ");
    print(await DataConnectionChecker().hasConnection);
    // returns a bool

    // We can also get an enum instead of a bool
    print("Current status: ${await DataConnectionChecker().connectionStatus}");
    // prints either DataConnectionStatus.connected
    // or DataConnectionStatus.disconnected

    // This returns the last results from the last call
    // to either hasConnection or connectionStatus
    print("Last results: ${DataConnectionChecker().lastTryResults}");

    // actively listen for status updates
    listener = DataConnectionChecker().onStatusChange.listen((status) {
      switch (status) {
        case DataConnectionStatus.connected:
          Internetstatus="Connectd TO THe Internet";
          print('Data connection is available.');
          setState(() {

          });
          break;
        case DataConnectionStatus.disconnected:
          Internetstatus="No Data Connection";
          print('You are disconnected from the internet.');
          setState(() {

          });
          break;
      }
    });

    // close listener after 30 seconds, so the program doesn't run forever
//    await Future.delayed(Duration(seconds: 30));
//    await listener.cancel();
    return await await DataConnectionChecker().connectionStatus;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Data Connection Checker"),
      ),
      body: Container(
        child: Center(
          child: Text("$Internetstatus"),
        ),
      ),
    );
  }
}

1

제안 된 솔루션에 문제가 있었는데 사용 lookup이 항상 예상 값을 반환하지는 않습니다.

이것은 DNS 캐싱으로 인한 것이며, 호출 값이 캐시되고 다음 시도에서 적절한 호출을 수행하도록 지시되어 캐시 된 값을 돌려줍니다. 물론 이것은 연결이 끊어지고 호출 lookup하면 인터넷이있는 것처럼 캐시 된 값을 반환 할 수 있으므로 여기서 문제가됩니다. 반대로 lookupnull 을 반환 한 후 인터넷을 다시 연결 하면 계속해서 null을 반환합니다. 지금 인터넷에 연결되어 있어도 몇 분 정도 걸릴 수 있습니다.

요약 : lookup무언가를 반환한다고해서 반드시 인터넷이 있다는 의미는 아니며 아무것도 반환하지 않는다고해서 반드시 인터넷이 없다는 의미는 아닙니다. 신뢰할 수 없습니다.

data_connection_checker플러그인 에서 영감을 얻어 다음 솔루션을 구현했습니다 .

 /// If any of the pings returns true then you have internet (for sure). If none do, you probably don't.
  Future<bool> _checkInternetAccess() {
    /// We use a mix of IPV4 and IPV6 here in case some networks only accept one of the types.
    /// Only tested with an IPV4 only network so far (I don't have access to an IPV6 network).
    final List<InternetAddress> dnss = [
      InternetAddress('8.8.8.8', type: InternetAddressType.IPv4), // Google
      InternetAddress('2001:4860:4860::8888', type: InternetAddressType.IPv6), // Google
      InternetAddress('1.1.1.1', type: InternetAddressType.IPv4), // CloudFlare
      InternetAddress('2606:4700:4700::1111', type: InternetAddressType.IPv6), // CloudFlare
      InternetAddress('208.67.222.222', type: InternetAddressType.IPv4), // OpenDNS
      InternetAddress('2620:0:ccc::2', type: InternetAddressType.IPv6), // OpenDNS
      InternetAddress('180.76.76.76', type: InternetAddressType.IPv4), // Baidu
      InternetAddress('2400:da00::6666', type: InternetAddressType.IPv6), // Baidu
    ];

    final Completer<bool> completer = Completer<bool>();

    int callsReturned = 0;
    void onCallReturned(bool isAlive) {
      if (completer.isCompleted) return;

      if (isAlive) {
        completer.complete(true);
      } else {
        callsReturned++;
        if (callsReturned >= dnss.length) {
          completer.complete(false);
        }
      }
    }

    dnss.forEach((dns) => _pingDns(dns).then(onCallReturned));

    return completer.future;
  }

  Future<bool> _pingDns(InternetAddress dnsAddress) async {
    const int dnsPort = 53;
    const Duration timeout = Duration(seconds: 3);

    Socket socket;
    try {
      socket = await Socket.connect(dnsAddress, dnsPort, timeout: timeout);
      socket?.destroy();
      return true;
    } on SocketException {
      socket?.destroy();
    }
    return false;
  }

에 대한 호출 _checkInternetAccesstimeout완료 하는 데 최대 시간 (여기서는 3 초) 이 걸리며 , DNS에 도달 할 수있는 경우 다른 DNS를 기다리지 않고 첫 번째 DNS에 도달하자마자 완료됩니다 (하나에 도달하면 인터넷이 있다는 것을 알고 있습니다). 에 대한 모든 호출 _pingDns은 병렬로 수행됩니다.

IPV4 네트워크에서 잘 작동하는 것 같고 IPV6 네트워크에서 테스트 할 수없는 경우 (액세스 권한이 없음) 여전히 작동해야한다고 생각합니다. 릴리스 모드 빌드에서도 작동하지만이 솔루션에서 문제가 있는지 확인하려면 아직 내 앱을 Apple에 제출해야합니다.

또한 대부분의 국가 (중국 포함)에서도 작동합니다. 하나에서 작동하지 않는 경우 대상 국가에서 액세스 할 수있는 목록에 DNS를 추가 할 수 있습니다.


1

나는 궁극적으로 ( 마지하더라도 ) 이 질문 에 대한 이전 답변 에서 @abernee가 제공 한 솔루션에 정착했습니다 . 나는 항상 내 프로젝트에서 가능한 한 적은 수의 외부 패키지를 사용하려고 시도하고 사용합니다. 외부 패키지가 내가 만든 소프트웨어에서 유일한 [잠재적 인] 실패 지점이라는 것을 알고 있기 때문입니다. 따라서 이와 같은 간단한 구현을 위해 두 개의 외부 패키지 에 연결하는 것은 쉽지 않았습니다 .

그럼에도 불구하고 나는 abernee의 코드를 가져 와서 더 간결하고 더 합리적으로 만들도록 수정했습니다. 합리적이라는 것은 그가 자신의 기능에서 Connectivity 패키지 의 힘을 소비 하지만이 패키지에서 가장 가치있는 출력 (예 : 네트워크 식별)을 반환하지 않음으로써 내부적으로 낭비한다는 것을 의미합니다. 따라서 다음은 abernee 솔루션의 수정 된 버전입니다.

import 'package:connectivity/connectivity.dart';
import 'package:data_connection_checker/data_connection_checker.dart';


// 'McGyver' - the ultimate cool guy (the best helper class any app can ask for).
class McGyver {

  static Future<Map<String, dynamic>> checkInternetAccess() async {
    //* ////////////////////////////////////////////////////////////////////////////////////////// *//
    //*   INFO: ONLY TWO return TYPES for Map 'dynamic' value => <bool> and <ConnectivityResult>   *//
    //* ////////////////////////////////////////////////////////////////////////////////////////// *//
    Map<String, dynamic> mapCon;
    final String isConn = 'isConnected', netType = 'networkType';
    ConnectivityResult conRes = await (Connectivity().checkConnectivity());
    switch (conRes) {
      case ConnectivityResult.wifi:   //* WiFi Network: true !!
        if (await DataConnectionChecker().hasConnection) {   //* Internet Access: true !!
          mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.wifi});
        } else {
          mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.wifi});
        }
        break;
      case ConnectivityResult.mobile:   //* Mobile Network: true !!
        if (await DataConnectionChecker().hasConnection) {   //* Internet Access: true !!
          mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.mobile});
        } else {
          mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.mobile});
        }
        break;
      case ConnectivityResult.none:   //* No Network: true !!
        mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.none});
        break;
    }
    return mapCon;
  }

}

그런 다음 다음과 같이 코드 어디에서나 간단한 호출을 통해이 정적 함수를 사용합니다.

bool isConn; ConnectivityResult netType;
McGyver.checkInternetAccess().then(
  (mapCIA) {  //* 'mapCIA' == amalgamation for 'map' from 'CheckInternetAccess' function result.
    debugPrint("'mapCIA' Keys: ${mapCIA.keys}");
    isConn = mapCIA['isConnected'];
    netType = mapCIA['networkType'];
  }
);
debugPrint("Internet Access: $isConn   |   Network Type: $netType");

Flutter 프로젝트 에서이 매우 기본적인 기능 을 얻기 위해 두 개의 외부 패키지 에 연결해야하는 것은 유감입니다. 하지만 지금은 이것이 우리가 가진 최고라고 생각합니다. 나는 실제로 선호하는 데이터 연결 검사기 오버 패키지를 연결 패키지 -하지만 (이 게시시) 이전은 매우 중요 실종 된 네트워크 식별 기능 나는 연결 패키지에서 필요로하는합니다. 이것이 제가이 접근 방식을 기본적으로 사용하는 이유입니다.


0

Flutter에서 Connectivity Package를 사용하여 코드를 단순화하려고합니다 .

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.
} else {
  // I am not connected to the internet
}

Android에서 이와 관련된 문제는 Wi-Fi 또는 모바일을 통해 연결되어 있다고해서 인터넷에 연결되어 있다는 것을 의미하지는 않습니다.
Megadec

1
@Megadec 슬프게도 네 그게 유일한 문제입니다 :(
devDeejay

0

늦은 답변이지만이 패키지를 사용하여 확인하십시오. 패키지 이름 : data_connection_checker

pubspec.yuml 파일에서 :

dependencies:
    data_connection_checker: ^0.3.4

connection.dart라는 파일 또는 원하는 이름을 만듭니다. 패키지 가져 오기 :

import 'package:data_connection_checker/data_connection_checker.dart';

인터넷 연결이 있는지 확인하십시오.

print(await DataConnectionChecker().hasConnection);

0

Wi-Fi 또는 모바일로 연결이 가능하더라도 인터넷 액세스를 확인하기 위해 data_connection_checker 패키지를 사용했습니다. 잘 작동합니다. 연결을 확인하는 코드는 다음과 같습니다.

bool result = await DataConnectionChecker().hasConnection;
if(result == true) {
   print('YAY! Free cute dog pics!');
} else {
   print('No internet :( Reason:');
   print(DataConnectionChecker().lastTryResults);
}

더 많은 정보를 원한다면 패키지 위로 향하십시오. 데이터 연결 검사기 패키지


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.