ตรวจสอบว่ามีการเชื่อมต่ออินเทอร์เน็ตบนแอพ Flutter หรือไม่


99

ฉันมีสายเครือข่ายที่จะดำเนินการ แต่ก่อนจะทำเช่นนั้นฉันต้องตรวจสอบว่าอุปกรณ์มีการเชื่อมต่ออินเทอร์เน็ตหรือไม่

นี่คือสิ่งที่ฉันได้ทำไปแล้ว:

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

วิธีการข้างต้นไม่ทำงาน

คำตอบ:


193

เชื่อมต่อปลั๊กอินรัฐที่อยู่ในเอกสารของมันว่ามันเพียง แต่ให้ข้อมูลหากมีการเชื่อมต่อเครือข่าย แต่ไม่ถ้าเครือข่ายที่เชื่อมต่อกับอินเทอร์เน็ต

โปรดทราบว่าใน Android สิ่งนี้ไม่รับประกันการเชื่อมต่ออินเทอร์เน็ต ตัวอย่างเช่นแอปอาจมีการเข้าถึง 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

2
สามารถทำได้ในพื้นหลังหรือไม่? เหมือนฉันมีคิวงานที่รอดำเนินการและรออินเทอร์เน็ต แต่แอปปิดอยู่?
Vidor Vistrom

60
โปรดทราบว่า google.com ไม่สามารถเข้าถึงได้ภายในประเทศจีนและด้วยเหตุนี้ตัวอย่างจะหยุดทำงานหากใช้ในประเทศจีน ในการขยายผู้ชมของคุณโปรดหลีกเลี่ยงการใช้ google.com และใช้ example.com แทน ผลลัพธ์สุดท้าย = รอ InternetAddress.lookup ('example.com');
otboss

4
สิ่งนี้ไม่ได้ผลสำหรับฉันif (result.isNotEmpty && result[0].rawAddress.isNotEmpty)ส่งคืนจริงเมื่อมี wifi แต่ไม่มีการเชื่อมต่ออินเทอร์เน็ต
เดน

5
โอ้ใช่ฉันลืมเรื่องนี้ไปแล้ว! อันที่จริงผมคิดว่าผมสามารถใช้awaitผมก็สามารถผนวกหลังจาก.timeout lookup()
Michel Feinstein

73

สำหรับใครก็ตามที่มาที่นี่ฉันต้องการเพิ่มคำตอบของGünterZöchbauerนี่คือทางออกของฉันในการใช้ยูทิลิตี้เพื่อให้ทราบว่ามีอินเทอร์เน็ตหรือไม่โดยไม่คำนึงถึงสิ่งอื่นใด

คำเตือน:

ฉันยังใหม่กับทั้ง Dart และ Flutter ดังนั้นนี่อาจไม่ใช่แนวทางที่ดีที่สุด แต่ก็ยินดีที่จะรับคำติชม


การรวม flutter_connectivity และการทดสอบการเชื่อมต่อของGünterZöchbauer

ความต้องการของฉัน

ฉันไม่ต้องการมีรหัสซ้ำ ๆ กันทุกที่ที่ฉันต้องการเพื่อตรวจสอบการเชื่อมต่อและฉันต้องการให้มันอัปเดตส่วนประกอบโดยอัตโนมัติหรือสิ่งอื่นใดที่เกี่ยวข้องกับการเชื่อมต่อเมื่อใดก็ตามที่มีการเปลี่ยนแปลง

ConnectionStatusSingleton

ก่อนอื่นเราตั้งค่า Singleton หากคุณไม่คุ้นเคยกับรูปแบบนี้มีข้อมูลดีๆมากมายเกี่ยวกับรูปแบบออนไลน์ แต่สาระสำคัญคือคุณต้องการสร้างอินสแตนซ์ของคลาสเดียวระหว่างวงจรชีวิตของแอปพลิเคชันและสามารถใช้งานได้ทุกที่

ซิงเกิลตันนี้flutter_connectivityเชื่อมต่อและรับฟังการเปลี่ยนแปลงการเชื่อมต่อจากนั้นทดสอบการเชื่อมต่อเครือข่ายจากนั้นใช้StreamControllerเพื่ออัปเดตสิ่งที่ต้องกังวล

ดูเหมือนว่า:

import 'dart:io'; //InternetAddress utility
import 'dart:async'; //For StreamController/Stream

import 'package:connectivity/connectivity.dart';

class ConnectionStatusSingleton {
    //This creates the single instance by calling the `_internal` constructor specified below
    static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
    ConnectionStatusSingleton._internal();

