Kiểm tra xem có kết nối Internet trên ứng dụng Flutter không


91

Tôi có một cuộc gọi mạng cần được thực hiện. Nhưng trước khi làm điều đó tôi cần kiểm tra xem thiết bị có kết nối internet hay không.

Đây là những gì tôi đã làm cho đến nay:

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

Phương pháp trên không hoạt động.

Câu trả lời:


176

Các kết nối cắm bang trong tài liệu của mình rằng nó chỉ cung cấp thông tin nếu có một kết nối mạng, nhưng không phải nếu mạng được kết nối với Internet

Lưu ý rằng trên Android, điều này không đảm bảo kết nối với Internet. Ví dụ: ứng dụng có thể có truy cập Wi-Fi nhưng có thể là VPN hoặc Wi-Fi khách sạn không có quyền truy cập.

Bạn có thể dùng

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
Tôi gặp lỗi "isNotEmpty không được khai báo bên trong InternetAddress"
Rissmon Suresh

2
Điều này có thể đạt được trong nền không? Giống như tôi có một hàng đợi các nhiệm vụ đang chờ thực thi và đang chờ kết nối Internet nhưng ứng dụng bị đóng?
Vidor Vistrom

54
Xin lưu ý rằng google.com không thể truy cập bên trong ở Trung Quốc và như vậy ví dụ sẽ bị treo nếu được sử dụng ở Trung Quốc. Để mở rộng đối tượng của bạn, vui lòng tránh sử dụng google.com và thay vào đó hãy sử dụng example.com. kết quả cuối cùng = await InternetAddress.lookup ('example.com');
otboss

4
Điều này không hoạt động đối với tôi, if (result.isNotEmpty && result[0].rawAddress.isNotEmpty)trả về true khi có wifi nhưng không có kết nối internet.
Denn

5
Ồ, vâng, tôi hoàn toàn quên mất điều này! Trên thực tế, tôi nghĩ rằng tôi có thể tiếp tục sử dụng await, tôi chỉ cần nối thêm .timeoutsau lookup().
Michel Feinstein

67

Đối với bất kỳ ai khác đặt chân đến đây, tôi muốn thêm vào câu trả lời của Günter Zöchbauer, đây là giải pháp của tôi để triển khai một tiện ích để biết liệu có internet hay không bất kể thứ gì khác.

Tuyên bố từ chối trách nhiệm:

Tôi mới sử dụng cả Dart và Flutter nên đây có thể không phải là cách tiếp cận tốt nhất, nhưng rất muốn nhận được phản hồi.


Kết hợp flut_connectivity và thử nghiệm kết nối của Günter Zöchbauer

Yêu cầu của tôi

Tôi không muốn có một loạt mã lặp lại ở bất kỳ đâu tôi cần để kiểm tra kết nối và tôi muốn nó tự động cập nhật các thành phần hoặc bất kỳ thứ gì khác quan tâm đến kết nối bất cứ khi nào có thay đổi.

ConnectionStatusSingleton

Đầu tiên, chúng tôi thiết lập một Singleton. Nếu bạn không quen với mô hình này, có rất nhiều thông tin trực tuyến về chúng. Nhưng ý chính là bạn muốn tạo một thể hiện duy nhất của một lớp trong vòng đời ứng dụng và có thể sử dụng nó ở bất cứ đâu.

Singleton này kết nối flutter_connectivityvà lắng nghe các thay đổi kết nối, sau đó kiểm tra kết nối mạng, sau đó sử dụng a StreamControllerđể cập nhật bất kỳ thứ gì quan tâm.

Nó trông như thế này:

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

Sử dụng

Khởi tạo

Đầu tiên, chúng ta phải đảm bảo rằng chúng ta gọi khởi tạo singleton của chúng ta. Nhưng chỉ một lần. Điều này phụ thuộc vào bạn nhưng tôi đã làm điều đó trong ứng dụng của mình 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();   
}

Widgethoặc nơi khác

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

Hy vọng ai đó khác thấy điều này hữu ích!


Ví dụ về repo github: https://github.com/dennmat/flutter-connectiontest-example

Chuyển đổi chế độ máy bay trong trình giả lập để xem kết quả


2
Đã kiểm tra mã và nó hoạt động với tôi. Tôi cần thêm thông tin để trợ giúp.
dennmat 21/1218

