Apple 平台上的離線功能

即使應用程式暫時遺失網路,Firebase 應用程式仍可正常運作 以獲得最佳效能和最安全的連線此外,Firebase 還提供可在本機保存資料的工具, 管理狀態及處理延遲情形

磁碟持續性

Firebase 應用程式會自動處理暫時的網路中斷問題。 離線時可存取快取資料,Firebase 會重新傳送任何寫入作業 並在恢復網路連線時執行動作

啟用磁碟持續性功能後,應用程式會將資料寫入本機 讓應用程式即使處於離線狀態,也能在離線時保持狀態 或是作業系統重新啟動應用程式

只需加入一行程式碼,即可啟用磁碟持續性。

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
Database.database().isPersistenceEnabled = true

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[FIRDatabase database].persistenceEnabled = YES;

持續性行為

啟用保存功能後,Firebase 即時資料庫用戶端的所有資料都會啟用保留功能 會在線上留存於磁碟且可以離線時同步處理, 即使使用者或作業系統重新啟動應用程式也就是說, 透過儲存在快取中的本機資料,如線上般運作。 若是本機更新,則會繼續觸發接聽程式回呼。

Firebase 即時資料庫用戶端會自動保留所有佇列 在應用程式離線時執行的寫入作業。 啟用持續性時,此佇列也會被保存到磁碟中, 使用者可以使用 會重新啟動應用程式。應用程式重新連上網路後, 並將作業傳送至 Firebase 即時資料庫伺服器

如果應用程式使用 Firebase 驗證 Firebase 即時資料庫用戶端會保留使用者的驗證設定 符記 如果驗證權杖在應用程式離線時到期,用戶端會暫停 寫入作業,直到應用程式重新驗證使用者為止,否則 寫入作業可能會因安全性規則而失敗。

持續更新資料

Firebase 即時資料庫會同步處理並儲存 有效的事件監聽器資料另外,您可以保留特定位置 同步。

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
let scoresRef = Database.database().reference(withPath: "scores")
scoresRef.keepSynced(true)

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"];
[scoresRef keepSynced:YES];

Firebase 即時資料庫用戶端會自動下載 並保持工作表的一致性,即使參照沒有 有效的事件監聽器您可以使用 導入的功能

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
scoresRef.keepSynced(false)

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[scoresRef keepSynced:NO];

根據預設,系統會快取先前同步處理資料的 10 MB。這應該是 可滿足大多數應用程式的需求如果快取超過設定的大小 Firebase 即時資料庫會清除近期至少使用過的資料。 已同步的資料不會從快取中清除。

離線查詢資料

Firebase 即時資料庫儲存查詢傳回的資料,以供使用 就能離線使用對於在離線狀態下建立的查詢 Firebase 即時資料庫仍會繼續處理先前載入的資料。 如果要求的資料尚未載入,Firebase 即時資料庫會載入 擷取自本機快取的資料網路連線恢復後 系統就會載入資料並顯示查詢

舉例來說,這段程式碼會查詢 Firebase 即時分數資料庫中的四個項目

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
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

注意:這項 Firebase 產品不適用於 App Clip 目標。
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

注意:這項 Firebase 產品不適用於 App Clip 目標。
scoresRef.queryOrderedByValue().queryLimited(toLast: 2).observe(.childAdded) { snapshot in
  print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")")
}

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[[[scoresRef queryOrderedByValue] queryLimitedToLast:2]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
      NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value);
    }];

在上述範例中,Firebase 即時資料庫用戶端 「已新增子項」取得分數最高的兩隻恐龍 因此能保留快取狀態但不會產生因為應用程式含有 從未在連線時執行該查詢。

如果應用程式在離線時要求最後六個項目,則會傳回 「已新增子項」即可立即瞭解四個快取項目的事件當 裝置恢復連線後,Firebase 即時資料庫用戶端 與伺服器通訊,並得到最後兩個「新增子項」和 「value」事件。

離線處理交易

凡是在應用程式離線時執行的交易,都會排入佇列。 應用程式重新連上網路後,系統就會將交易傳送至 即時資料庫伺服器

管理在家狀態

在即時應用程式中,建議偵測用戶端 。例如,你可以設定 想將使用者標示為「離線」當用戶端中斷連線時。