    //This is what's used to retrieve the instance through the app
    static ConnectionStatusSingleton getInstance() => _singleton;

    //This tracks the current connection status
    bool hasConnection = false;

    //This is how we'll allow subscribing to connection changes
    StreamController connectionChangeController = new StreamController.broadcast();

    //flutter_connectivity
    final Connectivity _connectivity = Connectivity();

    //Hook into flutter_connectivity's Stream to listen for changes
    //And check the connection status out of the gate
    void initialize() {
        _connectivity.onConnectivityChanged.listen(_connectionChange);
        checkConnection();
    }

    Stream get connectionChange => connectionChangeController.stream;

    //A clean up method to close our StreamController
    //   Because this is meant to exist through the entire application life cycle this isn't
    //   really an issue
    void dispose() {
        connectionChangeController.close();
    }

    //flutter_connectivity's listener
    void _connectionChange(ConnectivityResult result) {
        checkConnection();
    }

    //The test to actually see if there is a connection
    Future<bool> checkConnection() async {
        bool previousConnection = hasConnection;

        try {
            final result = await InternetAddress.lookup('google.com');
            if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
                hasConnection = true;
            } else {
                hasConnection = false;
            }
        } on SocketException catch(_) {
            hasConnection = false;
        }

        //The connection status changed send out an update to all listeners
        if (previousConnection != hasConnection) {
            connectionChangeController.add(hasConnection);
        }

        return hasConnection;
    }
}

การใช้งาน

การเริ่มต้น

ก่อนอื่นเราต้องแน่ใจว่าเราเรียกการเริ่มต้นของซิงเกิลตันของเรา แต่เพียงครั้งเดียว. ส่วนนี้ขึ้นอยู่กับคุณ แต่ฉันทำในแอปของฉันmain():

void main() {
    ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
    connectionStatus.initialize();

    runApp(MyApp());

    //Call this if initialization is occuring in a scope that will end during app lifecycle
    //connectionStatus.dispose();   
}

ในWidgetหรือที่อื่น ๆ

import 'dart:async'; //For StreamSubscription

...

class MyWidgetState extends State<MyWidget> {
    StreamSubscription _connectionChangeStream;

    bool isOffline = false;

    @override
    initState() {
        super.initState();

        ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
        _connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
    }

    void connectionChanged(dynamic hasConnection) {
        setState(() {
            isOffline = !hasConnection;
        });
    }

    @override
    Widget build(BuildContext ctxt) {
        ...
    }
}

หวังว่าคนอื่นจะพบว่ามีประโยชน์!


ตัวอย่าง github repo: https://github.com/dennmat/flutter-connectiontest-example

สลับโหมดเครื่องบินในโปรแกรมจำลองเพื่อดูผลลัพธ์


2
ทดสอบรหัสแล้วและใช้งานได้สำหรับฉันฉันต้องการข้อมูลเพิ่มเติมเพื่อช่วย
dennmat

3
โอเคฉันเห็นมัน อีกครั้งสำหรับการอ้างอิงในอนาคตของคุณข้อผิดพลาดที่คุณกำลังโพสต์เป็นเพียงตัวแก้ไขที่พยายามเปิดไฟล์ที่คิดว่าเกิดข้อผิดพลาด ข้อผิดพลาดที่แท้จริงควรมีอยู่ในแผงการดีบักคอนโซล / stack trace ของบรรณาธิการ ดังนั้นฉันเดาว่า runApp กลับมาฉันคิดว่ามันจะทำงานตลอดอายุของโปรแกรม เมื่อเห็นว่านี่เป็นหลักการกำจัดไม่จำเป็นจริงๆที่นี่ดังนั้นเพียงแค่ลบconnectionStatus.dispose()สมมติว่าคุณกำลังตั้งค่าดังกล่าวmain()ข้างต้น จะอัปเดตโพสต์และลิงก์ไปยังตัวอย่าง github
dennmat

1
หากต้องการตรวจสอบว่ามีการเปลี่ยน wifi หรือเซลลูลาร์หรือไม่คุณต้องใช้การเชื่อมต่อที่กระพือปีกเท่านั้น เสื้อคลุมนี้ตรวจสอบการเชื่อมต่อหลังจากสวิตช์เกิดขึ้น แต่จะไม่แจ้งเตือนทุกการเปลี่ยนแปลงเครือข่าย หากคุณกำลังใช้โปรแกรมจำลองการสลับโหมดเครื่องบินเป็นวิธีที่ง่ายที่สุดในการขาดการเชื่อมต่ออินเทอร์เน็ต หากคุณใช้อุปกรณ์จริงคุณต้องตรวจสอบให้แน่ใจว่าคุณยังไม่ได้เชื่อมต่อกับเครือข่ายมือถือที่มีข้อมูล
dennmat