3
Ahh, ok, tôi hiểu rồi. Vì vậy, một lần nữa để bạn tham khảo trong tương lai, lỗi bạn đang đăng chỉ là người chỉnh sửa cố gắng mở tệp mà nó cho rằng lỗi đã xảy ra. Lỗi thực sự sẽ có sẵn trong bảng điều khiển gỡ lỗi trình chỉnh sửa / bảng điều khiển theo dõi ngăn xếp của bạn. Vì vậy, tôi đoán runApp trả về Tôi cho rằng nó sẽ chạy trong toàn bộ vòng đời của chương trình. Vì đây là phần chính nên việc loại bỏ không thực sự cần thiết ở đây vì vậy chỉ cần loại bỏ connectionStatus.dispose()giả sử bạn đang thiết lập nó theo cách main()tương tự ở trên. Sẽ cập nhật bài đăng và liên kết đến ví dụ github.
dennmat 21/1218

1
Để chỉ phát hiện xem wifi hoặc mạng di động đang được chuyển đổi, bạn chỉ cần kết nối rung. Trình bao bọc này kiểm tra kết nối sau khi chuyển đổi xảy ra. Nhưng sẽ không cảnh báo mọi thay đổi mạng. Nếu bạn đang sử dụng trình giả lập, bật chế độ máy bay là cách dễ nhất để mất kết nối Internet. Nếu bạn đang sử dụng thiết bị thực, bạn phải đảm bảo rằng bạn vẫn chưa được kết nối với mạng di động có dữ liệu.
dennmat 21/1218

1
Có một số tùy chọn cho điều đó, bạn có thể sửa đổi các tùy chọn trên để sử dụng Bộ hẹn giờ để kiểm tra thường xuyên. Hoặc chỉ cần kiểm tra thường xuyên bằng tiện ích Hẹn giờ. Xem: api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html Một tùy chọn khác là kiểm tra kết nối trước mọi yêu cầu bạn gửi. Mặc dù có vẻ như bạn đang tìm kiếm thứ gì đó giống như websockets. Dù sao thì chúc may mắn
dennmat 29/12/18

2
Chúng ta có nên hủy đăng ký trong hàm dispose () của widget không? Tôi thấy điều này được thực hiện trong các ví dụ StreamController khác như ở đây: stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren

36

nhập mô tả hình ảnh ở đây

Ví dụ đầy đủ thể hiện người nghe về kết nối internet và nguồn của nó.

Tín dụng cho: kết nối và 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();
}

thông qua firebase, SDK có được không?
LOG_TAG

@LOG_TAG Bạn không cần phải sử dụng Firebase cho việc này.
CopsOnRoad,

1
@CopsOnRoad Cảm ơn bạn rất nhiều. bạn đã tiết kiệm thời gian của tôi.
Nimisha Ranipa

Bản đồ _source = {ConnectivityResult.none: false}; Tại sao bạn sử dụng "false" ở đây
Faruk AYDIN

@CopsOnRoad Cảm ơn bạn! Tôi đã sử dụng phương pháp này, Nhưng phương pháp này mang lại cho tôi lần đầu tiên NoInternetConnection! Tại sao đầu tiên cho tôi Không? Đây là bản in gỡ lỗi của tôi: connectResult.none connectResult.wifi connectionResult.wifi.
Faruk AYDIN

19

Sử dụng

dependencies:
  connectivity: ^0.4.2

những gì chúng tôi nhận được từ các nguồn cung cấp

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

Tương lai là một vấn đề nhỏ đối với tôi, chúng tôi phải thực hiện nó mỗi lần như:

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

Vì vậy, để giải quyết vấn đề này, tôi đã tạo một lớp chấp nhận một hàm với tham số boolean isNetworkPresent như thế này

methodName(bool isNetworkPresent){}

Và Lớp Tiện ích là

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

Và để sử dụng tính năng sử dụng kiểm tra kết nối

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

tôi sẽ sử dụng cú pháp này

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

17

Tôi thấy rằng chỉ sử dụng gói kết nối là không đủ để biết Internet có khả dụng hay không. Trong Android, nó chỉ kiểm tra xem có WIFI hoặc dữ liệu di động được bật hay không, nó không kiểm tra kết nối internet thực sự. Trong quá trình thử nghiệm của tôi, ngay cả khi không có tín hiệu di động ConnectivityResult.mobile vẫn trả về true.

