לפני שמתחילים
לפני שתוכלו להשתמש ב-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 יוצר מפתח ייחודי שאפשר להשתמש בו גם כמזהה ייחודי, כמו 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 הזמינים, באופן הבא:
stringlongdoubleboolDictionary<string, Object>List<Object>
אם משתמשים באובייקט C# עם סוג, אפשר להשתמש ב-JsonUtility.ToJson() המובנה כדי להמיר את האובייקט ל-JSON גולמי ולקרוא ל-SetRawJsonValueAsync().
לדוגמה, יכול להיות שיש לכם מחלקת משתמש שנראית כך:
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);
הוספה לרשימת נתונים
משתמשים ב-method Push() כדי להוסיף נתונים לרשימה באפליקציות עם כמה משתמשים.
השיטה Push() יוצרת מפתח ייחודי בכל פעם שנוסף צאצא חדש להפניה שצוינה ב-Firebase. כשמשתמשים במפתחות שנוצרים אוטומטית לכל רכיב חדש ברשימה, כמה לקוחות יכולים להוסיף צאצאים לאותו מיקום בו-זמנית בלי התנגשויות כתיבה. המפתח הייחודי שנוצר על ידי Push() מבוסס על חותמת זמן, כך שהפריטים ברשימה מסודרים באופן אוטומטי בסדר כרונולוגי.
אתם יכולים להשתמש בהפניה לנתונים החדשים שהוחזרו על ידי השיטה Push() כדי לקבל את הערך של המפתח שנוצר באופן אוטומטי של הצאצא, או להגדיר נתונים לצאצא. קריאה ל-Key בהפניה ל-Push() מחזירה את הערך של המפתח שנוצר אוטומטית.
עדכון שדות ספציפיים
כדי לכתוב בו-זמנית לצמתים צאצאים ספציפיים של צומת בלי להחליף צמתים צאצאים אחרים, משתמשים בשיטה 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.
באמצעות הנתיבים האלה, אפשר לבצע עדכונים בו-זמנית בכמה מיקומים בעץ ה-JSON באמצעות קריאה אחת ל-UpdateChildrenAsync(), כמו בדוגמה הזו שבה נוצרת הרשומה החדשה בשני המיקומים. עדכונים בו-זמניים שמתבצעים בדרך הזו הם אטומיים: או שכל העדכונים מצליחים או שכולם נכשלים.
מחיקת נתונים
הדרך הפשוטה ביותר למחוק נתונים היא להפעיל את RemoveValue() בהפניה למיקום של הנתונים האלה.
אפשר גם למחוק על ידי ציון null כערך לפעולת כתיבה אחרת, כמו SetValueAsync() או UpdateChildrenAsync(). אפשר להשתמש בשיטה הזו עם UpdateChildrenAsync() כדי למחוק כמה צאצאים בקריאה אחת ל-API.
איך יודעים שהנתונים נשמרו.
כדי לדעת מתי הנתונים נשמרים בשרת Firebase Realtime Database, אפשר להוסיף המשך. גם SetValueAsync() וגם UpdateChildrenAsync() מחזירים Task שמאפשר לדעת מתי הפעולה הושלמה. אם הקריאה נכשלת מסיבה כלשהי, המאפיין 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 מסנכרן את הנתונים האלה עם שרתי מסד הנתונים המרוחקים ועם לקוחות אחרים על בסיס "המאמץ המרבי".
כתוצאה מכך, כל הכתיבות למסד הנתונים מפעילות אירועים מקומיים באופן מיידי, לפני שנתונים כלשהם נכתבים בשרת. זה אומר שהאפליקציה תמשיך להגיב, בלי קשר לזמן האחזור או לקישוריות של הרשת.
אחרי שהקישוריות נוצרת מחדש, האפליקציה מקבלת את קבוצת האירועים המתאימה כדי שהלקוח יסתנכרן עם מצב השרת הנוכחי, בלי שתצטרכו לכתוב קוד בהתאמה אישית.