ChatGPT解决这个技术问题 Extra ChatGPT

检查 Flutter 应用上是否有可用的 Internet 连接

我有一个要执行的网络调用。但在此之前,我需要检查设备是否具有互联网连接。

这是我到目前为止所做的:

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

以上方法无效。


A
Amani

connectivity 插件在其文档中声明它仅在存在网络连接时提供信息,但在网络连接到 Internet 时不提供信息

请注意,在 Android 上,这并不能保证连接到 Internet。例如,该应用程序可能具有 wifi 访问权限,但它可能是 VPN 或无法访问的酒店 WiFi。

您可以使用

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

我收到错误“isNotEmpty 未在 InternetAddress 中声明”
这可以在后台实现吗?就像我有一个任务队列等待执行并等待互联网但应用程序已关闭?
请注意,在中国境内无法访问 google.com,因此如果在中国使用该示例将会挂起。为了扩大您的受众,请避免使用 google.com 并改用 example.com。最终结果 = 等待 InternetAddress.lookup('example.com');
这对我不起作用 if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) 在有 wifi 但没有互联网连接时返回 true。
哦,是的,我完全忘记了这一点!实际上我认为我可以继续使用 await,我可以在 lookup() 之后附加 .timeout
d
dennmat

对于登陆这里的其他任何人,我想补充 Günter Zöchbauer 的回答,这是我实施实用程序以了解是否有互联网的解决方案,不管其他任何事情。

免责声明:

我对 Dart 和 Flutter 都是新手,所以这可能不是最好的方法,但很想得到反馈。

结合 flutter_connectivity 和 Günter Zöchbauer 的连接测试

我的要求

我不想在需要检查连接的任何地方都有一堆重复的代码,我希望它能够在发生更改时自动更新组件或其他任何关心连接的东西。

连接状态单例

首先我们设置一个单例。如果你不熟悉这种模式,网上有很多关于它们的好信息。但要点是您希望在应用程序生命周期中创建一个类的单个实例,并且能够在任何地方使用它。

这个单例连接到 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

在模拟器中切换飞行模式以查看结果


测试了代码,它对我有用,我需要更多信息来帮助。
啊,好的,我明白了。因此,再次供您将来参考,您发布的错误只是编辑器试图打开它认为发生错误的文件。真正的错误应该在您的编辑器调试控制台/堆栈跟踪面板中可用。所以我猜 runApp 返回我认为它会在整个程序生命周期中运行。鉴于这主要是 dispose 在这里并不是真正必要的,所以只需删除 connectionStatus.dispose() 假设您在上面的 main() 中设置它。将更新帖子并链接到 github 示例。
要检测是否正在切换 wifi 或蜂窝,您只需要颤振连接。此包装器在切换发生后检查连接。但不会提醒每一次网络变化。如果您使用的是模拟器,则切换飞行模式是断开互联网连接的最简单方法。如果您使用的是实际设备,则必须确保您尚未连接到具有数据的移动网络。
有几个选项,您可以修改上面的内容以使用 Timer 进行频繁测试。或者只是经常使用 Timer 实用程序进行测试。请参阅:api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html 另一种选择是在您发送每个请求之前测试连接。虽然看起来你可能正在寻找类似 websockets 的东西。总之祝你好运
我们不应该在小部件的 dispose() 函数中取消订阅吗?我看到这是在其他 StreamController 示例中完成的,例如:stackoverflow.com/questions/44788256/updating-data-in-flutter
C
CopsOnRoad

空安全代码:

一次检查:创建此方法:Future hasNetwork() async { try { final result = await InternetAddress.lookup('example.com'); return result.isNotEmpty && result[0].rawAddress.isNotEmpty; } on SocketException catch (_) { return false; } } 用法: bool isOnline = await hasNetwork();