Với iOS, thử nghiệm của tôi cho thấy plugin kết nối có phát hiện chính xác nếu có kết nối internet khi điện thoại không có tín hiệu hay không, vấn đề chỉ xảy ra với Android.

Giải pháp tôi tìm thấy là sử dụng gói data_connection_checker cùng với gói kết nối. Điều này chỉ đảm bảo rằng có kết nối internet bằng cách thực hiện yêu cầu đến một vài địa chỉ đáng tin cậy, thời gian chờ mặc định cho việc kiểm tra là khoảng 10 giây.

Hàm isInternet đã hoàn thành của tôi trông giống như sau:

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

Phần if (await DataConnectionChecker().hasConnection)này giống nhau cho cả kết nối di động và wifi và có lẽ nên được chuyển sang một chức năng riêng biệt. Tôi đã không làm điều đó ở đây để để nó dễ đọc hơn.

Đây là câu trả lời Stack Overflow đầu tiên của tôi, hy vọng nó sẽ giúp ích cho ai đó.


1
Chào mừng bạn đến với stackoverflow. Chỉ tự hỏi, lợi thế hơn là chỉ sử dụng await DataConnectionChecker().hasConnectionở nơi đầu tiên?
herbert

2
Lý do duy nhất là trên IOS, gói kết nối có thể cho biết khá nhiều ngay lập tức rằng không có kết nối. Nếu tôi chỉ sử dụng gói data_connection_checker, ứng dụng trên IOS sẽ phải đợi cho đến khi yêu cầu http mà nó đưa ra hết thời gian chờ, khoảng 10 giây, trước khi trả về false. Tuy nhiên, điều này có thể được chấp nhận trong một số trường hợp. Gói kết nối cũng có thể cho biết bạn đang sử dụng WIFI hay dữ liệu di động mà tôi không cần biết ở đây nhưng có thể hữu ích khi biết.
abernee

Điều này hoạt động hoàn hảo với một vài sửa đổi cú pháp trong đoạn mã trên. 1. bạn cần thay đổi Future <Bool> thành future <bool>), vì các kiểu là chữ thường. 2. Thêm dấu chấm phẩy (;) cho câu lệnh trả về cuối cùng thứ 4.
TDM

Cảm ơn TDM, tôi đã chỉnh sửa câu trả lời với các sửa đổi của bạn.
abernee

6

Tôi đã tạo một gói (tôi nghĩ) giải quyết vấn đề này một cách đáng tin cậy.

Gói trên pub.dev

Gói trên GitHub

Thảo luận rất được hoan nghênh. Bạn có thể sử dụng trình theo dõi sự cố trên GitHub.


Tôi không còn nghĩ rằng đây là một phương pháp đáng tin cậy:


Muốn thêm thứ gì đó vào câu trả lời của @ Oren : bạn thực sự nên thêm một lần bắt nữa, sẽ bắt được tất cả các ngoại lệ khác (chỉ để an toàn), HOẶC chỉ cần loại bỏ hoàn toàn loại ngoại lệ và sử dụng một hàm bắt, xử lý tất cả các ngoại lệ:

Trường hợp 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;
}

hoặc thậm chí đơn giản hơn ...

Trường hợp 2:


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

5

Tôi đã tạo một lớp cơ sở cho trạng thái tiện ích con

Cách sử dụng thay vì State<LoginPage>sử dụng BaseState<LoginPage> thì chỉ cần sử dụng biến boolean isOnline

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

Đầu tiên, hãy thêm plugin kết nối:

dependencies:
  connectivity: ^0.4.3+2

Sau đó thêm lớp 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;
  }
}

Và bạn cần truyền tiện ích con ở trạng thái của bạn như thế này

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

2
làm thế nào tôi có thể sử dụng lớp học này?
DolDurma

@DolDurma Chỉ cần thêm nó và nhập nó sau đó thay vì Nhà nước <LoginPage> sử dụng BaseState <LoginPage> sau đó chỉ cần sử dụng biến isOnline boolean
amorenew

với mã này, tôi không thể lấy được vali từ widget. ví dụ: RegisterBloc get _registerBloc => widget.registerBloc;tôi gặp lỗi error: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29)này, hãy xem sự class _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
tương xứng

@DolDurma Tôi không chắc chắn những gì vấn đề này mà không có một mẫu GitHub vì thông tin này là không đủ
amorenew

