تفعيل إمكانيات الاتصال بلا إنترنت

تعمل تطبيقات Firebase حتى إذا فقد تطبيقك الشبكة مؤقتًا. الاتصال. بالإضافة إلى ذلك، يوفر Firebase أدوات للاحتفاظ بالبيانات محليًا، وإدارة التواجد ووقت الاستجابة.

ثبات القرص

تتعامل تطبيقات Firebase مع الانقطاعات المؤقتة في الشبكة تلقائيًا. تتوفّر البيانات المخزّنة مؤقتًا عندما تكون غير متصل بالإنترنت، ويعيد Firebase إرسال أي عمليات كتابة. عند استعادة اتصال الشبكة.

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

يمكنك تفعيل ميزة تثبيت القرص باستخدام سطر واحد فقط من الرمز.

FirebaseDatabase.instance.setPersistenceEnabled(true);

سلوك الاستمرارية

من خلال تفعيل ميزة الثبات، أي بيانات يقوم برنامج قاعدة بيانات Firebase في الوقت الفعلي تتم مزامنته أثناء استمرار الاتصال بالإنترنت على القرص وإتاحتها في وضع عدم الاتصال، حتى عندما يعيد المستخدم أو نظام التشغيل تشغيل التطبيق. هذا يعني أن كما لو كان على الإنترنت باستخدام البيانات المحلية المخزنة في ذاكرة التخزين المؤقت. سيستمر تنشيط استدعاءات المستمعين للحصول على التحديثات المحلية.

يحتفظ برنامج قاعدة بيانات Firebase في الوقت الفعلي تلقائيًا بقائمة انتظار لجميع كتابة العمليات التي يتم إجراؤها أثناء عدم اتصال التطبيق بالإنترنت. عند تمكين الثبات، يتم أيضًا حفظ قائمة الانتظار هذه على القرص حتى يكون جميع عندما تتوفر كتاباتك عندما يستخدم المستخدم أو نظام التشغيل لإعادة تشغيل التطبيق. عندما يستعيد التطبيق الاتصال، فإن جميع يتم إرسال العمليات إلى خادم قاعدة بيانات Firebase في الوقت الفعلي.

إذا كان تطبيقك يستخدم مصادقة Firebase: يحتفظ عميل قاعدة بيانات Firebase في الوقت الفعلي بمصادقة المستخدم الرمز المميز عبر عمليات إعادة تشغيل التطبيق. إذا انتهت صلاحية الرمز المميّز للمصادقة عندما يكون تطبيقك غير متصل بالإنترنت، سيتم إيقاف البرنامج مؤقتًا. كتابة العمليات حتى يعيد التطبيق مصادقة المستخدم، وإلا عمليات الكتابة بسبب قواعد الأمان.

الحفاظ على إعادة تحميل البيانات

وتزامن قاعدة بيانات Firebase في الوقت الفعلي وتخزّن نسخة محلية من المستمعين النشطين. بالإضافة إلى ذلك، يمكنك الاحتفاظ بمواقع جغرافية محددة متزامنًا.

final scoresRef = FirebaseDatabase.instance.ref("scores");
scoresRef.keepSynced(true);

يعمل عميل قاعدة بيانات Firebase في الوقت الفعلي تلقائيًا على تنزيل البيانات في هذه المواقع ويحافظ على مزامنتها حتى إذا كان المرجع المستمعين النشطين. يمكنك إيقاف المزامنة مرة أخرى باستخدام السطر التالي من التعليمة البرمجية.

scoresRef.keepSynced(false);

بشكل تلقائي، يتم تخزين 10 ميغابايت من البيانات التي تمت مزامنتها سابقًا مؤقتًا. يجب أن يكون هذا كافيًا لمعظم التطبيقات. إذا تخطت ذاكرة التخزين المؤقت حجمها الذي تم إعداده، فإن قاعدة بيانات Firebase في الوقت الفعلي تزيل نهائيًا البيانات المستخدَمة مؤخرًا. لا تتم الإزالة النهائية للبيانات التي يتم الاحتفاظ بها متزامنة من ذاكرة التخزين المؤقت.

الاستعلام عن البيانات بلا اتصال بالإنترنت

تخزن قاعدة بيانات Firebase في الوقت الفعلي البيانات التي يتم عرضها من استعلام لاستخدامها عندما تكون غير متصل بالإنترنت. بالنسبة للاستعلامات التي تم إنشاؤها أثناء وضع عدم الاتصال، تواصل قاعدة بيانات Firebase في الوقت الفعلي العمل مع البيانات التي تم تحميلها مسبقًا. إذا لم يتم تحميل البيانات المطلوبة، يتم تحميل قاعدة بيانات Firebase في الوقت الفعلي من ذاكرة التخزين المؤقت المحلية. عندما يكون اتصال الشبكة متاحًا مرة أخرى، يتم تحميل البيانات وستعكس الاستعلام.

