مراقبة حالة الاتصال بالإنترنت باستخدام 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
final injector = GetIt.instance;
class Injector {
static void init() async {
injector.registerFactory(() => ConnectionStatusListener.getInstance());
initNoInternetListener();
}
}كيفية تحسين تجربة المستخدم في Flutter عند انقطاع الاتصال بالشبكة
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await ScreenUtil.ensureScreenSize();
Injector.init();
Bloc.observer = Observer();
runApp(HayyakMain(keyRoute: navigatorKey));
}