设置监听器:将以下依赖项添加到您的 pubspec.yaml 文件中。连接性加号:^2.0.2 完整代码:void main() => runApp(MaterialApp(home: HomePage()));类 HomePage 扩展 StatefulWidget { @override _HomePageState createState() => _HomePageState(); } 类 _HomePageState 扩展 State { Map _source = {ConnectivityResult.none: false};最终 MyConnectivity _connectivity = MyConnectivity.instance; @override void initState() { super.initState(); _connectivity.initialise(); _connectivity.myStream.listen((source) { setState(() => _source = source); }); } @override 小部件构建(BuildContext 上下文){ 字符串字符串; switch (_source.keys.toList()[0]) { case ConnectivityResult.mobile: string = 'Mobile: Online';休息; case ConnectivityResult.wifi: string = 'WiFi: Online';休息; case ConnectivityResult.none: 默认值: string = 'Offline'; } 返回脚手架(主体:中心(子:文本(字符串)),); } @override void dispose() { _connectivity.disposeStream(); super.dispose(); } } 类 MyConnectivity { MyConnectivity._();静态最终_instance = MyConnectivity._();静态 MyConnectivity 获取实例 => _instance;最终 _connectivity = Connectivity(); final _controller = StreamController.broadcast();流获取 myStream => _controller.stream; void initialise() async { ConnectivityResult 结果 = await _connectivity.checkConnectivity(); _checkStatus(结果); _connectivity.onConnectivityChanged.listen((result) { _checkStatus(result); }); } void _checkStatus(ConnectivityResult 结果) async { bool isOnline = false;尝试 { 最终结果 = 等待 InternetAddress.lookup('example.com'); isOnline = result.isNotEmpty && 结果[0].rawAddress.isNotEmpty; } on SocketException catch (_) { isOnline = false; } _controller.sink.add({result: isOnline});无效 disposeStream() => _controller.close(); }

截屏:

https://i.stack.imgur.com/nVArc.gif

感谢:connectivity_plus 和 Günter Zöchbauer


通过firebase,SDK有可能吗?
@LOG_TAG 您不必为此使用 Firebase。
Map _source = {ConnectivityResult.none: false};为什么你在这里使用“假”
如果您总是遇到“无连接错误”,请添加“”_source.clear();在“setState(() => _source = source);”之前
我将此代码与流提供程序一起使用,但即使我断开 Wi-Fi,isOnline 也始终返回 true。
a
abernee

我发现仅使用 connectivity 包不足以判断互联网是否可用。在 Android 中,它只检查是否有 WIFI 或是否打开了移动数据,而不检查实际的互联网连接。在我的测试过程中,即使没有移动信号 ConnectivityResult.mobile 也会返回 true。

使用 IOS 时,我的测试发现连接插件在手机没有信号时可以正确检测是否有互联网连接,问题仅出在 Android 上。

我找到的解决方案是将 data_connection_checker 包与连接包一起使用。这只是通过向几个可靠地址发出请求来确保有 Internet 连接,检查的默认超时时间约为 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) 部分对于移动连接和 wifi 连接是相同的,可能应该移到单独的函数中。我在这里没有这样做以使其更具可读性。

这是我的第一个 Stack Overflow 答案,希望对某人有所帮助。


欢迎来到stackoverflow。只是想知道,首先使用 await DataConnectionChecker().hasConnection 有什么优势?
唯一的原因是,在 IOS 上,连接包可以立即告诉您没有连接。如果我只是使用 data_connection_checker 包,则 IOS 上的应用程序必须等到它发出的 http 请求超时,大约 10 秒,然后才能返回 false。不过,在某些情况下,这可能是可以接受的。连接包还可以判断您使用的是 WIFI 还是移动数据,我在这里不需要知道,但知道可能有用。
这在上面的代码中只需很少的语法修改就可以完美地工作。 1. 你需要将 Future 更改为 future ) ,因为类型是小写的。 2. 为最后的第四个返回语句添加分号 ( ; )。
感谢 TDM,我已经根据您的修改编辑了答案。
DataConnectionChecker 已弃用。使用 internet_connection_checker pub.dev/packages/internet_connection_checker
T
Tushar Pandey

使用

dependencies:
  connectivity: ^0.4.2

我们从 resouces 得到的是

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

实用程序类是

导入“包:连接/连接.dart”;类 NetworkCheck { Future check() async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.mobile) { return true; } else if (connectivityResult == ConnectivityResult.wifi) { return true; } 返回假; } 动态 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)

此软件包已弃用并由 Connectivity Plus 取代
k
kristiyan.mitev