1
มีตัวเลือกไม่กี่ตัวคุณสามารถแก้ไขด้านบนเพื่อใช้ Timer เพื่อทดสอบบ่อยๆ หรือเพียงทดสอบบ่อยๆโดยใช้ยูทิลิตี้ Timer โปรดดู: api.dartlang.org/stable/2.1.0/dart-async/Timer-class.htmlอีกทางเลือกหนึ่งคือการทดสอบการเชื่อมต่อก่อนทุกครั้งที่คุณส่งคำขอ แม้ว่าคุณอาจกำลังมองหาบางอย่างเช่น websockets ยังไงก็ขอให้โชคดี
dennmat

3
เราไม่ควรยกเลิกการสมัครสมาชิกในฟังก์ชัน dispose () ของวิดเจ็ตหรือไม่? ฉันเห็นว่าสิ่งนี้ทำได้ในตัวอย่าง StreamController อื่น ๆ เช่นที่นี่: stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren

41

ป้อนคำอธิบายภาพที่นี่

ตัวอย่างเต็มแสดงให้เห็นถึงการเชื่อมต่ออินเทอร์เน็ตและแหล่งที่มาของผู้ฟัง

เครดิต: การเชื่อมต่อและ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

@LOG_TAG คุณไม่จำเป็นต้องใช้ Firebase สำหรับสิ่งนี้
CopsOnRoad

1
@CopsOnRoad ขอบคุณมากมาย คุณประหยัดเวลาของฉัน
Nimisha Ranipa

แผนที่ _source = {ConnectivityResult.none: false}; ทำไมคุณถึงใช้ "เท็จ" ที่นี่
Faruk AYDIN

@CopsOnRoad ขอบคุณ! ฉันใช้วิธีนี้ แต่วิธีนี้ทำให้ฉัน NoInternetConnection เป็นครั้งแรก! ทำไมต้องให้ฉันครั้งแรกไม่มี? นี่คือการพิมพ์แก้จุดบกพร่องของฉัน: connectivityResult.none connectivityResult.wifi connectivityResult.wifi
Faruk AYDIN

23

ฉันพบว่าเพียงแค่ใช้การเชื่อมต่อแพ็คเกจไม่เพียงพอที่จะบอกได้ว่าอินเทอร์เน็ตใช้งานได้หรือไม่ ใน Android จะตรวจสอบว่ามี WIFI หรือไม่หรือเปิดข้อมูลมือถือไว้ แต่จะไม่ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตจริง ในระหว่างการทดสอบของฉันแม้ว่าจะไม่มีสัญญาณมือถือ ConnectivityResult.mobile จะส่งคืนจริง

ด้วย 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 และอาจจะถูกย้ายไปยังฟังก์ชั่นที่แยกต่างหาก ฉันไม่ได้ทำที่นี่เพื่อให้อ่านได้มากขึ้น

นี่เป็นคำตอบ Stack Overflow แรกของฉันหวังว่าจะช่วยใครบางคนได้


1
ยินดีต้อนรับสู่ stackoverflow แค่สงสัยว่าแค่ใช้await DataConnectionChecker().hasConnectionตอนแรกมีประโยชน์อะไร?
herbert

2
เหตุผลเดียวก็คือใน IOS แพ็คเกจการเชื่อมต่อสามารถบอกได้ทันทีว่าไม่มีการเชื่อมต่อ หากฉันเพิ่งใช้แพ็คเกจ data_connection_checker แอปบน IOS จะต้องรอจนกว่าคำขอ http จะหมดเวลาประมาณ 10 วินาทีก่อนที่จะส่งคืนเท็จ ซึ่งอาจยอมรับได้ในบางกรณี แพ็คเกจการเชื่อมต่อยังสามารถบอกได้ว่าคุณกำลังใช้ WIFI หรือข้อมูลมือถือซึ่งฉันไม่จำเป็นต้องรู้ที่นี่ แต่อาจมีประโยชน์ที่จะรู้
abernee

