مراقبة حالة الاتصال بالإنترنت باستخدام Flutter وDart

مراقبة حالة الاتصال بالإنترنت باستخدام Flutter وDart

مراقبة حالة الاتصال بالإنترنت باستخدام Flutter وDart

تعد مراقبة حالة الاتصال بالإنترنت أمرًا بالغ الأهمية لتطبيقات الهاتف المحمول، حيث تتطلب العديد من التطبيقات الحديثة اتصالاً ثابتًا بالشبكة لتقديم الخدمات بشكل فعال. يوفر الكود أعلاه مثالًا عمليًا لكيفية تحقيق ذلك باستخدام لغة برمجة Dart وإطار عمل Flutter.


كيفية تحسين تجربة المستخدم في Flutter عند انقطاع الاتصال بالشبكة


dart:async: توفر أدوات لمعالجة العمليات غير المتزامنة، مثل StreamController.

dart:io: تتيح الوصول إلى وظائف الإدخال/الإخراج الأساسية، مثل التحقق من الاتصال بالإنترنت باستخدام InternetAddress.lookup.

connectivity_plus: مكتبة خارجية تُستخدم لمراقبة حالة الاتصال بالشبكة (Wi-Fi، Mobile، وغيرها).

flutter/cupertino.dart: يوفر أدوات لبناء واجهات المستخدم بأسلوب iOS.

hayyak/core/injection/injector.dart: يُستخدم لإدارة الاعتمادات، ولكنه ليس مفصلاً في الكود.

../routing_manager/routing_manager.dart: يُستخدم لإدارة التنقل بين صفحات التطبيق.

الفئة ConnectionStatusListener

الفئة ConnectionStatusListener مسؤولة عن مراقبة حالة الاتصال بالإنترنت وإعلام الأجزاء الأخرى من التطبيق بأي تغييرات في الحالة.


النمط الأحادي (Singleton Pattern)

تستخدم الفئة النمط الأحادي لضمان وجود كائن واحد فقط من ConnectionStatusListener خلال دورة حياة التطبيق.

_singleton: كائن ثابت من الفئة.

ConnectionStatusListener._internal(): مُنشئ خاص يستخدم لإنشاء الكائن الأحادي.

getInstance(): دالة ثابتة تعيد الكائن الأحادي.


hasShownNoInternet: علم يشير إلى ما إذا تم عرض إشعار بعدم وجود اتصال بالإنترنت أم لا.

_connectivity: كائن من مكتبة connectivity_plus لمراقبة حالة الاتصال.

hasConnection: علم يشير إلى حالة الاتصال الحالية.

connectionChangeController: متحكم بالبث لإرسال تحديثات حالة الاتصال.

connectionChange: تيار (Stream) يعرض تحديثات حالة الاتصال.

_connectionChange(List<ConnectivityResult> result): يتم الاتصال به عندما تتغير حالة الاتصال.

checkConnection(List<ConnectivityResult> result ): تحقق من اتصال الإنترنت الفعلي من خلال محاولة الوصول إلى google.com.


التهيئة (): تهيئة جهاز مراقبة حالة الاتصال والتحقق من الحالة الحالية.

التخلص (): أغلق وحدة التحكم في التدفق عند الانتهاء.


navigatorKey: مفتاح عام يستخدم لإدارة التنقل بين صفحات التطبيق.

initNoInternetListener(): تهيئة مستمع حالة الاتصال وتحديث الواجهة وفقًا لحالة الاتصال.

updateConnectivity(bool hasConnection, ConnectionStatusListener communicationStatus): قم بتحديث الواجهة وفقًا لحالة الاتصال الحالية.


ConnectionStatusListener.class

import 'dart:async';
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/cupertino.dart';
import 'package:hayyak/core/injection/injector.dart';
import '../routing_manager/routing_manager.dart';

class ConnectionStatusListener {
  static final ConnectionStatusListener _singleton = ConnectionStatusListener._internal();

  ConnectionStatusListener._internal();

  bool hasShownNoInternet = false;
  final Connectivity _connectivity = Connectivity();
  static ConnectionStatusListener getInstance() => _singleton;

  bool hasConnection = false;
  StreamController<bool> connectionChangeController = StreamController<bool>.broadcast();
  Stream<bool> get connectionChange => connectionChangeController.stream;

  void _connectionChange(List<ConnectivityResult> result) {
    checkConnection(result);
  }