我创建了一个包(我认为)可以可靠地处理这个问题。

The package on pub.dev

The package on 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;
}

甚至更简单...

案例二:


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

a
amorenew

我为小部件状态创建了一个基类

用法而不是 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;
  }

我怎样才能使用这个类?
@DolDurma 只需添加并导入它,然后代替 State 使用 BaseState 然后只需使用布尔变量 isOnline
使用此代码,我无法从 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 我不确定没有 GitHub 示例的问题是什么,因为这些信息还不够
请检查此 repo 并告诉我如何使用 is_online 登录控制台 github.com/MahdiPishguy/flutter-connectivity-sample
c
codingwithtashi

好吧,我几乎阅读了所有帖子,@dennmat 帖子对我最有用。虽然它对我不起作用,而且它也已经过时了。我已经更新了 Flutter 更新的 connectivity 包(即 connectivity_plus)和 data_connection_checker(检查移动设备和 wifi 是否有实际的互联网连接)。
在这篇文章之后,您将能够收听连续上网。

<强> 1。添加依赖项
a) connectivity_plus: ^1.0.6
b) data_connection_checker: ^0.3.4

2. 处理所有连接的自定义类。

import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:data_connection_checker/data_connection_checker.dart'; 

class ConnectionUtil {
  //This creates the single instance by calling the `_internal` constructor specified below
  static final ConnectionUtil _singleton = new ConnectionUtil._internal();
  ConnectionUtil._internal();
  //This is what's used to retrieve the instance through the app
  static ConnectionUtil getInstance() => _singleton;
  //This tracks the current connection status
  bool hasConnection = false;
  //This is how we'll allow subscribing to connection changes
  StreamController connectionChangeController = StreamController();
  //flutter_connectivity
  final Connectivity _connectivity = Connectivity();
  void initialize() {
    _connectivity.onConnectivityChanged.listen(_connectionChange);
  }
  //flutter_connectivity's listener
  void _connectionChange(ConnectivityResult result) {
    hasInternetInternetConnection();
  }
  Stream get connectionChange => connectionChangeController.stream;
  Future<bool> hasInternetInternetConnection() async {
    bool previousConnection = hasConnection;
    var connectivityResult = await (Connectivity().checkConnectivity());
    //Check if device is just connect with mobile network or wifi
    if (connectivityResult == ConnectivityResult.mobile ||
        connectivityResult == ConnectivityResult.wifi) {
      //Check there is actual internet connection with a mobile network or wifi
      if (await DataConnectionChecker().hasConnection) {
        // Network data detected & internet connection confirmed.
        hasConnection = true;
      } else {
        // Network data detected but no internet connection found.
        hasConnection = false;
      }
    }
    // device has no mobile network and wifi connection at all
    else {
      hasConnection = false;
    }
    // The connection status changed send out an update to all listeners
    if (previousConnection != hasConnection) {
      connectionChangeController.add(hasConnection);
    }
    return hasConnection;
  }
}

检查任何地方的连接并倾听变化。

@override
  initState() {
    print('called');
    //Create instance
    ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
    //Initialize
    connectionStatus.initialize();
    //Listen for connection change
    _connectionChangeStream = connectionStatus.connectionChange.listen((event) {
      print(event);
    });

    super.initState();
  }

现在在切换飞行模式时检查日志。你应该得到具有真假值的日志。

注意:这在 Flutter Web 中不起作用,如果您希望使用 diohttp 插件而不是 data_connection_checker 使其工作。

示例项目可在 here 中找到。谢谢


感谢您的努力。但是你能告诉我是否必须将这段代码放在每个 initState 中吗?如果是这样,我该如何做一些工作来使检查类似于对所有应用程序的全局检查。提前致谢。
显然这不是最好的方法,您可以使用一些状态管理工具,如 provider 或 bloc 来监听流并发出更改。
正确,这就是为什么我已经添加了connectivity_plus
data_connection_checker 已停产。使用 internet_connection_checker
O
Oren

在 @dennmatt 的 answer 之后,我注意到即使 Internet 连接关闭,InternetAddress.lookup 也可能返回成功的结果 - 我通过从模拟器连接到我的家庭 WiFi,然后断开路由器的电缆对其进行了测试。我认为原因是路由器缓存了域查找结果,因此它不必在每个查找请求上查询 DNS 服务器。

