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

这是我目前为止所做的:

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

上述方法行不通。


当前回答

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

尽管如此,我还是采用了abernee的代码,并对其进行了修改,使其更精简、更合理。我说的明智是指他在自己的功能中消耗了Connectivity包的功能,但在内部由于没有从这个包中返回最有价值的输出(即网络标识)而浪费了它。这是阿伯尼解决方案的修改版本:

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项目中获得这个非常基本的功能-但我想目前这是我们拥有的最好的。实际上,我更喜欢数据连接检查器包而不是连接包——但是(在发布这篇文章的时候)前者缺少我从连接包中需要的非常重要的网络识别功能。这就是我(暂时)默认采用这种方法的原因。

其他回答

使用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),
                  ),
                ],
              ),
            ),
          )

输出:

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

引用自文档:

请注意,在Android上,这并不保证连接到互联网。例如,应用程序可能有wifi接入,但它可能是一个VPN或酒店wifi,没有接入。

如果你真的需要检查www互联网的连接,更好的选择是

data_connection_checker包

我几乎读了所有的帖子,@dennmat的帖子对我最有用。虽然它对我没用,而且也过时了。我有更新颤振更新连接包(I。E connectivity_plus)和data_connection_checker(检查移动和wifi是否有实际的互联网连接)。 在这篇文章之后,你将能够连续监听互联网连接。

1. 添加依赖关系 A)连通性:^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();
  }

切换飞行模式时检查日志。你应该得到有true和false值的日志。

注意:这将无法在flutter web工作,如果你想让它工作,请使用dio或http插件而不是data_connection_checker。

项目示例可以在这里找到。谢谢

我发现仅仅使用连接包不足以判断互联网是否可用。在安卓系统中,它只会检查是否有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)部分对于移动连接和wifi连接都是一样的,可能应该移动到一个单独的函数。我在这里没有这样做是为了让它更易于阅读。

在@dennmatt的回答之后,我注意到InternetAddress。查找可能会返回成功的结果,即使互联网连接断开-我测试它从我的模拟器连接到我的家庭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是在async internet -check之前设置的,因此理论上,如果checkConnection()在短时间内被调用多次,那么在一行中可能有多个hasConnection=true或多个hasConnection=false。 我不确定@dennmatt是否故意这样做,但在我们的用例中没有副作用(setState只被调用两次,具有相同的值)。