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


89

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

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

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

上面的方法不起作用。

Answers:


175

连接插件的状态在其文档是否有网络连接,但不是如果网络连接到互联网,它仅提供信息

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

您可以使用

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 Suresh '18

2
可以在后台实现吗?就像我有等待执行和等待互联网的任务队列,但应用程序已关闭?
Vidor Vistrom

54
请注意,在中国内部无法访问google.com,因此如果在中国使用该示例,该示例将挂起。为了扩大您的受众群体,请避免使用google.com,而改用example.com。最终结果=等待InternetAddress.lookup('example.com');
otboss

4
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty)当没有wifi但没有互联网连接时,这对我不起作用返回true。
Denn

5
哦,是的,我完全忘记了!实际上我认为我可以继续使用await,我可以在.timeout之后追加lookup()
Michel Feinstein

67

对于在此居住的其他人,我想补充一下GünterZöchbauer的答案,这是我的解决方案,用于实施实用程序,以了解是否有互联网,无论是否有其他互联网。

免责声明:

我对Dart和Flutter都是陌生的,所以这可能不是最好的方法,但是希望获得反馈。


将flutter_connectivity与GünterZöchbauer的连接测试相结合

我的要求

我不想在需要检查连接的任何地方重复使用一堆重复的代码,而是希望它在发生更改时自动更新组件或其他任何关心连接的内容。

ConnectionStatusSingleton

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

这个单例挂接到flutter_connectivity并侦听连接更改,然后测试网络连接,然后使用aStreamController更新所有需要的内容。

看起来像这样:

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 '18

3
嗯,好的,我明白了。因此,再次供您参考,您所发布的错误只是编辑器尝试在认为错误发生的位置打开文件。真正的错误应该在编辑器的调试控制台/堆栈跟踪面板中可用。所以我想我认为runApp返回会在整个程序生命周期内运行。认为这实际上是主要的处理,因此在这里不需要connectionStatus.dispose()设置,因此只需删除即可(假设您已在main()上面进行设置)。将更新帖子并链接到github示例。
dennmat '18

1
要仅检测wifi或蜂窝电话正在切换,您只需要抖动连接即可​​。发生切换后,此包装器将检查连接。但是不会提醒每个网络更改。如果您使用的是模拟器,则切换飞行模式是失去互联网连接的最简单方法。如果您使用的是实际设备,则必须确保您仍未使用数据连接到移动网络。
dennmat '18

1
有几个选项,您可以修改以上内容以使用Timer进行频繁测试。或者只是使用Timer实用程序进行频繁测试。请参阅:api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html另一个选择是在发送每个请求之前测试连接。虽然看起来您可能正在寻找类似websockets的东西。无论如何,祝你好运
dennmat

2
我们不应该在小部件的dispose()函数中取消订阅吗?我看到这是在其他StreamController示例中完成的,例如:stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren

36

在此处输入图片说明

完整的示例演示了Internet连接及其来源的侦听器。

归功于:连接性和GünterZö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 '19

@LOG_TAG您不必为此使用Firebase。
CopsOnRoad

1
@CopsOnRoad非常感谢。你节省了我的时间。
Nimisha Ranipa

地图_source = {ConnectivityResult.none: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
    });

因此,要解决此问题,我创建了一个类,该类接受带有boolean 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软件包与连接软件包一起使用。这只是通过向一些可靠的地址发出请求来确保存在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答案,希望对您有所帮助。


1
欢迎使用stackoverflow。只是想知道,与仅使用一头相比有什么优势await DataConnectionChecker().hasConnection
Herbert

2
唯一的原因是,在IOS上,连接软件包可以立即告知没有连接。如果我只是使用data_connection_checker包,则IOS上的应用程序必须等待,直到发出的HTTP请求超时(大约10秒),然后返回false。在某些情况下,这可能是可以接受的。连通性包还可以告诉您您是否正在使用WIFI或移动数据,在这里我不需要知道这些信息,但可能会很有用。
abernee

这与上面的代码中很少的语法修改完美地结合在一起。1.您需要将Future <Bool>更改为future <bool>),因为类型是小写。2.在最后的第四个return语句中添加分号(;)。
TDM

感谢TDM,我已经通过您的修改对答案进行了编辑。
abernee

6

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

pub.dev上的包

GitHub上的软件包

讨论非常受欢迎。您可以在GitHub上使用问题跟踪器。


我不再认为以下是可靠的方法:


想要在@Oren的答案中添加一些内容:您确实应该再添加一个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只需添加并导入它,然后使用StateState <LoginPage>代替State <LoginPage>,然后使用布尔变量
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,

@DolDurma我不确定没有GitHub示例会导致什么问题,因为此信息还不够
amorenew

1
请检查此仓库,并告诉我如何使用is_online控制台 github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma,

3

按照@dennmatt的回答,我注意到InternetAddress.lookup即使关闭了Internet连接,它也可能会返回成功的结果-我通过从模拟器连接到家庭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是在异步intenet-check之前设置的,因此从理论上讲,如果checkConnection()在短时间内被多次调用,则可能会hasConnection=true连续出现多个或连续出现多个hasConnection=false。我不确定@dennmatt是否故意这样做,但是在我们的用例中没有副作用(setState仅以相同的值被调用两次)。


3

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

从文档中引用:

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

如果您确实需要检查与www Internet的连接,则更好的选择是

data_connection_checker软件包


1

这是我的解决方案,它检查Internet连接以及数据连接,我希望您喜欢它。

首先在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它仍可以像使用互联网一样返回缓存的值,反之,如果您在lookup返回null后重新连接互联网,则在访问期间仍将返回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时立即完成,而无需等待其他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项目中获得此非常基本的功能-但我想现在这是我们拥有的最好的功能。我实际上更喜欢Data Connection Checker软件包而不是Connectivity软件包-但是(在发布此消息时)前者缺少我需要Connectivity软件包中非常重要的网络识别功能。这就是我[默认]默认使用此方法的原因。


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上的问题在于,仅因为您是通过wifi或移动设备进行连接,并不意味着您已连接到互联网。
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

我使用了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);
}

如果需要更多信息,请直接查看包装。 数据连接检查程序包


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.