على سبيل المثال، تقوم هذه التعليمة البرمجية بالاستعلام عن آخر أربعة عناصر في قاعدة بيانات للدرجات:

final scoresRef = FirebaseDatabase.instance.ref("scores");
scoresRef.orderByValue().limitToLast(4).onChildAdded.listen((event) {
  debugPrint("The ${event.snapshot.key} dinosaur's score is ${event.snapshot.value}.");
});

لنفترض أنّ المستخدم يفقد الاتصال بالإنترنت ويتوقّف عن الاتصال بالإنترنت ويعيد تشغيل التطبيق. أثناء عدم اتصال التطبيق بالإنترنت، يطلب التطبيق آخر عنصرين من الموقع نفسه. سيعرض هذا الاستعلام آخر عنصرين بنجاح لأن التطبيق حمّل جميع العناصر الأربعة في الاستعلام أعلاه.

scoresRef.orderByValue().limitToLast(2).onChildAdded.listen((event) {
  debugPrint("The ${event.snapshot.key} dinosaur's score is ${event.snapshot.value}.");
});

في المثال السابق، يطرح عميل قاعدة بيانات Firebase في الوقت الفعلي "تمت إضافة تابعة" التي تضم أعلى ديناصورين من النقاط، وذلك باستخدام تم الاحتفاظ بذاكرة التخزين المؤقت. لكنها لن تزيد "القيمة" حدث، نظرًا لأن التطبيق يحتوي على لم تنفذ هذا الاستعلام أثناء الاتصال بالإنترنت.

إذا طلب التطبيق العناصر الستة الأخيرة أثناء عدم الاتصال، فسيحصل "تمت إضافة تابعة" الأحداث للعناصر الأربعة المخزنة مؤقتًا على الفور. عندما الإنترنت مرة أخرى، فسيجري برنامج قاعدة بيانات Firebase في الوقت الفعلي مع الخادم ويتم الحصول على آخر عنصرين "تابعين" و 'value' أحداث للتطبيق.

التعامل مع المعاملات بلا إنترنت

يتم وضع أي معاملات يتم إجراؤها عندما يكون التطبيق بلا اتصال بالإنترنت في قائمة الانتظار. بعد أن يستعيد التطبيق الاتصال بالشبكة، يتم إرسال المعاملات إلى خادم قاعدة بيانات الوقت الفعلي.

تحتوي قاعدة بيانات Firebase في الوقت الفعلي على العديد من الميزات للتعامل مع والسيناريوهات واتصال الشبكة. ينطبق باقي هذا الدليل على تطبيقك سواء كانت ميزة التثبيت التلقائي مفعّلة أم لا.

إدارة التواجد

غالبًا ما يكون من المفيد في تطبيقات الوقت الفعلي اكتشاف الوقت الذي يستغرقه العملاء الاتصال وقطع الاتصال. على سبيل المثال، يمكنك أن تريد وضع علامة "غير متصل" على المستخدم عندما ينقطع اتصال عميله.

يوفر عملاء قاعدة بيانات Firebase أساسيات بسيطة يمكنك استخدامها الكتابة في قاعدة البيانات عندما ينقطع اتصال العميل بقاعدة بيانات Firebase الخوادم. وتحدث هذه التحديثات سواء انفصل العميل عن الخدمة أم لا لذا يمكنك الاعتماد عليها لتنظيف البيانات حتى إذا انقطع الاتصال أو تعطل عميل ما. جميع عمليات الكتابة، بما في ذلك الإعداد وتحديثه وإزالته، عند قطع الاتصال.

فيما يلي مثال بسيط لكتابة البيانات عند الفصل باستخدام المجموعة الأساسية onDisconnect:

final presenceRef = FirebaseDatabase.instance.ref("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().set("I disconnected!");

طريقة عمل ميزة on Connect

عند إنشاء عملية onDisconnect()، يتم على خادم قاعدة بيانات Firebase في الوقت الفعلي. يفحص الخادم الأمان وتتأكد من أن المستخدم يمكنه تنفيذ حدث الكتابة المطلوب، ويبلغ تطبيقك إذا كان غير صالح. ثم الخادم ويراقب الاتصال. إذا انتهت مهلة الاتصال في أي وقت أو بواسطة عميل قاعدة البيانات في الوقت الفعلي، فإن الخادم يفحص أمان مرة ثانية (للتأكد من أن العملية لا تزال صالحة) ثم يتم استدعاء الحدث.

try {
    await presenceRef.onDisconnect().remove();
} catch (error) {
    debugPrint("Could not establish onDisconnect event: $error");
}

يمكن أيضًا إلغاء حدث onUnsubscribe من خلال الاتصال بـ .cancel():

final onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.set("I disconnected");
// ...
// some time later when we change our minds
// ...
onDisconnectRef.cancel();

اكتشاف حالة الاتصال

بالنسبة إلى العديد من الميزات المتعلّقة بالحضور، يكون ذلك مفيدًا لتطبيقك. لمعرفة ما إذا كان متصلاً بالإنترنت أو غير متصل بالإنترنت. قاعدة بيانات Firebase في الوقت الفعلي يوفر موقعًا خاصًا في /.info/connected يتم تعديل كل مرة يتم فيها تعديل حالة اتصال عميل قاعدة بيانات Firebase في الوقت الفعلي التغييرات. وفي ما يلي مثال لذلك:

final connectedRef = FirebaseDatabase.instance.ref(".info/connected");
connectedRef.onValue.listen((event) {
  final connected = event.snapshot.value as bool? ?? false;
  if (connected) {
    debugPrint("Connected.");
  } else {
    debugPrint("Not connected.");
  }
});

/.info/connected هي قيمة منطقية ليست متزامنة بين عملاء قاعدة البيانات في الوقت الفعلي لأن القيمة يعتمد على حالة العميل. بعبارة أخرى، إذا كان أحد العملاء تقرأ /.info/connected على أنها false، هذا لا ضمان قراءة عميل منفصل للخطأ أيضًا.

وقت الاستجابة

الطوابع الزمنية للخادم

وتوفر خوادم قاعدة بيانات Firebase في الوقت الفعلي آلية لإدراج الطوابع الزمنية التي تم إنشاؤها على الخادم كبيانات. وهذه الميزة بالإضافة إلى onDisconnect، طريقة سهلة لتدوين الملاحظات بشكل موثوق فيه الوقت الذي تم فيه قطع اتصال عميل قاعدة البيانات في الوقت الفعلي:

final userLastOnlineRef =
    FirebaseDatabase.instance.ref("users/joe/lastOnline");
userLastOnlineRef.onDisconnect().set(ServerValue.timestamp);

انحراف الساعة

في حين أن ServerValue.timestamp أكثر بكثير ودقيقة ومفضلة لمعظم عمليات القراءة/الكتابة، قد يكون من المفيد أحيانًا تقدير ساعة العميل فيما يتعلق بخوادم قاعدة بيانات Firebase في الوقت الفعلي. إِنْتَ يمكن إرفاق معاودة الاتصال بالموقع الجغرافي /.info/serverTimeOffset. وذلك من أجل الحصول على القيمة بالمللي ثانية التي يستخدمها عملاء قاعدة بيانات Firebase في الوقت الفعلي تضيفه إلى الوقت المحلي المبلّغ عنه (وقت الحقبة بالمللي ثانية) لتقدير وقت الخادم. لاحظ أن دقة هذه الإزاحة يمكن أن تتأثر وقت استجابة الشبكة، لذا فهي مفيدة في المقام الأول لاكتشاف اختلافات كبيرة (أكبر من ثانية واحدة) في وقت الساعة.

final offsetRef = FirebaseDatabase.instance.ref(".info/serverTimeOffset");
offsetRef.onValue.listen((event) {
  final offset = event.snapshot.value as num? ?? 0.0;
  final estimatedServerTimeMs =
      DateTime.now().millisecondsSinceEpoch + offset;
});

نموذج تطبيق التواجد

من خلال الجمع بين عمليات قطع الاتصال ومراقبة حالة الاتصال الطوابع الزمنية للخادم، فيمكنك إنشاء نظام تواجد المستخدم. في هذا النظام، يقوم كل مستخدم بتخزين البيانات في موقع قاعدة البيانات للإشارة إلى ما إذا كان برنامج قاعدة البيانات في الوقت الفعلي متصل بالإنترنت. يضبط العملاء هذا الموقع على "صحيح" عندما عند اتصالهم بالإنترنت وبطابع زمني عند قطع الاتصال. هذا الطابع الزمني تشير إلى آخر مرة كان فيها المستخدم المحدد متصلاً بالإنترنت.

تجدر الإشارة إلى أنّ تطبيقك يجب أن يضع عمليات إلغاء الربط في قائمة انتظار قبل أن يبدأ المستخدم وتمييزها عبر الإنترنت، لتجنب أي شروط سباق في حال انعقاد يتم فقدان اتصال الشبكة قبل إرسال كلا الأمرين إلى الخادم.

// Since I can connect from multiple devices, we store each connection
// instance separately any time that connectionsRef's value is null (i.e.
// has no children) I am offline.
final myConnectionsRef =
    FirebaseDatabase.instance.ref("users/joe/connections");

// Stores the timestamp of my last disconnect (the last time I was seen online)
final lastOnlineRef =
    FirebaseDatabase.instance.ref("/users/joe/lastOnline");

final connectedRef = FirebaseDatabase.instance.ref(".info/connected");
connectedRef.onValue.listen((event) {
  final connected = event.snapshot.value as bool? ?? false;
  if (connected) {
    final con = myConnectionsRef.push();

    // When this device disconnects, remove it.
    con.onDisconnect().remove();

    // When I disconnect, update the last time I was seen online.
    lastOnlineRef.onDisconnect().set(ServerValue.timestamp);

    // Add this device to my connections list.
    // This value could contain info about the device or a timestamp too.
    con.set(true);
  }
});