无论如何,如果您像我一样使用 Firestore,您可以将 try-SocketException-catch 块替换为空事务并捕获 TimeoutExceptions:

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

另外,请注意previousConnection设置在异步互联网检查之前,所以理论上如果在短时间内多次调用checkConnection(),可能会有多个hasConnection=true连续或连续多个hasConnection=false .我不确定@dennmatt 是否故意这样做,但在我们的用例中没有副作用(setState 仅以相同的值调用了两次)。


Q
Quentin

我对建议的解决方案有疑问,使用 lookup 并不总是返回预期值。

这是由于 DNS 缓存,调用的值被缓存,而不是在下一次尝试时执行正确的调用,它会返回缓存的值。当然这是一个问题,因为这意味着如果您失去连接并调用 lookup,它仍然可以返回缓存值,就像您有互联网一样,相反,如果您在 lookup 返回 null 后重新连接互联网,它仍然会返回缓存的持续时间为空,可能是几分钟,即使您现在有互联网。

TL;DR: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;
  }

_checkInternetAccess 的调用最多需要 timeout 的持续时间才能完成(此处为 3 秒),如果我们可以到达任何 DNS,它将在到达第一个 DNS 后立即完成,而无需等待其他 (因为达到一个就足以知道你有互联网)。对 _pingDns 的所有调用都是并行完成的。

它似乎在 IPV4 网络上运行良好,当我无法在 IPV6 网络上测试它时(我无权访问它),我认为它应该仍然可以工作。它也适用于发布模式构建,但我还必须将我的应用程序提交给 Apple 以查看他们是否发现此解决方案有任何问题。

它也应该适用于大多数国家(包括中国),如果它在一个国家/地区不起作用,您可以将 DNS 添加到可从您的目标国家/地区访问的列表中。


A
Andrew

连接性:包不保证实际的互联网连接(可能只是没有互联网访问的 wifi 连接)。

从文档中引用:

请注意,在 Android 上,这并不能保证连接到 Internet。例如,该应用程序可能具有 wifi 访问权限,但它可能是 VPN 或无法访问的酒店 WiFi。

如果您确实需要检查与 www 互联网的连接,那么更好的选择是

data_connection_checker package


同意。这就是为什么要结合 *Connectivity**Data Connection Checker* 包(如此处所述 -> stackoverflow.com/a/62063600/3002719) 是解决此问题的更好方法。
S
Sandeep Pareek

使用connectivity_widget:^0.1.7

添加依赖项:

dependencies:
     connectivity_widget: ^0.1.7

添加代码:

           ConnectivityWidget(
            builder: (context, isOnline) => Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    "${isOnline ? 'Connected' : 'Offline'}",
                    style: TextStyle(
                        fontSize: 30,
                        color: isOnline ? Colors.green : Colors.red),
                  ),
                ],
              ),
            ),
          )

输出:

https://i.stack.imgur.com/WOZoU.gif


这个包现在不支持空安全
T
Tirth Raj

这是我的解决方案它检查互联网连接以及数据连接希望你喜欢它。

dependencies:        
    data_connection_checker:
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"),
        ),
      ),
    );
  }
}

S
SilSur

我最终(虽然不情愿)选择了@abernee 在 previous answer 中针对这个问题给出的解决方案。我总是尝试在我的项目中使用尽可能少的外部包——因为我知道外部包是我创建的软件中唯一的 [潜在] 故障点。因此,为了像这样的简单实现而链接到 两个 外部包对我来说并不容易

尽管如此,我还是采用了 abernee 的代码并对其进行了修改,使其更精简、更合理。明智的意思是他在他的函数中消耗了 Connectivity package 的力量,但随后在内部浪费了它,因为没有从这个包中返回最有价值的输出(即网络标识)。所以这里是 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 项目中获得这个非常基本功能 - 但我想目前这是我们拥有的最好的。实际上,我更喜欢 Data Connection Checker 包而不是 Connectivity 包 - 但是(在发布此消息时)前者缺少我需要的 Connectivity 包中非常重要的网络识别功能。这就是我默认使用这种方法的原因[暂时]。