สิ่งนี้ใช้ได้อย่างสมบูรณ์กับการปรับเปลี่ยนไวยากรณ์เล็กน้อยในโค้ดด้านบน 1. คุณต้องเปลี่ยนอนาคต <Bool> เป็น <bool> ในอนาคต) เนื่องจากประเภทเป็นตัวพิมพ์เล็ก 2. เพิ่มเครื่องหมายอัฒภาค (;) สำหรับคำสั่งส่งคืนสุดท้ายที่ 4
TDM

ขอบคุณ TDM ฉันได้แก้ไขคำตอบด้วยการปรับเปลี่ยนของคุณแล้ว
abernee

20

การใช้

dependencies:
  connectivity: ^0.4.2

สิ่งที่เราได้รับจากทรัพยากรคือ

      import 'package:connectivity/connectivity.dart';

      Future<bool> check() async {
        var connectivityResult = await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.mobile) {
          return true;
        } else if (connectivityResult == ConnectivityResult.wifi) {
          return true;
        }
        return false;
      }

อนาคตเป็นปัญหาเล็กน้อยสำหรับฉันเราต้องดำเนินการทุกครั้งเช่น:

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

ดังนั้นเพื่อแก้ปัญหานี้ฉันได้สร้างคลาสซึ่งยอมรับฟังก์ชันที่มีพารามิเตอร์บูลีน isNetworkPresent เช่นนี้

methodName(bool isNetworkPresent){}

และยูทิลิตี้คลาสคือ

import 'package:connectivity/connectivity.dart';

class NetworkCheck {
  Future<bool> check() async {
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile) {
      return true;
    } else if (connectivityResult == ConnectivityResult.wifi) {
      return true;
    }
    return false;
  }

  dynamic checkInternet(Function func) {
    check().then((intenet) {
      if (intenet != null && intenet) {
        func(true);
      }
      else{
    func(false);
  }
    });
  }
}

และใช้ยูทิลิตี้ตรวจสอบการเชื่อมต่อ

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

ฉันจะใช้ไวยากรณ์นี้

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

6

ฉันได้สร้างแพ็คเกจที่ (คิดว่า) เกี่ยวข้องกับปัญหานี้อย่างน่าเชื่อถือ

แพ็คเกจบน pub.dev

แพ็คเกจบน GitHub

เจ้าตัวยินดีมาก คุณสามารถใช้ตัวติดตามปัญหาบน GitHub


ฉันไม่คิดว่าด้านล่างนี้เป็นวิธีที่เชื่อถือได้อีกต่อไป:


ต้องการเพิ่มบางอย่างในคำตอบของ @ Oren : คุณควรเพิ่มการจับอีกหนึ่งรายการซึ่งจะจับข้อยกเว้นอื่น ๆ ทั้งหมด (เพื่อความปลอดภัย) หรือเพียงแค่ลบประเภทข้อยกเว้นทั้งหมดและใช้การจับที่เกี่ยวข้องกับข้อยกเว้นทั้งหมด:

กรณีที่ 1:

try {
  await Firestore.instance
    .runTransaction((Transaction tx) {})
    .timeout(Duration(seconds: 5));
  hasConnection = true;
} on PlatformException catch(_) { // May be thrown on Airplane mode
  hasConnection = false;
} on TimeoutException catch(_) {
  hasConnection = false;
} catch (_) {
  hasConnection = false;
}

หรือง่ายกว่า ...

กรณีที่ 2:


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

5

ฉันสร้างคลาสพื้นฐานสำหรับสถานะวิดเจ็ต

การใช้งานแทนการState<LoginPage>ใช้งานBaseState<LoginPage> จากนั้นใช้ตัวแปรบูลีน isOnline

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

ขั้นแรกให้เพิ่มปลั๊กอินการเชื่อมต่อ:

dependencies:
  connectivity: ^0.4.3+2

จากนั้นเพิ่มคลาส BaseState

import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';

import 'package:connectivity/connectivity.dart';
import 'package:flutter/widgets.dart';

/// a base class for any statful widget for checking internet connectivity
abstract class BaseState<T extends StatefulWidget> extends State {

  void castStatefulWidget();

  final Connectivity _connectivity = Connectivity();

  StreamSubscription<ConnectivityResult> _connectivitySubscription;

  /// the internet connectivity status
  bool isOnline = true;

  /// initialize connectivity checking
  /// Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initConnectivity() async {
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print(e.toString());
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) {
      return;
    }

    await _updateConnectionStatus().then((bool isConnected) => setState(() {
          isOnline = isConnected;
        }));
  }

  @override
  void initState() {
    super.initState();
    initConnectivity();
    _connectivitySubscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult result) async {
      await _updateConnectionStatus().then((bool isConnected) => setState(() {
            isOnline = isConnected;
          }));
    });
  }

  @override
  void dispose() {
    _connectivitySubscription.cancel();
    super.dispose();
  }

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

