مراقبة اتصال الشبكة
مراقبة اتصال الشبكة
يجب على التطبيقات المحمولة الحديثة التعامل بسلاسة مع ظروف الشبكة غير الموثوقة. بدلاً من السماح لطلبات الشبكة بالفشل بصمت، يمكن لتطبيقات Flutter استخدام حزمة connectivity_plus للتحقق من حالة الشبكة الحالية عند التشغيل والاستماع إلى التغييرات في الوقت الفعلي — مع عرض تغذية راجعة مناسبة داخل التطبيق عندما يتعذر الاتصال أو يعود.
إضافة حزمة connectivity_plus
أضف الحزمة إلى ملف pubspec.yaml:
pubspec.yaml
dependencies:
flutter:
sdk: flutter
connectivity_plus: ^6.0.3
شغّل الأمر flutter pub get لتنزيل التبعية. على Android، لا تلزم أذونات إضافية لقراءة حالة الاتصال. وعلى iOS، تعمل الحزمة مباشرةً دون أي تعديلات على Info.plist.
واجهة برمجة التطبيقات الرئيسية
تُعرض الحزمة من خلال صنف وحيد هو Connectivity مع نقطتَي دخول رئيسيتين:
checkConnectivity()— تُعيدFuture<List<ConnectivityResult>>يحتوي على نوع (أو أنواع) الاتصال الحالية.onConnectivityChanged—Stream<List<ConnectivityResult>>يُصدر حدثاً في كل مرة تتغير فيها حالة الشبكة.
يشمل التعداد ConnectivityResult قيماً مثل wifi وmobile وethernet وvpn وbluetooth وnone. قد يُبلّغ الجهاز عن نتائج متعددة في آنٍ واحد (مثلاً wifi وvpn معاً).
connectivity_plus عن نوع واجهة الشبكة، لا عمّا إذا كانت الإنترنت متاحة فعلياً. جهاز متصل بشبكة WiFi لا تملك اتصالاً صاعداً سيُعيد مع ذلك ConnectivityResult.wifi. للتحقق الحقيقي من إمكانية الوصول، اجمع هذه الحزمة مع فحص HTTP أو استخدم internet_connection_checker_plus.فحص الاتصال عند التشغيل
أنظف نمط هو إجراء الفحص الأولي داخل initState ثم الاشتراك فوراً في الدفق:
NetworkStatusService — الفحص والاستماع
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
class NetworkAwarePage extends StatefulWidget {
const NetworkAwarePage({super.key});
@override
State<NetworkAwarePage> createState() => _NetworkAwarePageState();
}
class _NetworkAwarePageState extends State<NetworkAwarePage> {
final Connectivity _connectivity = Connectivity();
late StreamSubscription<List<ConnectivityResult>> _subscription;
bool _isOnline = true;
ConnectivityResult _connectionType = ConnectivityResult.none;
@override
void initState() {
super.initState();
_checkInitialConnectivity();
_subscription = _connectivity.onConnectivityChanged.listen(_onConnectivityChanged);
}
Future<void> _checkInitialConnectivity() async {
final results = await _connectivity.checkConnectivity();
_onConnectivityChanged(results);
}
void _onConnectivityChanged(List<ConnectivityResult> results) {
final hasConnection = results.any(
(r) => r != ConnectivityResult.none,
);
setState(() {
_isOnline = hasConnection;
_connectionType = results.isNotEmpty ? results.first : ConnectivityResult.none;
});
}
@override
void dispose() {
_subscription.cancel(); // ألغِ دائماً لمنع تسرب الذاكرة
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('عرض الشبكة')),
body: Column(
children: [
if (!_isOnline)
Container(
width: double.infinity,
color: Colors.red.shade700,
padding: const EdgeInsets.symmetric(vertical: 8),
child: const Text(
'لا يوجد اتصال بالإنترنت',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
Expanded(
child: Center(
child: Text(
_isOnline
? 'متصل عبر $_connectionType'
: 'غير متصل',
style: const TextStyle(fontSize: 18),
),
),
),
],
),
);
}
}
StreamSubscription داخل dispose(). الإخفاق في ذلك يُبقي الاشتراك حياً حتى بعد إزالة الودجت من الشجرة، مما يُسبب تسرب الذاكرة وأخطاء setState على ودجت منتهي الصلاحية.استخراج ConnectivityService قابل لإعادة الاستخدام
في التطبيقات الأكبر حجماً، عزل منطق الاتصال في صنف خدمة مخصص وحقنه في الودجات عبر حل لإدارة الحالة مثل Provider أو Riverpod. يجعل ذلك الخدمة قابلة للاختبار ويتجنب تكرار نسخة Connectivity في التطبيق.
ConnectivityService — نمط أحادي قابل لإعادة الاستخدام
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
class ConnectivityService {
final Connectivity _connectivity = Connectivity();
// دفق بث يمكن للودجات الاستماع إليه
Stream<bool> get onStatusChange => _connectivity.onConnectivityChanged.map(
(results) => results.any((r) => r != ConnectivityResult.none),
);
/// تُعيد true إذا كانت أي واجهة غير none متاحة الآن.
Future<bool> get isConnected async {
final results = await _connectivity.checkConnectivity();
return results.any((r) => r != ConnectivityResult.none);
}
/// تسمية مقروءة بشرياً لنوع الاتصال الأساسي.
Future<String> get connectionLabel async {
final results = await _connectivity.checkConnectivity();
if (results.contains(ConnectivityResult.wifi)) return 'WiFi';
if (results.contains(ConnectivityResult.mobile)) return 'بيانات الهاتف';
if (results.contains(ConnectivityResult.ethernet)) return 'إيثرنت';
return 'غير متصل';
}
}
عرض التغذية الراجعة داخل التطبيق
تشمل الأنماط الشائعة لإظهار تغييرات الاتصال للمستخدم:
- شريط بانر — شريط ملون ثابت في أعلى الشاشة أو أسفلها (كما هو موضح أعلاه).
- SnackBar — إشعار مؤقت يختفي تلقائياً، مناسب لأحداث إعادة الاتصال.
- تراكب / حجب الشاشة الكاملة — للتطبيقات التي لا تدعم الاستخدام دون اتصال.
- تعطيل الإجراءات — تعتيم أزرار الرفع والإرسال عند انقطاع الاتصال.
ملخص
توفر حزمة connectivity_plus أداتين متكاملتين: مستقبل checkConnectivity() للمرة الواحدة لفحص التشغيل، ودفق onConnectivityChanged للتحديثات التفاعلية. النمط المعياري هو: (1) إضافة الحزمة، (2) استدعاء المستقبل في initState، (3) الاشتراك في الدفق وتحديث الحالة، و(4) إلغاء الاشتراك في dispose(). في تطبيقات الإنتاج، اقرن ذلك بفحص فعلي لإمكانية الوصول إلى الإنترنت واستخرج المنطق في خدمة مشتركة.