H
Hekmat

迟到的答案,但使用这个包来检查。包名: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);

M
Muhamad Haydar Jawad

我使用 data_connection_checker 包来检查互联网访问,即使 wifi 或移动设备可用连接,它也运行良好:这是检查连接的代码:

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

如果您想了解更多信息,请查看包裹。 Data Connection Checker Package


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

class InternetConnect extends StatefulWidget {
  @override
  InternetConnectState createState() => InternetConnectState();
}

class InternetConnectState extends State<InternetConnect> {
  ConnectivityResult previous;
  bool dialogshown = false;
  StreamSubscription connectivitySubscription;

  Future<bool> checkinternet() async {
    try {
      final result = await InternetAddress.lookup('google.com');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        return Future.value(true);
      }
    } on SocketException catch (_) {
      return Future.value(false);
    }
  }

  void checkInternetConnect(BuildContext context) {
    connectivitySubscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult connresult) {
      if (connresult == ConnectivityResult.none) {
        dialogshown = true;
        showDialog(
            context: context, barrierDismissible: false, child: alertDialog());
      } else if (previous == ConnectivityResult.none) {
        checkinternet().then((result) {
          if (result == true) {
            if (dialogshown == true) {
              dialogshown = false;
              Navigator.pop(context);
            }
          }
        });
      }

      previous = connresult;
    });
  }

  AlertDialog alertDialog() {
    return AlertDialog(
      title: Text('ERROR'),
      content: Text("No Internet Detected."),
      actions: <Widget>[
        FlatButton(
          // method to exit application programitacally

          onPressed: () {
            AppSettings.openWIFISettings();
          },
          child: Text("Settings"),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

    and you can use this method in init of any class

@override
void initState() {
  // TODO: implement initState
  InternetConnectState().checkInternetConnect(context);
  super.initState();
}

V
Verdy Bangkit

基于此答案https://stackoverflow.com/a/68436867/10761151

如果你使用 dart null 安全,你会得到一个错误,所以你可以更新依赖 data_connection_checker: ^0.3.4 到 internet_connection_checker: ^0.0.1+2

你可以使用这个代码

import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';

class ConnectionUtil {
  static final ConnectionUtil _singleton = new ConnectionUtil._internal();
  ConnectionUtil._internal();

  static ConnectionUtil getInstance() => _singleton;

  bool hasConnection = false;

  StreamController connectionChangeController = StreamController();

  final Connectivity _connectivity = Connectivity();
  void initialize() {
    _connectivity.onConnectivityChanged.listen(_connectionChange);
  }

  void _connectionChange(ConnectivityResult result) {
    _hasInternetInternetConnection();
  }

  Stream get connectionChange => connectionChangeController.stream;
  Future<bool> _hasInternetInternetConnection() async {
    bool previousConnection = hasConnection;
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi) {
      // this is the different
      if (await InternetConnectionChecker().hasConnection) {
        hasConnection = true;
      } else {
        hasConnection = false;
      }
    } else {
      hasConnection = false;
    }

    if (previousConnection != hasConnection) {
      connectionChangeController.add(hasConnection);
    }
    return hasConnection;
  }
}

在有状态的小部件上,您可以实现此代码

  bool hasInterNetConnection = false;

  @override
  initState() {
    ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
    connectionStatus.initialize();
    connectionStatus.connectionChange.listen(connectionChanged);

    super.initState();
  }

  void connectionChanged(dynamic hasConnection) {
    setState(() {
      hasInterNetConnection = hasConnection;
    });
  }

多次调用connectionChanged(=我调用initSate的次数,即每次调用有状态小部件时)。即使在我取消“处置”方法中的“流”后,也会发生这种情况。我该如何解决?
d
devDeejay

只是尝试使用 Flutter 中的 Connectivity 包来简化代码。

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 上的问题在于,仅仅因为您通过 wifi 或移动设备连接,并不意味着您已连接到互联网。
@Megadec 遗憾的是,这是唯一的问题 :(
D
David B.

我对接受的答案有一些问题,但它似乎解决了其他人的答案。我想要一个可以从它使用的 url 获得响应的解决方案,所以我认为 http 非常适合该功能,为此我发现这个答案非常有用。 How do I check Internet Connectivity using HTTP requests(Flutter/Dart)?


B
Brian Tompsett - 汤莱恩

对我来说,我只是在 Firebase 中创建一个数据并使用未来的构建器来等待数据。在这里,像这样,您可以检查连接是否太慢,以便加载数据:

FutureBuilder(
    future: _getImage(context),
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.none:
          return Text('Press button to start.');
        case ConnectionState.active:
        case ConnectionState.waiting:
          return Container(
              height:
                  MediaQuery.of(context).size.height / 1.25,
              width:
                  MediaQuery.of(context).size.width / 1.25,
              child: Loading());
        case ConnectionState.done:
          if (snapshot.hasData) {
            return snapshot.data;
          } else {
            return FlatButton(
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) =>
                            ProfilePage()));
              },
              child: Icon(
                Icons.add_a_photo,
                size: 50,
              ),
            );
          }
        // You can reach your snapshot.data['url'] in here
      }
      return null;
    },
  ),