และคุณต้องแคสต์วิดเจ็ตในสถานะของคุณเช่นนี้

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

2
ฉันจะใช้คลาสนี้ได้อย่างไร
DolDurma

@DolDurma เพียงแค่เพิ่มและนำเข้าจากนั้นแทน State <LoginPage> ใช้ BaseState <LoginPage> จากนั้นใช้ตัวแปรบูลีน isOnline
amorenew

ด้วยรหัสนี้ฉันไม่สามารถรับค่าตอบแทนwidgetได้ ตัวอย่างเช่นRegisterBloc get _registerBloc => widget.registerBloc;ฉันได้รับข้อผิดพลาดนี้เมื่อerror: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29)เห็นการดำเนินการนี้:class _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
DolDurma

@DolDurma ฉันไม่แน่ใจว่าเกิดปัญหาอะไรหากไม่มีตัวอย่าง GitHub เพราะข้อมูลนี้ไม่เพียงพอ
amorenew

1
โปรดตรวจสอบ repo นี้และแสดงวิธีใช้is_onlineเพื่อเข้าสู่ระบบคอนโซล github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma

3

ตามคำตอบของ @dennmatt ฉันสังเกตเห็นว่าInternetAddress.lookupอาจส่งคืนผลลัพธ์ที่ประสบความสำเร็จแม้ว่าการเชื่อมต่ออินเทอร์เน็ตจะปิดอยู่ - ฉันทดสอบโดยเชื่อมต่อจากเครื่องจำลองไปยัง WiFi ที่บ้านของฉันจากนั้นถอดสายเราเตอร์ของฉันออก ฉันคิดว่าเหตุผลก็คือเราเตอร์แคชผลลัพธ์การค้นหาโดเมนดังนั้นจึงไม่จำเป็นต้องค้นหาเซิร์ฟเวอร์ DNS ในคำขอค้นหาแต่ละครั้ง

อย่างไรก็ตามถ้าคุณใช้ Firestore เหมือนฉันคุณสามารถแทนที่บล็อก try-SocketException-catch ด้วยธุรกรรมที่ว่างเปล่าและรับ TimeoutExceptions:

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 แบบ async ดังนั้นในทางทฤษฎีหากcheckConnection()มีการเรียกหลายครั้งในช่วงเวลาสั้น ๆ อาจมีหลายรายการhasConnection=trueในแถวหรือหลายรายการhasConnection=falseในแถว ฉันไม่แน่ใจว่า @dennmatt ทำตามวัตถุประสงค์หรือไม่ แต่ในกรณีการใช้งานของเราไม่มีผลข้างเคียงใด ๆ ( setStateถูกเรียกเพียงสองครั้งด้วยค่าเดียวกัน)


3

การเชื่อมต่อ: แพ็คเกจไม่รับประกันการเชื่อมต่ออินเทอร์เน็ตจริง (อาจเป็นเพียงการเชื่อมต่อ wifi โดยไม่ต้องเชื่อมต่ออินเทอร์เน็ต)

อ้างจากเอกสาร:

โปรดทราบว่าใน Android สิ่งนี้ไม่รับประกันการเชื่อมต่ออินเทอร์เน็ต ตัวอย่างเช่นแอปอาจมีการเข้าถึง wifi แต่อาจเป็น VPN หรือ WiFi ของโรงแรมที่ไม่สามารถเข้าถึงได้

หากคุณต้องการตรวจสอบการเชื่อมต่อกับอินเทอร์เน็ต www จริงๆทางเลือกที่ดีกว่าคือ

แพ็คเกจ data_connection_checker


1

นี่คือทางออกของฉันตรวจสอบการเชื่อมต่ออินเทอร์เน็ตและการเชื่อมต่อข้อมูลฉันหวังว่าคุณจะชอบ

ก่อนอื่นให้เพิ่มการอ้างอิงใน pubsec.yaml ของคุณ
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"),
        ),
      ),
    );
  }
}

1

ฉันมีปัญหากับแนวทางแก้ไขที่เสนอโดยการใช้lookupไม่ได้ส่งคืนค่าที่คาดหวังเสมอไป