  Future<bool> checkConnection(List<ConnectivityResult> result) async {
    bool previousConnection = hasConnection;

    if (result.contains(ConnectivityResult.wifi) || result.contains(ConnectivityResult.mobile)) {
      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;
      }
    } else {
      hasConnection = false;
    }

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

  Future<void> initialize() async {
    _connectivity.onConnectivityChanged.listen(_connectionChange);

    List<ConnectivityResult> result = await _connectivity.checkConnectivity();
    _connectionChange(result);
  }

  void dispose() {
    connectionChangeController.close();
  }
}

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

initNoInternetListener() async {
  var connectionStatus = injector<ConnectionStatusListener>();
  await connectionStatus.initialize();

  updateConnectivity(connectionStatus.hasConnection, connectionStatus);

  connectionStatus.connectionChange.listen((hasConnection) {
    updateConnectivity(hasConnection, connectionStatus);
  });
}

updateConnectivity(bool hasConnection, ConnectionStatusListener connectionStatus) {
  WidgetsBinding.instance.addPostFrameCallback((_) {
    if (!hasConnection && !connectionStatus.hasShownNoInternet) {
      connectionStatus.hasShownNoInternet = true;
      navigatorKey.currentState?.pushNamed(RouteManager.internet);
    } else if (hasConnection && connectionStatus.hasShownNoInternet) {
      connectionStatus.hasShownNoInternet = false;
      if (navigatorKey.currentState?.canPop() ?? false) {
        navigatorKey.currentState?.pop();
      }
    }
  });
}

إنشاء Stream لحالة الاتصال بالإنترنت في تطبيقات Flutter


يعد الكود المقدم جزءًا من تطبيق يستخدم مكتبة GetIt لإدارة التبعيات (حقن التبعية) في تطبيق Flutter. دعونا نحلل الكود بالتفصيل ونفهم وظائفه.

المكتبات المستخدمة
GetIt: مكتبة شعبية لإدارة التبعيات في Dart وFlutter. تتيح لك هذه المكتبة تسجيل واسترجاع الكائنات التي تعتمد عليها أجزاء مختلفة من تطبيقك بسهولة.

انشاء injector 
GetIt.instance: إنشاء مثيل واحد لـ GetIt يعمل كوسيط لتسجيل التبعيات واستردادها في التطبيق.
الحاقن: يخزن المتغير النهائي لمثيل GetIt، مما يجعله نقطة الوصول الأساسية لجميع التبعيات المسجلة.
الحاقن: فئة تحتوي على وظيفة تهيئة ثابتة واحدة تسجل التبعيات الضرورية وتهيئ مستمع الحضور.
الحرف الأول: دالة ثابتة تُستخدم لتهيئة التبعيات عند بدء تشغيل التطبيق.
jector.registerFactory(() => ConnectionStatusListener.getInstance()): قم بتسجيل ConnectionStatusListener كـ "مصنع" في GetIt. هذا يعني أنه في كل مرة يتم فيها طلب مثيل ConnectionStatusListener، يتم استخدام getInstance لاسترداد مثيل مفرد للفئة.
initNoInternetListener(): استدعاء هذه الوظيفة لتهيئة مستمع الحالة عبر الإنترنت. يجب أن تكون هذه الوظيفة موجودة في مكان آخر في التطبيق وتقوم بتنشيط مستمع الحضور لإظهار أو إخفاء الإشعارات غير المتصلة بالإنترنت.

Injector.class
final injector = GetIt.instance;

class Injector {
  static void init() async {
    injector.registerFactory(() => ConnectionStatusListener.getInstance());
    initNoInternetListener();
  }
}

كيفية تحسين تجربة المستخدم في Flutter عند انقطاع الاتصال بالشبكة


تعريف الدالة الرئيسية: الدالة main هي نقطة الدخول لأي تطبيق Dart أو Flutter. إعلانها باستخدام async يشير إلى أنها قد تحتوي على عمليات غير متزامنة تنتظر إتمامها.
تهيئة Flutter: هذه الدالة تضمن تهيئة Flutter بشكل صحيح قبل القيام بأي عمليات أخرى تتعلق بـ Flutter. تُستخدم عادة عندما تكون هناك عمليات تحتاج إلى التنفيذ قبل استدعاء runApp.

main.dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await ScreenUtil.ensureScreenSize();
  Injector.init();
  Bloc.observer = Observer();
  runApp(HayyakMain(keyRoute: navigatorKey));
}
تعليقات