แอปพลิเคชัน Firebase จะทำงานได้แม้แอปของคุณจะสูญเสียเครือข่ายชั่วคราว การเชื่อมต่อ นอกจากนี้ Firebase ยังมีเครื่องมือสำหรับ การยืนยันข้อมูลภายในเครื่อง ในการจัดการการตรวจหาบุคคลในบ้าน และการจัดการกับเวลาในการตอบสนอง
ความต่อเนื่องของดิสก์
แอป Firebase จะจัดการการหยุดชะงักของเครือข่ายชั่วคราวโดยอัตโนมัติ ข้อมูลแคชจะใช้งานได้ขณะที่ออฟไลน์และ Firebase จะส่งการเขียนซ้ำ เมื่อการเชื่อมต่อเครือข่ายกลับมาทำงานอีกครั้ง
เมื่อคุณเปิดใช้การคงอยู่ของดิสก์ แอปจะเขียนข้อมูลภายในเครื่องไปยัง อุปกรณ์ของคุณเพื่อให้แอปรักษาสถานะขณะออฟไลน์ได้แม้ว่าผู้ใช้จะ หรือระบบปฏิบัติการรีสตาร์ทแอป
คุณเปิดใช้การคงอยู่ของดิสก์ได้ด้วยโค้ดเพียงบรรทัดเดียว
Swift
Database.database().isPersistenceEnabled = true
Objective-C
[FIRDatabase database].persistenceEnabled = YES;
พฤติกรรมอย่างต่อเนื่อง
เมื่อเปิดใช้การถาวร ข้อมูลทั้งหมดที่ไคลเอ็นต์ Firebase Realtime Database จะซิงค์ขณะที่ออนไลน์ยังคงอยู่ที่ดิสก์และพร้อมใช้งานแบบออฟไลน์ แม้ว่าผู้ใช้หรือระบบปฏิบัติการจะรีสตาร์ทแอปก็ตาม ซึ่งหมายความว่า แอปพลิเคชันจะทำงานเช่นเดียวกับที่ออนไลน์โดยใช้ข้อมูลในตัวเครื่องที่จัดเก็บในแคช Callback ของผู้ฟังจะยังคงเริ่มทำงานต่อไปเพื่ออัปเดตในพื้นที่
ไคลเอ็นต์ 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 MB ควรเป็น เพียงพอสำหรับแอปพลิเคชันส่วนใหญ่ หากแคชมีขนาดใหญ่กว่าขนาดที่กำหนดค่าไว้ Firebase Realtime Database จะล้างข้อมูลที่ใช้ล่าสุดออกถาวร โดยข้อมูลที่ซิงค์ไว้จะไม่ถูกลบออกจากแคชถาวร
การค้นหาข้อมูลแบบออฟไลน์
Firebase Realtime Database จัดเก็บข้อมูลที่แสดงผลจากการค้นหาสำหรับการใช้งาน เมื่อออฟไลน์ สำหรับการค้นหาที่สร้างขึ้นขณะออฟไลน์ Firebase Realtime Database จะยังคงทำงานต่อไปสำหรับข้อมูลที่โหลดก่อนหน้านี้ หากข้อมูลที่ขอไม่โหลด Firebase Realtime Database จะโหลด จากแคชในเครื่อง เมื่อการเชื่อมต่อเครือข่ายใช้งานได้อีกครั้ง จะโหลดข้อมูลและจะแสดงการค้นหา
ตัวอย่างเช่น โค้ดนี้จะสอบถามถึงพารามิเตอร์ 4 รายการใน 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); }];
สมมติว่าผู้ใช้ขาดการเชื่อมต่อ ออฟไลน์ และรีสตาร์ทแอป ขณะที่ออฟไลน์ แอปจะค้นหาสำหรับ 2 รายการสุดท้ายจาก สถานที่เดียวกัน การค้นหานี้จะแสดง 2 รายการสุดท้ายได้สำเร็จ เพราะแอปโหลดขึ้นมาทั้ง 4 รายการในการค้นหาด้านบน
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 เพิ่ม "เพิ่มเด็ก" เหตุการณ์สำหรับไดโนเสาร์ 2 ตัวที่ทำคะแนนสูงสุดโดยใช้ แคชที่เก็บไว้ แต่จะไม่เพิ่ม "ค่า" เนื่องจากแอป ไม่เคยดำเนินการค้นหานั้นขณะที่ออนไลน์
หากแอปจะขอรายการ 6 รายการล่าสุดขณะออฟไลน์ "เพิ่มเด็ก" เหตุการณ์ของทั้ง 4 รายการที่แคชไว้ได้ทันที เมื่อ อุปกรณ์กลับมาออนไลน์อีกครั้ง ไคลเอ็นต์ Firebase Realtime Database จะซิงค์ กับเซิร์ฟเวอร์ แล้วส่ง "เพิ่มเด็ก" 2 คนสุดท้าย และ "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!"];
วิธีการทำงานของการยกเลิกการเชื่อมต่อ
เมื่อคุณสร้างการดำเนินการ onDisconnect()
อยู่ที่เซิร์ฟเวอร์ Firebase Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัยเพื่อ
ตรวจสอบว่าผู้ใช้สามารถทำกิจกรรมการเขียนตามที่ขอได้ แล้วแจ้งข้อมูล
แอปของคุณหากไม่ถูกต้อง จากนั้นเซิร์ฟเวอร์
ติดตามดูการเชื่อมต่อ หากการเชื่อมต่ออินเทอร์เน็ตหมดเวลา หรือ
มีการปิดอย่างต่อเนื่องโดยไคลเอ็นต์ Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัย
ครั้งที่ 2 (เพื่อให้มั่นใจว่าการดำเนินการยังคงถูกต้อง) แล้วจึงเรียกใช้
กิจกรรมนั้น
แอปของคุณสามารถใช้ Callback ในการดำเนินการเขียน
เพื่อตรวจสอบว่าการแนบ 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 คุณ
สามารถแนบ Callback ไปยังตำแหน่ง /.info/serverTimeOffset
เพื่อรับค่าเป็นมิลลิวินาทีที่ไคลเอ็นต์ Firebase Realtime Database
เพิ่มลงในเวลาที่รายงานในท้องถิ่น (เวลา Epoch ในหน่วยมิลลิวินาที) เพื่อประมาณการ
เวลาของเซิร์ฟเวอร์ โปรดทราบว่าความแม่นยำของออฟเซ็ตนี้อาจได้รับผลกระทบจาก
เวลาในการตอบสนองของเครือข่าย และ มีประโยชน์สำหรับการค้นพบ
เวลาของนาฬิกามีความคลาดเคลื่อนมาก (> 1 วินาที)
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]]; } }];