1
vui lòng kiểm tra repo này và chỉ cho tôi cách tôi có thể sử dụng is_onlineđể đăng nhập vào bảng điều khiển github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma

3

Theo câu trả lời của @dennmatt , tôi nhận thấy điều đó InternetAddress.lookupcó thể trả về kết quả thành công ngay cả khi kết nối Internet bị tắt - Tôi đã kiểm tra bằng cách kết nối từ trình mô phỏng với WiFi tại nhà của mình, sau đó ngắt kết nối cáp của bộ định tuyến. Tôi nghĩ lý do là bộ định tuyến lưu vào bộ nhớ cache các kết quả tra cứu miền để nó không phải truy vấn máy chủ DNS trên mỗi yêu cầu tra cứu.

Dù sao, nếu bạn sử dụng Firestore như tôi, bạn có thể thay thế khối try-SocketException-catch bằng một giao dịch trống và bắt 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;
}

Ngoài ra, xin lưu ý rằng điều đó previousConnectionđược đặt trước kiểm tra intenet không đồng bộ, vì vậy về mặt lý thuyết nếu checkConnection()được gọi nhiều lần trong một thời gian ngắn, có thể có nhiều hasConnection=truetrong một hàng hoặc nhiều hasConnection=falsetrong một hàng. Tôi không chắc liệu @dennmatt có cố ý hay không, nhưng trong trường hợp sử dụng của chúng tôi, không có tác dụng phụ nào ( setStatechỉ được gọi hai lần với cùng một giá trị).


3

Khả năng kết nối: gói không đảm bảo kết nối internet thực tế (có thể chỉ là kết nối wifi mà không cần truy cập internet).

Trích dẫn từ tài liệu:

Lưu ý rằng trên Android, điều này không đảm bảo kết nối với Internet. Ví dụ: ứng dụng có thể có truy cập Wi-Fi nhưng có thể là VPN hoặc Wi-Fi khách sạn không có quyền truy cập.

Nếu bạn thực sự cần kiểm tra kết nối với Internet www, lựa chọn tốt hơn sẽ là

gói data_connection_checker


1

Đây là giải pháp của tôi Nó kiểm tra kết nối Internet cũng như kết nối dữ liệu, tôi hy vọng bạn thích nó.

Trước hết, hãy thêm các phụ thuộc vào pubsec.yaml của bạn
dependencies:        
    data_connection_checker:
And Here Is The main.dart Of My Solution
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

Tôi gặp vấn đề với các giải pháp được đề xuất, việc sử dụng lookupkhông phải lúc nào cũng trả lại giá trị mong đợi.

Điều này là do bộ nhớ đệm DNS, giá trị của cuộc gọi được lưu vào bộ nhớ cache và nếu thực hiện một cuộc gọi thích hợp vào lần thử tiếp theo, nó sẽ trả lại giá trị được lưu trong bộ nhớ cache. Tất nhiên đây là một vấn đề ở đây vì nó có nghĩa là nếu bạn mất kết nối và gọi lookupnó vẫn có thể trả về giá trị được lưu trong bộ nhớ cache như khi bạn có internet và ngược lại, nếu bạn kết nối lại internet sau khi lookuptrả về null, nó sẽ vẫn trả về null trong khoảng thời gian bộ nhớ cache, có thể mất vài phút, ngay cả khi bạn có Internet ngay bây giờ.

TL; DR: lookuptrả lại một thứ gì đó không nhất thiết có nghĩa là bạn có internet và nó không trả lại bất cứ thứ gì không nhất thiết có nghĩa là bạn không có internet. Nó không đáng tin cậy.

Tôi đã triển khai giải pháp sau bằng cách lấy cảm hứng từ data_connection_checkerplugin:

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

Lệnh gọi _checkInternetAccesscần tối đa một khoảng thời gian timeoutđể hoàn thành (ở đây là 3 giây) và nếu chúng tôi có thể truy cập bất kỳ DNS nào, nó sẽ hoàn tất ngay sau khi đạt đến DNS đầu tiên, mà không cần đợi những DNS khác (vì chỉ cần đạt được một DNS là đủ biết bạn có internet). Tất cả các cuộc gọi đến _pingDnsđược thực hiện song song.