เนื่องจากการแคช DNS ค่าของการโทรจะถูกแคชและตั้งใจที่จะทำการโทรที่เหมาะสมในการลองครั้งถัดไปจะให้ค่าแคชกลับมา แน่นอนว่านี่เป็นปัญหาที่นี่เนื่องจากหมายความว่าหากคุณสูญเสียการเชื่อมต่อและเรียกlookupได้ว่ายังสามารถคืนค่าแคชได้ราวกับว่าคุณมีอินเทอร์เน็ตและในทางกลับกันหากคุณเชื่อมต่ออินเทอร์เน็ตอีกครั้งหลังจากlookupส่งคืนค่าว่างมันจะยังคงคืนค่าว่างตลอดระยะเวลาของ แคชซึ่งอาจใช้เวลาไม่กี่นาทีแม้ว่าคุณจะมีอินเทอร์เน็ตแล้วก็ตาม

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 ลงในรายการที่สามารถเข้าถึงได้จากประเทศเป้าหมายของคุณ


1

ในที่สุดฉันก็ ( แม้ว่าจะไม่เต็มใจ ) ก็ตัดสินวิธีแก้ปัญหาที่ได้รับจาก @abernee ในคำตอบก่อนหน้านี้สำหรับคำถามนี้ ฉันมักจะพยายามและใช้แพ็คเกจภายนอกในโครงการของฉันให้น้อยที่สุดเท่าที่จะเป็นไปได้ - อย่างที่ฉันรู้ว่าแพ็กเกจภายนอกเป็นเพียงจุดเดียวของความล้มเหลวในซอฟต์แวร์ที่ฉันสร้าง เพื่อที่จะเชื่อมโยงไปยังสองแพคเกจภายนอกเพียงสำหรับการดำเนินงานที่เรียบง่ายเช่นนี้ก็ไม่ง่ายสำหรับผม

อย่างไรก็ตามฉันใช้รหัสของ abernee และแก้ไขเพื่อให้บางลงและสมเหตุสมผลมากขึ้น โดยสมเหตุสมผลฉันหมายความว่าเขาใช้พลังงานของแพ็คเกจการเชื่อมต่อในฟังก์ชันของเขา แต่ก็เสียมันไปภายในโดยไม่ส่งคืนผลลัพธ์ที่มีค่าที่สุดจากแพ็คเกจนี้ (เช่นการระบุเครือข่าย) ดังนั้นนี่คือโซลูชันของ abernee เวอร์ชันแก้ไข:

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


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

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

}

จากนั้นคุณจะใช้ฟังก์ชันคงที่นี้ผ่านการโทรธรรมดาจากที่ใดก็ได้ในรหัสของคุณดังนี้:

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

เป็นเรื่องน่าเสียดายที่คุณต้องเชื่อมโยงกับแพ็คเกจภายนอกสองชุดเพื่อรับฟังก์ชันพื้นฐานนี้ในโครงการ Flutter ของคุณ - แต่ตอนนี้ฉันคิดว่านี่เป็นสิ่งที่ดีที่สุดที่เรามี จริงๆแล้วฉันชอบแพ็คเกจตัวตรวจสอบการเชื่อมต่อข้อมูลมากกว่าแพ็คเกจการเชื่อมต่อแต่ (ในขณะที่โพสต์สิ่งนี้) ก่อนหน้านี้ไม่มีคุณสมบัติการระบุเครือข่ายที่สำคัญมากที่ฉันต้องการจากแพ็คเกจการเชื่อมต่อ นี่คือเหตุผลที่ฉันผิดนัดใช้แนวทางนี้ [ชั่วคราว]


0

แค่พยายามทำให้โค้ดง่ายขึ้นโดยใช้Connectivity Package ใน 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
}

ปัญหาเกี่ยวกับสิ่งนี้บน 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);
}

ตรงไปที่แพ็คเกจหากคุณต้องการข้อมูลเพิ่มเติม แพ็คเกจตัวตรวจสอบการเชื่อมต่อข้อมูล


0

ฉันมีปัญหากับคำตอบที่ได้รับการยอมรับ แต่ดูเหมือนว่าจะแก้ปัญหาให้คนอื่นได้ ฉันต้องการโซลูชันที่สามารถรับการตอบสนองจาก url ที่ใช้ดังนั้นฉันคิดว่า http น่าจะดีสำหรับฟังก์ชันนั้นและฉันพบว่าคำตอบนี้มีประโยชน์มาก ฉันจะตรวจสอบการเชื่อมต่ออินเทอร์เน็ตโดยใช้คำขอ HTTP (Flutter / Dart) ได้อย่างไร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.