P
Praveen G

您可以使用此软件包 https://pub.dev/packages/flutter_network_connectivity

在底层,它利用 Android 上的 NetworkCapabilities 和 iOS 上的 NetworkMonitor 并监听连接变化和 ping 以检查互联网可用性,您还可以配置为定期查找互联网可用性。

添加到您的 pubspec.yaml

flutter_network_connectivity: ^0.0.6

创建对象

FlutterNetworkConnectivity flutterNetworkConnectivity =
    FlutterNetworkConnectivity(
      isContinousLookUp: true,  // optional, false if you cont want continous lookup
      lookUpDuration: const Duration(seconds: 5),  // optional, to override default lookup duration
      lookUpUrl: 'example.com',  // optional, to override default lookup url
);

您可以使用它的方法连续检查网络连接或调用检查当前状态

_flutterNetworkConnectivity.getInternetAvailabilityStream().listen((isInternetAvailable) {
  // do something
});

并注册监听器

await _flutterNetworkConnectivity.registerAvailabilityListener();

检查通话状态

bool _isNetworkConnectedOnCall = await _flutterNetworkConnectivity.isInternetConnectionAvailable();

我认为值得一提的是,flutter_network_connectivity 不能用于 Flutter Web 开发。提到的库使用 dart:io,它不能在 web 构建的 Flutter 应用程序中使用。有关详细信息,请阅读以下 github 问题:github.com/thisisamir98/connection_status_bar/issues/3
N
Nagaraj Alagusundaram

我编写了一个包来检查活动的互联网连接并相应地显示一个小部件。

flutter_no_internet_widget

例子:

InternetWidget(
 online: Text('Online'),
 offline: Text('Offline),
);

根据网络状态,将显示相应的小部件。如果您有一个有效的互联网连接,将显示一个在线小部件。

所有重量级都由软件包完成,您所要做的就是提供在线和离线小部件。或者,您可以提供加载小部件和查找 URL。

欢迎讨论、PR 或建议。

https://i.stack.imgur.com/omwix.gif


Z
Zeeshan

最终 ConnectivityResult 结果 = 等待 Connectivity().checkConnectivity();

if (result == ConnectivityResult.wifi) {
  print('Connected to a Wi-Fi network');
} else if (result == ConnectivityResult.mobile) {
  print('Connected to a mobile network');
} else {
  print('Not connected to any network');
}

使用connectivity_plus包
正如目前所写的那样,您的答案尚不清楚。请edit添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以找到有关如何写出好答案的更多信息in the help center
M
Muhammad Shafique

连接插件在其文档中声明它仅在存在网络连接时提供信息,但在网络连接到 Internet 时不提供信息。使用下面的代码,不要忘记使用“.timeout()”,因为你可以使用“await”永远卡住。

import 'dart:io';

Future<bool> isConnected() async {
  try {
    List<InternetAddress> result = await InternetAddress.lookup('example.com')
        .timeout(Duration(seconds: 5));

    //
    if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
      return true;
    }
    //
    else {
      return false;
    }
  } on SocketException catch (_) {
    return false;
  }
}