Nó có vẻ hoạt động tốt trên mạng IPV4 và khi tôi không thể kiểm tra nó trên mạng IPV6 (tôi không có quyền truy cập vào mạng này), tôi nghĩ nó vẫn sẽ hoạt động. Nó cũng hoạt động trên các bản dựng chế độ phát hành, nhưng tôi vẫn phải gửi ứng dụng của mình cho Apple để xem họ có tìm thấy bất kỳ vấn đề nào với giải pháp này hay không.

Nó cũng sẽ hoạt động ở hầu hết các quốc gia (bao gồm cả Trung Quốc), nếu nó không hoạt động ở một quốc gia, bạn có thể thêm DNS vào danh sách có thể truy cập từ quốc gia mục tiêu của bạn.


1

Cuối cùng ( mặc dù miễn cưỡng ) tôi đã giải quyết được giải pháp do @abernee đưa ra trong câu trả lời trước đây cho câu hỏi này. Tôi luôn cố gắng và sử dụng càng ít gói bên ngoài trong các dự án của mình càng tốt - vì tôi biết các gói bên ngoài là điểm [tiềm ẩn] thất bại duy nhất trong phần mềm tôi tạo. Vì vậy, để liên kết đến HAI gói bên ngoài chỉ để thực hiện đơn giản như thế này là không dễ dàng đối với tôi .

Tuy nhiên, tôi đã lấy mã của abernee và sửa đổi nó để làm cho nó gọn gàng và hợp lý hơn. Bằng cách hợp lý, tôi có nghĩa là anh ta tiêu thụ sức mạnh của gói Kết nối trong chức năng của mình nhưng sau đó lãng phí nó bên trong bằng cách không trả lại các đầu ra có giá trị nhất từ ​​gói này (tức là nhận dạng mạng). Vì vậy, đây là phiên bản sửa đổi của giải pháp 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;
  }

}

Sau đó, bạn sẽ sử dụng hàm tĩnh này thông qua một cuộc gọi đơn giản từ bất kỳ đâu trong mã của bạn như sau:

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

Thật tiếc khi bạn phải liên kết với HAI GÓI BÊN NGOÀI để có được chức năng rất cơ bản này trong dự án Flutter của bạn - nhưng tôi đoán hiện tại đây là chức năng tốt nhất mà chúng tôi có. Tôi thực sự thích gói Trình kiểm tra kết nối dữ liệu hơn gói Kết nối - nhưng (tại thời điểm đăng bài này) trước đây đã thiếu tính năng nhận dạng mạng rất quan trọng mà tôi yêu cầu từ gói Kết nối. Đây là lý do tôi mặc định sử dụng phương pháp này [tạm thời].


0

Chỉ đang cố gắng đơn giản hóa mã bằng Gói kết nối trong Flutter.

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
}

Tuy nhiên, vấn đề với điều này trên Android là chỉ vì bạn được kết nối qua wifi hoặc điện thoại di động, điều đó không có nghĩa là bạn đã kết nối với internet.
Megadec

1
@Megadec thật đáng buồn, đó là vấn đề duy nhất :(
devDeejay

0

trả lời muộn, nhưng hãy sử dụng gói này để kiểm tra. Tên gói: data_connection_checker

trong tệp pubspec.yuml của bạn:

dependencies:
    data_connection_checker: ^0.3.4

tạo một tệp có tên là connection.dart hoặc bất kỳ tên nào bạn muốn. nhập gói:

import 'package:data_connection_checker/data_connection_checker.dart';

kiểm tra xem có kết nối internet hay không:

print(await DataConnectionChecker().hasConnection);

0

Tôi đã sử dụng gói data_connection_checker để kiểm tra truy cập internet ngay cả khi kết nối có sẵn bằng wifi hoặc di động, nó hoạt động tốt: đây là mã để kiểm tra kết nối:

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

xem qua gói nếu bạn muốn biết thêm thông tin. Gói kiểm tra kết nối dữ liệu


0

Tôi gặp một số vấn đề với câu trả lời được chấp nhận, nhưng có vẻ như nó giải quyết được câu trả lời cho những người khác. Tôi muốn một giải pháp có thể nhận được phản hồi từ url mà nó sử dụng, vì vậy tôi nghĩ http sẽ rất tốt cho chức năng đó và vì điều đó, tôi thấy câu trả lời này thực sự hữu ích. Làm cách nào để kiểm tra Kết nối Internet bằng các yêu cầu HTTP (Flutter / Dart)?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.