Firebase 資料庫用戶端提供簡易基本功能,可協助您 用戶端與 Firebase 資料庫中斷連線時,會寫入資料庫 伺服器無論用戶端是否完全中斷連線,都會執行這些更新。 因此即使連線中斷,您依然可以用它們清理資料 或用戶端停止運作所有寫入作業,包括設定 並在連線中斷時執行更新、移除、移除等動作。

以下是在連線中斷時,使用 onDisconnect 原始版本:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
let presenceRef = Database.database().reference(withPath: "disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnectSetValue("I disconnected!")

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
FIRDatabaseReference *presenceRef = [[FIRDatabase database] referenceWithPath:@"disconnectmessage"];
// Write a string when this client loses connection
[presenceRef onDisconnectSetValue:@"I disconnected!"];

如何中斷連線

建立 onDisconnect() 作業時,作業 位於 Firebase 即時資料庫伺服器中伺服器會檢查 確保使用者可以執行要求的寫入事件,並通知 失效的應用程式。接著,伺服器 它會監控連線狀態如果連線逾時,或 就會由即時資料庫用戶端主動關閉,伺服器則會檢查安全 次 (以確保作業仍然有效) 時,請叫用 活動。

應用程式可在寫入作業中使用回呼 確認 onDisconnect 已正確連接:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
presenceRef.onDisconnectRemoveValue { error, reference in
  if let error = error {
    print("Could not establish onDisconnect event: \(error)")
  }
}

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[presenceRef onDisconnectRemoveValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *reference) {
  if (error != nil) {
    NSLog(@"Could not establish onDisconnect event: %@", error);
  }
}];

您也可以呼叫 .cancel() 來取消 onDisconnect 事件:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
presenceRef.onDisconnectSetValue("I disconnected")
// some time later when we change our minds
presenceRef.cancelDisconnectOperations()

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
[presenceRef onDisconnectSetValue:@"I disconnected"];
// some time later when we change our minds
[presenceRef cancelDisconnectOperations];

偵測連線狀態

對許多狀態相關功能而言,這對應用程式來說很實用 得知裝置是否連上網路Firebase 即時資料庫 提供位於/.info/connected的特殊地點 每次 Firebase 即時資料庫用戶端的連線狀態時,都會更新 並輸入變更內容範例如下:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
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

注意:這項 Firebase 產品不適用於 App Clip 目標。
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 是不是布林值 因為值是 視用戶端的狀態而定。換句話說,如果單一用戶端 讀取 /.info/connected 為 false,這不會 確保個別用戶端也會讀取 false。

處理延遲時間

伺服器時間戳記

Firebase 即時資料庫伺服器提供插入 在伺服器上產生的資料時間戳記 (以資料形式呈現)。這項功能結合了 onDisconnect,可讓您輕鬆可靠地記錄 即時資料庫用戶端中斷連線的時間:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
let userLastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline")
userLastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())

Objective-C

注意:這項 Firebase 產品不適用於 App Clip 目標。
FIRDatabaseReference *userLastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"];
[userLastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];

時鐘偏差

firebase.database.ServerValue.TIMESTAMP 不僅止於此 準確且適合大多數讀取/寫入作業 這也有助於估算客戶的時鐘偏差 對應至 Firebase 即時資料庫伺服器個人中心 可將回呼附加至位置 /.info/serverTimeOffset 以便取得 Firebase 即時資料庫用戶端的值 (以毫秒為單位) 與當地回報時間相加 (以毫秒為單位),進行估算 伺服器時間請注意,位移的精確度會受到 因此非常適合用於探索網路延遲 時鐘時間出現明顯差異 (> 1 秒)。

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
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

注意:這項 Firebase 產品不適用於 App Clip 目標。
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);
}];

範例在家狀態應用程式

結合連線作業與連線狀態監控 您可以建構使用者連接系統。在這個系統中 每位使用者將資料儲存在資料庫位置,指出 即時資料庫用戶端已連線。用戶端在下列情況會將這個位置設為 true 以及連線中斷時的時間戳記。這個時間戳記 表示特定使用者上次上線的時間。

請注意,應用程式應在使用者中斷連線前,將中斷作業排入佇列 線上標記,以避免客戶的 在能將兩個指令傳送至伺服器之前,網路連線中斷。

這類簡易的使用者線上狀態系統如下:

Swift

注意:這項 Firebase 產品不適用於 App Clip 目標。
// 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

注意:這項 Firebase 產品不適用於 App Clip 目標。
// 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]];
  }
}];