قبل البدء
قبل أن تتمكّن من استخدام Realtime Database, عليك تنفيذ ما يلي:
سجِّل مشروع Unity الخاص بك وأعدَّه لاستخدام Firebase.
إذا كان مشروع Unity يستخدم Firebase حاليًا، يكون قد تم تسجيله وإعداده لاستخدام Firebase.
إذا لم يكن لديك مشروع Unity، يمكنك تنزيل نموذج تطبيق.
أضِف حزمة Firebase Unity SDK (تحديدًا
FirebaseDatabase.unitypackage) إلى مشروع Unity الخاص بك.
يُرجى العِلم أنّ إضافة Firebase إلى مشروع Unity تتضمّن مهامًا في كلّ من الـ Firebase console ومشروع 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:
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);
إلحاق البيانات بقائمة
استخدِم طريقة 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() لحذف عدة عقد فرعية في طلب واجهة برمجة تطبيقات واحد.
معرفة متى يتم تنفيذ التغييرات على بياناتك
لمعرفة متى يتم تنفيذ التغييرات على بياناتك في Firebase Realtime Database، يمكنك إضافة استمرار. تعرِض كلّ من SetValueAsync() وUpdateChildrenAsync() عنصر Task يتيح لك معرفة متى تكتمل العملية. إذا لم ينجح الاستدعاء لأي سبب، ستكون قيمة IsFaulted في `Tasks` صحيحة، وستشير السمة 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 هذه البيانات مع خوادم قاعدة البيانات البعيدة ومع العملاء الآخرين على أساس "أفضل جهد".
نتيجةً لذلك، تؤدي جميع عمليات الكتابة في قاعدة البيانات إلى إطلاق أحداث محلية على الفور، قبل كتابة أي بيانات على الخادم. وهذا يعني أنّ تطبيقك يظل سريع الاستجابة بغض النظر عن وقت استجابة الشبكة أو الاتصال.
بمجرد استعادة الاتصال، يتلقّى تطبيقك المجموعة المناسبة من الأحداث حتى تتم مزامنة العميل مع حالة الخادم الحالية، بدون الحاجة إلى كتابة أي رمز مخصّص.