事前準備
如要使用 Realtime Database,您必須先完成下列步驟:
註冊 Unity 專案並設定使用 Firebase。
如果 Unity 專案已使用 Firebase,則表示已為 Firebase 註冊及設定。
如果您沒有 Unity 專案,可以下載應用程式示例。
將 Firebase Unity SDK (具體來說是
FirebaseDatabase.unitypackage
) 新增至 Unity 專案。
請注意,將 Firebase 新增至 Unity 專案時,需要在 Firebase 主控台和您開啟的 Unity 專案中執行任務 (例如,從主控台下載 Firebase 設定檔,然後將其移至 Unity 專案)。
儲存資料
將資料寫入 Firebase Realtime Database 的方法有五種:
方法 | 常見的使用方式 |
---|---|
SetValueAsync() |
將資料寫入或取代至定義的路徑 (例如 users/<user-id>/<username> )。 |
SetRawJsonValueAsync() |
使用原始 JSON (例如 users/<user-id>/<username> ) 寫入或取代資料。 |
Push() |
新增至資料清單。每次呼叫 Push() 時,Firebase 都會產生專屬金鑰,這也是可用來做為專屬 ID 的 user-scores/<user-id>/<unique-score-id> 。 |
UpdateChildrenAsync() |
更新已定義路徑的部分金鑰,而不會取代所有資料。 |
RunTransaction() |
更新可能因並行更新而損毀的複雜資料。 |
取得 DatabaseReference
如要將資料寫入資料庫,您需要 DatabaseReference
的例項:
using Firebase; using Firebase.Database; public class MyScript: MonoBehaviour { void Start() { // Get the root reference location of the database. DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference; } }
在參照資料中寫入、更新或刪除資料
基本寫入作業
對於基本的寫入作業,您可以使用 SetValueAsync()
將資料儲存至指定的參照,取代該路徑上的任何現有資料。您可以使用這個方法,傳遞與可用 JSON 類型相對應的類型,如下所示:
string
long
double
bool
Dictionary<string, Object>
List<Object>
如果您使用類型化的 C# 物件,可以使用內建的 JsonUtility.ToJson()
將物件轉換為原始 JSON,然後呼叫 SetRawJsonValueAsync()
。舉例來說,您可能會擁有如下所示的 User 類別:
public class User { public string username; public string email; public User() { } public User(string username, string email) { this.username = username; this.email = email; } }
您可以使用 SetRawJsonValueAsync()
新增使用者,方法如下:
private void writeNewUser(string userId, string name, string email) { User user = new User(name, email); string json = JsonUtility.ToJson(user); mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json); }
以這種方式使用 SetValueAsync()
或 SetRawJsonValueAsync()
會覆寫指定位置的資料,包括任何子項節點。不過,您還是可以更新子項,而不需要重寫整個物件。如果您想允許使用者更新個人資料,可以按照下列方式更新使用者名稱:
mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);
將資料附加至資料清單
使用 Push()
方法,將資料附加至多用戶端應用程式中的清單。每次在指定 Firebase 參照資料中新增子項時,Push()
方法都會產生專屬索引鍵。只要為清單中的每個新元素使用這些自動產生的鍵,多個用戶端就能同時將子項新增至相同位置,而不會發生寫入衝突。Push()
產生的專屬索引是根據時間戳記,因此清單項目會自動依時間先後排序。
您可以使用 Push()
方法傳回的新資料參照,取得子項的自動產生鍵值,或為子項設定資料。對 Push()
參照呼叫 Key
會傳回自動產生鍵的值。
更新特定欄位
如要同時寫入節點的特定子項,而不覆寫其他子項,請使用 UpdateChildrenAsync()
方法。
呼叫 UpdateChildrenAsync()
時,您可以指定索引鍵的路徑,藉此更新較低層級的子項值。如果資料儲存在多個位置,可讓資料更容易擴充,您可以使用資料分支更新該資料的所有例項。舉例來說,遊戲可能會有類似以下的 LeaderboardEntry
類別:
public class LeaderboardEntry { public string uid; public int score = 0; public LeaderboardEntry() { } public LeaderboardEntry(string uid, int score) { this.uid = uid; this.score = score; } public Dictionary<string, Object> ToDictionary() { Dictionary<string, Object> result = new Dictionary<string, Object>(); result["uid"] = uid; result["score"] = score; return result; } }
如要建立 LeaderboardEntry,並同時將其更新至最近分數動態消息和使用者自己的分數清單,遊戲會使用以下程式碼:
private void WriteNewScore(string userId, int score) { // Create new entry at /user-scores/$userid/$scoreid and at // /leaderboard/$scoreid simultaneously string key = mDatabase.Child("scores").Push().Key; LeaderBoardEntry entry = new LeaderBoardEntry(userId, score); Dictionary<string, Object> entryValues = entry.ToDictionary(); Dictionary<string, Object> childUpdates = new Dictionary<string, Object>(); childUpdates["/scores/" + key] = entryValues; childUpdates["/user-scores/" + userId + "/" + key] = entryValues; mDatabase.UpdateChildrenAsync(childUpdates); }
本範例使用 Push()
在節點中建立項目,其中包含 /scores/$key
上所有使用者的項目,並同時使用 Key
擷取金鑰。接著,您可以使用這個鍵,在使用者的分數 /user-scores/$userid/$key
中建立第二個項目。
透過這些路徑,您可以透過一次呼叫 UpdateChildrenAsync()
來同時更新 JSON 樹狀結構中的多個位置,例如這個範例如何在兩個位置建立新項目。以這種方式進行的同時更新作業是不可分割的:所有更新都成功或都失敗。
刪除資料
刪除資料最簡單的方法,就是在資料位置的參照上呼叫 RemoveValue()
。
您也可以將 null
指定為其他寫入作業 (例如 SetValueAsync()
或 UpdateChildrenAsync()
) 的值,藉此刪除資料。您可以將這項技巧與 UpdateChildrenAsync()
搭配使用,在單一 API 呼叫中刪除多個子項。
掌握資料提交的時間。
如要瞭解資料何時提交至 Firebase Realtime Database 伺服器,您可以新增接續。SetValueAsync()
和 UpdateChildrenAsync()
都會傳回 Task
,讓您瞭解作業何時完成。如果呼叫因任何原因失敗,Tasks IsFaulted
會設為 true,並使用 Exception
屬性指出失敗的原因。
將資料儲存為交易
如果要處理可能因並行修改而毀損的資料 (例如遞增計數器),您可以使用交易作業。您可以為這項作業提供 Func
。這個更新 Func
會將資料的目前狀態做為引數,並傳回您要寫入的新狀態。如果其他用戶端在您成功寫入新值之前寫入該位置,系統會再次以新的目前值呼叫更新函式,並重試寫入作業。
舉例來說,您可以在遊戲中允許使用者更新排行榜,顯示前五名最高分:
private void AddScoreToLeaders(string email, long score, DatabaseReference leaderBoardRef) { leaderBoardRef.RunTransaction(mutableData => { List<object> leaders = mutableData.Value as List<object> if (leaders == null) { leaders = new List<object>(); } else if (mutableData.ChildrenCount >= MaxScores) { long minScore = long.MaxValue; object minVal = null; foreach (var child in leaders) { if (!(child is Dictionary<string, object>)) continue; long childScore = (long) ((Dictionary<string, object>)child)["score"]; if (childScore < minScore) { minScore = childScore; minVal = child; } } if (minScore > score) { // The new score is lower than the existing 5 scores, abort. return TransactionResult.Abort(); } // Remove the lowest score. leaders.Remove(minVal); } // Add the new high score. Dictionary<string, object> newScoreMap = new Dictionary<string, object>(); newScoreMap["score"] = score; newScoreMap["email"] = email; leaders.Add(newScoreMap); mutableData.Value = leaders; return TransactionResult.Success(mutableData); }); }
如果有多位使用者同時記錄分數,或是用戶端有過時資料,使用交易可避免排行榜出現錯誤。如果交易遭到拒絕,伺服器會將目前的值傳回給用戶端,後者會使用更新後的值再次執行交易。這項作業會重複執行,直到交易獲得接受或嘗試次數過多為止。
離線寫入資料
如果用戶端失去網路連線,應用程式仍會繼續正常運作。
每個連線至 Firebase 資料庫的用戶端都會維護任何有效資料的內部版本。資料寫入時,系統會先將資料寫入這個本機版本。接著,Firebase 用戶端會以「盡力而為」的方式,將這些資料與遠端資料庫伺服器和其他用戶端同步。
因此,所有寫入資料庫的作業都會立即觸發本機事件,然後才將任何資料寫入伺服器。也就是說,無論網路延遲或連線狀況為何,應用程式都能持續回應。
重新建立連線後,應用程式會收到適當的事件組合,讓用戶端與目前的伺服器狀態保持同步,而無需撰寫任何自訂程式碼。