Zanim zaczniesz
Zanim użyjesz Realtime Database, musisz:
Zarejestruj projekt Unity i skonfiguruj go tak, aby używał Firebase.
Jeśli Twój projekt w Unity korzysta już z Firebase, jest już zarejestrowany i skonfigurowany pod kątem tej usługi.
Jeśli nie masz projektu Unity, możesz pobrać próbną aplikację.
Dodaj pakiet SDK Firebase Unity (szczególnie plik
FirebaseDatabase.unitypackage
) do projektu Unity.
Pamiętaj, że dodanie Firebase do projektu Unity wymaga wykonania zadań zarówno w konsoli Firebase, jak i w otwartym projekcie Unity (np. musisz pobrać pliki konfiguracyjne Firebase z konsoli, a następnie przenieść je do projektu Unity).
Zapisywanie danych
Istnieje pięć metod zapisu danych w Firebase Realtime Database:
Metoda | Typowe zastosowania |
---|---|
SetValueAsync() |
zapisywać lub zastępować dane w określonej ścieżce, takiej jak users/<user-id>/<username> . |
SetRawJsonValueAsync() |
Zapisz lub zastąp dane nieprzetworzonym kodem JSON, np. users/<user-id>/<username> . |
Push() |
Dodaj do listy danych. Za każdym razem, gdy wywołujesz funkcję Push() , Firebase generuje unikalny klucz, którego można też używać jako unikalnego identyfikatora, np. user-scores/<user-id>/<unique-score-id> . |
UpdateChildrenAsync() |
Zaktualizuj niektóre klucze dla zdefiniowanej ścieżki bez zastępowania wszystkich danych. |
RunTransaction() |
Aktualizuj złożone dane, które mogą ulec uszkodzeniu w wyniku równoczesnych aktualizacji. |
Pobieranie obiektu DatabaseReference
Aby zapisać dane w bazie danych, potrzebujesz instancji 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; } }
zapisywać, aktualizować i usuwać dane w referencji;
Podstawowe operacje zapisu
W przypadku podstawowych operacji zapisu możesz użyć funkcji SetValueAsync()
, aby zapisać dane w określonym odwołaniu, zastępując wszystkie istniejące dane na tej ścieżce. Za pomocą tej metody możesz przekazywać typy odpowiadające dostępnym typom JSON w ten sposób:
string
long
double
bool
Dictionary<string, Object>
List<Object>
Jeśli używasz typowanego obiektu C#, możesz użyć wbudowanej funkcji JsonUtility.ToJson()
do konwertowania obiektu na surowy JSON i wywołania funkcji SetRawJsonValueAsync()
.
Możesz na przykład mieć klasę użytkownika podobną do tej:
public class User { public string username; public string email; public User() { } public User(string username, string email) { this.username = username; this.email = email; } }
Aby dodać użytkownika z uprawnieniami SetRawJsonValueAsync()
, wykonaj te czynności:
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); }
Użycie w ten sposób wartości SetValueAsync()
lub SetRawJsonValueAsync()
spowoduje zastąpienie danych w wybranej lokalizacji, w tym wszystkich węzłów podrzędnych. Nadal możesz jednak aktualizować obiekt podrzędny bez konieczności przepisywania całego obiektu. Jeśli chcesz zezwolić użytkownikom na aktualizowanie swoich profili, możesz zaktualizować nazwę użytkownika w ten sposób:
mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);
Dołączanie do listy danych
Aby dołączać dane do listy w aplikacji wielostanowiskowej, użyj metody Push()
.
Metoda Push()
generuje unikalny klucz za każdym razem, gdy do określonego odwołania Firebase jest dodawany nowy element podrzędny. Dzięki użyciu tych automatycznie generowanych kluczy dla każdego nowego elementu na liście kilku klientów może dodawać elementy podrzędne do tej samej lokalizacji w tym samym czasie bez konfliktów zapisu. Unikalny klucz wygenerowany przez funkcję Push()
jest oparty na sygnaturze czasowej, więc elementy listy są automatycznie sortowane chronologicznie.
Możesz użyć odwołania do nowych danych zwróconych przez metodę Push()
, aby uzyskać wartość automatycznie wygenerowanego klucza wydawcy podrzędnego lub ustawić dane dla elementu podrzędnego. Wywołanie funkcji Key
w przypadku odwołania Push()
zwraca wartość klucza wygenerowanego automatycznie.
Aktualizowanie konkretnych pól
Aby jednocześnie zapisywać dane w określonych węzłach podrzędnych węzła bez zastępowania innych węzłów podrzędnych, użyj metody UpdateChildrenAsync()
.
Podczas wywoływania funkcji UpdateChildrenAsync()
możesz aktualizować wartości podrzędne niższego poziomu, podając ścieżkę klucza. Jeśli dane są przechowywane w kilku lokalizacjach, aby zapewnić lepszą skalowalność, możesz zaktualizować wszystkie wystąpienia tych danych za pomocą rozgałęzienia danych. Na przykład gra może mieć klasę LeaderboardEntry
, która wygląda tak:
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; } }
Aby utworzyć pozycję na tablicy wyników i jednocześnie zaktualizować ją w pliku danych o ostatnich wynikach oraz na liście wyników użytkownika, gra używa takiego kodu:
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); }
W tym przykładzie element Push()
służy do utworzenia wpisu w węźle zawierającym wpisy wszystkich użytkowników w węźle /scores/$key
i jednoczesnego pobrania klucza za pomocą elementu Key
. Klucz można następnie wykorzystać do utworzenia drugiego wpisu w tablicy wyników użytkownika na stronie /user-scores/$userid/$key
.
Za pomocą tych ścieżek możesz aktualizować wiele lokalizacji w drzewie JSON za pomocą jednego wywołania UpdateChildrenAsync()
, na przykład w jaki sposób ten przykład tworzy nowy wpis w obu lokalizacjach. Jednoczesne aktualizacje w ten sposób są atomowe: albo wszystkie się powiodą, albo wszystkie się nie powiodą.
Usuń dane
Najprostszym sposobem usuwania danych jest wywołanie funkcji RemoveValue()
z odniesieniem do lokalizacji tych danych.
Możesz też usunąć wartość, podając null
jako wartość dla innej operacji zapisu, takiej jak SetValueAsync()
lub UpdateChildrenAsync()
. Możesz użyć tej metody razem z UpdateChildrenAsync()
, aby usunąć wiele elementów podrzędnych w jednym wywołaniu interfejsu API.
Dowiedz się, kiedy Twoje dane są zapisywane.
Aby dowiedzieć się, kiedy Twoje dane zostaną zapisane na serwerze Firebase Realtime Database, możesz dodać kontynuację. Zarówno SetValueAsync()
, jak i UpdateChildrenAsync()
zwracają wartość Task
, która informuje o zakończeniu operacji. Jeśli wywołanie zakończy się niepowodzeniem z jakiegokolwiek powodu, w elementach zadań IsFaulted
będzie ustawiona wartość true, a w elementach Exception
– wartość wskazująca przyczynę niepowodzenia.
Zapisywanie danych jako transakcji
Podczas pracy z danymi, które mogą zostać uszkodzone przez równoległe modyfikacje, np. z licznikami przyrostowymi, możesz użyć operacji transakcji.
Operacja ta ma nazwę Func
. Ta aktualizacja Func
przyjmuje jako argument bieżący stan danych i zwraca nowy stan, który chcesz zapisać. Jeśli inny klient zapisze w tej lokalizacji nową wartość, zanim uda się zapisać Twoją nową wartość, funkcja aktualizacji zostanie wywołana ponownie z nową bieżącą wartością i ponownie spróbuje zapisać dane.
Na przykład w grze możesz zezwolić użytkownikom na aktualizowanie tabeli z 5 najwyższymi wynikami:
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); }); }
Użycie transakcji zapobiega nieprawidłowej tablicy wyników, jeśli w tym samym czasie wielu użytkowników rejestruje swoje wyniki lub klient ma nieaktualne dane. W przypadku odrzucenia transakcji serwer zwraca bieżącą wartość klientowi, który uruchamia transakcję ponownie ze zaktualizowaną wartością. Ta procedura jest powtarzana, dopóki transakcja nie zostanie zaakceptowana lub nie zostanie podjęta zbyt duża liczba prób.
Zapisuj dane offline
Jeśli klient utraci połączenie z siecią, Twoja aplikacja będzie nadal działać prawidłowo.
Każdy klient połączony z bazą danych Firebase utrzymuje własną wersję wewnętrzną wszystkich aktywnych danych. Podczas zapisywania danych są one najpierw zapisywane w tej wersji lokalnej. Klient Firebase synchronizuje te dane ze zdalnymi serwerami baz danych i innymi klientami w ramach najlepszych starań.
W rezultacie wszystkie zapisy w bazie danych powodują natychmiastowe wywołanie zdarzeń lokalnych, zanim jakiekolwiek dane zostaną zapisane na serwerze. Oznacza to, że aplikacja pozostaje responsywna niezależnie od opóźnień w sieci lub połączenia.
Po ponownym nawiązaniu połączenia aplikacja otrzymuje odpowiedni zestaw zdarzeń, dzięki czemu klient synchronizuje się z bieżącym stanem serwera, bez konieczności pisania kodu niestandardowego.