تعمل تطبيقات Firebase حتى إذا فقد تطبيقك الشبكة مؤقتًا. الاتصال. بالإضافة إلى ذلك، يوفر Firebase أدوات للاحتفاظ بالبيانات محليًا، وإدارة التواجد ووقت الاستجابة.
ثبات القرص
تتعامل تطبيقات Firebase مع الانقطاعات المؤقتة في الشبكة تلقائيًا. تتوفّر البيانات المخزّنة مؤقتًا عندما تكون غير متصل بالإنترنت، ويعيد Firebase إرسال أي عمليات كتابة. عند استعادة اتصال الشبكة.
عند تفعيل خاصية الاحتفاظ بالقرص، يكتب تطبيقك البيانات محليًا على حتى يحافظ تطبيقك على حالته أثناء عدم الاتصال بالإنترنت، حتى إذا كان المستخدم أو نظام التشغيل يعيد تشغيل التطبيق.
يمكنك تفعيل ميزة تثبيت القرص باستخدام سطر واحد فقط من الرمز.
Swift
Database.database().isPersistenceEnabled = true
Objective-C
[FIRDatabase database].persistenceEnabled = YES;
سلوك الاستمرارية
من خلال تفعيل ميزة الاحتفاظ بالبيانات، ستظهر أي بيانات يجريها عميل Firebase Realtime Database. تتم مزامنته أثناء استمرار الاتصال بالإنترنت على القرص وإتاحتها في وضع عدم الاتصال، حتى عندما يعيد المستخدم أو نظام التشغيل تشغيل التطبيق. هذا يعني أن كما لو كان على الإنترنت باستخدام البيانات المحلية المخزنة في ذاكرة التخزين المؤقت. سيستمر تنشيط استدعاءات المستمعين للحصول على التحديثات المحلية.
يحتفظ عميل Firebase Realtime Database تلقائيًا بقائمة انتظار لجميع كتابة العمليات التي يتم إجراؤها أثناء عدم اتصال التطبيق بالإنترنت. عند تمكين الثبات، يتم أيضًا حفظ قائمة الانتظار هذه على القرص حتى يكون جميع عندما تتوفر كتاباتك عندما يستخدم المستخدم أو نظام التشغيل لإعادة تشغيل التطبيق. عندما يستعيد التطبيق الاتصال، فإن جميع يتم إرسال العمليات إلى خادم Firebase Realtime Database.
إذا كان تطبيقك يستخدم مصادقة Firebase، يستمر عميل Firebase Realtime Database في مواصلة مصادقة المستخدم. الرمز المميز عبر عمليات إعادة تشغيل التطبيق. إذا انتهت صلاحية الرمز المميّز للمصادقة عندما يكون تطبيقك غير متصل بالإنترنت، سيتم إيقاف البرنامج مؤقتًا. كتابة العمليات حتى يعيد التطبيق مصادقة المستخدم، وإلا عمليات الكتابة بسبب قواعد الأمان.
الحفاظ على إعادة تحميل البيانات
يعمل Firebase Realtime Database على مزامنة وتخزين نسخة محلية من المستمعين النشطين. بالإضافة إلى ذلك، يمكنك الاحتفاظ بمواقع جغرافية محددة متزامنًا.
Swift
let scoresRef = Database.database().reference(withPath: "scores") scoresRef.keepSynced(true)
Objective-C
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"]; [scoresRef keepSynced:YES];
يعمل عميل Firebase Realtime Database على تنزيل البيانات تلقائيًا في هذه المواقع ويحافظ على مزامنتها حتى إذا كان المرجع المستمعين النشطين. يمكنك إيقاف المزامنة مرة أخرى باستخدام السطر التالي من التعليمة البرمجية.
Swift
scoresRef.keepSynced(false)
Objective-C
[scoresRef keepSynced:NO];
بشكل تلقائي، يتم تخزين 10 ميغابايت من البيانات التي تمت مزامنتها سابقًا مؤقتًا. يجب أن يكون هذا كافيًا لمعظم التطبيقات. إذا تخطت ذاكرة التخزين المؤقت حجمها الذي تم إعداده، تزيل Firebase Realtime Database نهائيًا البيانات التي تم استخدامها مؤخرًا. لا تتم الإزالة النهائية للبيانات التي يتم الاحتفاظ بها متزامنة من ذاكرة التخزين المؤقت.
الاستعلام عن البيانات بلا اتصال بالإنترنت
تخزِّن Firebase Realtime Database البيانات التي يتم عرضها من خلال طلب بحث لاستخدامها. عندما تكون غير متصل بالإنترنت. بالنسبة للاستعلامات التي تم إنشاؤها أثناء وضع عدم الاتصال، تواصل Firebase Realtime Database العمل مع البيانات التي تم تحميلها سابقًا. إذا لم يتم تحميل البيانات المطلوبة، يتم تحميل Firebase Realtime Database. من ذاكرة التخزين المؤقت المحلية. عندما يكون اتصال الشبكة متاحًا مرة أخرى، يتم تحميل البيانات وستعكس الاستعلام.
على سبيل المثال، تطلب هذه التعليمة البرمجية لآخر أربعة عناصر في Firebase Realtime Database من النتائج
Swift
let scoresRef = Database.database().reference(withPath: "scores") scoresRef.queryOrderedByValue().queryLimited(toLast: 4).observe(.childAdded) { snapshot in print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")") }
Objective-C
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"]; [[[scoresRef queryOrderedByValue] queryLimitedToLast:4] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) { NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value); }];
لنفترض أنّ المستخدم يفقد الاتصال بالإنترنت ويتوقّف عن الاتصال بالإنترنت ويعيد تشغيل التطبيق. أثناء عدم اتصال التطبيق بالإنترنت، يطلب التطبيق آخر عنصرين من الموقع نفسه. سيعرض هذا الاستعلام آخر عنصرين بنجاح لأن التطبيق حمّل جميع العناصر الأربعة في الاستعلام أعلاه.
Swift
scoresRef.queryOrderedByValue().queryLimited(toLast: 2).observe(.childAdded) { snapshot in print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")") }
Objective-C
[[[scoresRef queryOrderedByValue] queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) { NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value); }];
في المثال السابق، رفع العميل Firebase Realtime Database "تمت إضافة تابعة" التي تضم أعلى ديناصورين من النقاط، وذلك باستخدام تم الاحتفاظ بذاكرة التخزين المؤقت. لكنها لن تزيد "القيمة" حدث، نظرًا لأن التطبيق يحتوي على لم تنفذ هذا الاستعلام أثناء الاتصال بالإنترنت.
إذا طلب التطبيق العناصر الستة الأخيرة أثناء عدم الاتصال، فسيحصل "تمت إضافة تابعة" الأحداث للعناصر الأربعة المخزنة مؤقتًا على الفور. عندما إعادة اتصال الجهاز بالإنترنت، تتم مزامنة برنامج Firebase Realtime Database مع الخادم ويتم الحصول على آخر عنصرين "تابعين" و 'value' أحداث للتطبيق.
التعامل مع المعاملات بلا إنترنت
يتم وضع أي معاملات يتم إجراؤها عندما يكون التطبيق بلا اتصال بالإنترنت في قائمة الانتظار. بعد أن يستعيد التطبيق الاتصال بالشبكة، يتم إرسال المعاملات إلى خادم Realtime Database.
إدارة التواجد
غالبًا ما يكون من المفيد في تطبيقات الوقت الفعلي اكتشاف الوقت الذي يستغرقه العملاء الاتصال وقطع الاتصال. على سبيل المثال، يمكنك أن تريد وضع علامة "غير متصل" على المستخدم عندما ينقطع اتصال عميله.
يوفر عملاء قاعدة بيانات Firebase أساسيات بسيطة يمكنك استخدامها الكتابة في قاعدة البيانات عندما ينقطع اتصال العميل بقاعدة بيانات Firebase الخوادم. وتحدث هذه التحديثات سواء انفصل العميل عن الخدمة أم لا لذا يمكنك الاعتماد عليها لتنظيف البيانات حتى إذا انقطع الاتصال أو تعطل عميل ما. جميع عمليات الكتابة، بما في ذلك الإعداد وتحديثه وإزالته، عند قطع الاتصال.
فيما يلي مثال بسيط لكتابة البيانات عند الفصل باستخدام
المجموعة الأساسية onDisconnect
:
Swift
let presenceRef = Database.database().reference(withPath: "disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnectSetValue("I disconnected!")
Objective-C
FIRDatabaseReference *presenceRef = [[FIRDatabase database] referenceWithPath:@"disconnectmessage"]; // Write a string when this client loses connection [presenceRef onDisconnectSetValue:@"I disconnected!"];
طريقة عمل ميزة on Connect
عند إنشاء عملية onDisconnect()
، يتم
يوجد على خادم Firebase Realtime Database. يفحص الخادم الأمان
وتتأكد من أن المستخدم يمكنه تنفيذ حدث الكتابة المطلوب، ويبلغ
تطبيقك إذا كان غير صالح. ثم الخادم
ويراقب الاتصال. إذا انتهت مهلة الاتصال في أي وقت أو
بشكل نشط من قِبل عميل Realtime Database، يفحص الخادم الأمان
مرة ثانية (للتأكد من أن العملية لا تزال صالحة) ثم يتم استدعاء
الحدث.
يمكن لتطبيقك استخدام الاستدعاء في عملية الكتابة.
للتأكّد من توصيل onDisconnect
بشكل صحيح:
Swift
presenceRef.onDisconnectRemoveValue { error, reference in if let error = error { print("Could not establish onDisconnect event: \(error)") } }
Objective-C
[presenceRef onDisconnectRemoveValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *reference) { if (error != nil) { NSLog(@"Could not establish onDisconnect event: %@", error); } }];
يمكن أيضًا إلغاء حدث "onDisconnect
" من خلال الاتصال بالرقم .cancel()
:
Swift
presenceRef.onDisconnectSetValue("I disconnected") // some time later when we change our minds presenceRef.cancelDisconnectOperations()
Objective-C
[presenceRef onDisconnectSetValue:@"I disconnected"]; // some time later when we change our minds [presenceRef cancelDisconnectOperations];
اكتشاف حالة الاتصال
بالنسبة إلى العديد من الميزات المتعلّقة بالحضور، يكون ذلك مفيدًا لتطبيقك.
لمعرفة ما إذا كان متصلاً بالإنترنت أو غير متصل بالإنترنت. Firebase Realtime Database
يوفر موقعًا خاصًا في /.info/connected
والذي
يتم تعديل كل مرة يتم فيها تعديل حالة اتصال عميل Firebase Realtime Database
التغييرات. وفي ما يلي مثال لذلك:
Swift
let connectedRef = Database.database().reference(withPath: ".info/connected") connectedRef.observe(.value, with: { snapshot in if snapshot.value as? Bool ?? false { print("Connected") } else { print("Not connected") } })
Objective-C
FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"]; [connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { if([snapshot.value boolValue]) { NSLog(@"connected"); } else { NSLog(@"not connected"); } }];
/.info/connected
هي قيمة منطقية ليست
تمت مزامنتها بين Realtime Database من العملاء لأن القيمة
يعتمد على حالة العميل. بعبارة أخرى، إذا كان أحد العملاء
تقرأ /.info/connected
على أنها false، هذا لا
ضمان قراءة عميل منفصل للخطأ أيضًا.
وقت الاستجابة
الطوابع الزمنية للخادم
توفر خوادم Firebase Realtime Database آلية لإدراج
الطوابع الزمنية التي تم إنشاؤها على الخادم كبيانات. وهذه الميزة بالإضافة إلى
onDisconnect
، طريقة سهلة لتدوين الملاحظات بشكل موثوق فيه
الوقت الذي تم فيه قطع اتصال عميل Realtime Database:
Swift
let userLastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline") userLastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())
Objective-C
FIRDatabaseReference *userLastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"]; [userLastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];
انحراف الساعة
في حين أن firebase.database.ServerValue.TIMESTAMP
أكثر بكثير
ودقيقة ومفضلة لمعظم عمليات القراءة/الكتابة،
قد يكون من المفيد أحيانًا تقدير ساعة العميل
في ما يتعلق بخوادم Firebase Realtime Database. إِنْتَ
يمكن إرفاق معاودة الاتصال بالموقع الجغرافي /.info/serverTimeOffset
.
للحصول على القيمة، بالمللي ثانية، التي يستخدمها عملاء Firebase Realtime Database
تضيفه إلى الوقت المحلي المبلّغ عنه (وقت الحقبة بالمللي ثانية) لتقدير
وقت الخادم. لاحظ أن دقة هذه الإزاحة يمكن أن تتأثر
وقت استجابة الشبكة، لذا فهي مفيدة في المقام الأول لاكتشاف
اختلافات كبيرة (أكبر من ثانية واحدة) في وقت الساعة.
Swift
let offsetRef = Database.database().reference(withPath: ".info/serverTimeOffset") offsetRef.observe(.value, with: { snapshot in if let offset = snapshot.value as? TimeInterval { print("Estimated server time in milliseconds: \(Date().timeIntervalSince1970 * 1000 + offset)") } })
Objective-C
FIRDatabaseReference *offsetRef = [[FIRDatabase database] referenceWithPath:@".info/serverTimeOffset"]; [offsetRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { NSTimeInterval offset = [(NSNumber *)snapshot.value doubleValue]; NSTimeInterval estimatedServerTimeMs = [[NSDate date] timeIntervalSince1970] * 1000.0 + offset; NSLog(@"Estimated server time: %0.3f", estimatedServerTimeMs); }];
نموذج تطبيق التواجد
من خلال الجمع بين عمليات قطع الاتصال ومراقبة حالة الاتصال الطوابع الزمنية للخادم، فيمكنك إنشاء نظام تواجد المستخدم. في هذا النظام، يقوم كل مستخدم بتخزين البيانات في موقع قاعدة البيانات للإشارة إلى ما إذا كان عميل واحد (Realtime Database) متصل بالإنترنت. يضبط العملاء هذا الموقع على "صحيح" عندما عند اتصالهم بالإنترنت وبطابع زمني عند قطع الاتصال. هذا الطابع الزمني تشير إلى آخر مرة كان فيها المستخدم المحدد متصلاً بالإنترنت.
تجدر الإشارة إلى أنّ تطبيقك يجب أن يضع عمليات إلغاء الربط في قائمة انتظار قبل أن يبدأ المستخدم وتمييزها عبر الإنترنت، لتجنب أي شروط سباق في حال انعقاد يتم فقدان اتصال الشبكة قبل إرسال كلا الأمرين إلى الخادم.
إليك نظام بسيط لتواجد المستخدم:
Swift
// 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 let myConnectionsRef = Database.database().reference(withPath: "users/morgan/connections") // stores the timestamp of my last disconnect (the last time I was seen online) let lastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline") let connectedRef = Database.database().reference(withPath: ".info/connected") connectedRef.observe(.value, with: { snapshot in // only handle connection established (or I've reconnected after a loss of connection) guard snapshot.value as? Bool ?? false else { return } // add this device to my connections list let con = myConnectionsRef.childByAutoId() // when this device disconnects, remove it. con.onDisconnectRemoveValue() // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition // where you set the user's presence to true and the client disconnects before the // onDisconnect() operation takes effect, leaving a ghost user. // this value could contain info about the device or a timestamp instead of just true con.setValue(true) // when I disconnect, update the last time I was seen online lastOnlineRef.onDisconnectSetValue(ServerValue.timestamp()) })
Objective-C
// 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 FIRDatabaseReference *myConnectionsRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/connections"]; // stores the timestamp of my last disconnect (the last time I was seen online) FIRDatabaseReference *lastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"]; FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"]; [connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { if([snapshot.value boolValue]) { // connection established (or I've reconnected after a loss of connection) // add this device to my connections list FIRDatabaseReference *con = [myConnectionsRef childByAutoId]; // when this device disconnects, remove it [con onDisconnectRemoveValue]; // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition // where you set the user's presence to true and the client disconnects before the // onDisconnect() operation takes effect, leaving a ghost user. // this value could contain info about the device or a timestamp instead of just true [con setValue:@YES]; // when I disconnect, update the last time I was seen online [lastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]]; } }];