فهم أعطال إحدى ألعاب Unity باستخدام ميزات Crashlytics المتقدّمة

1- مقدمة

في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استخدام الميزات المتقدّمة في Crashlytics التي ستمنحك نظرة أفضل على الأعطال والظروف التي قد تكون تسببت فيها.

ستضيف وظيفة جديدة إلى نموذج لعبة، MechaHamster: Level Up with Firebase Edition. هذه اللعبة النموذجية هي إصدار جديد من لعبة Firebase الكلاسيكية MechaHamster التي تزيل معظم وظائف Firebase المدمجة، ما يتيح لك إمكانية تنفيذ استخدامات جديدة لمنصة Firebase بدلاً منها.

ستضيف قائمة تصحيح أخطاء إلى اللعبة. تستدعي قائمة تصحيح الأخطاء هذه الطرق التي ستنشئها وتسمح لك بممارسة الوظائف المختلفة لتطبيق Crashlytics. ستوضّح لك هذه الطرق كيفية إضافة تعليقات توضيحية إلى تقارير الأعطال التلقائية باستخدام مفاتيح مخصّصة وسجلّات مخصّصة وأخطاء غير فادحة وغيرها.

بعد إنشاء اللعبة، ستستخدم قائمة تصحيح الأخطاء، وستطّلع على النتائج لفهم طريقة العرض الفريدة التي تتيحها لعبتك،

المعلومات التي ستطّلع عليها

  • أنواع الأخطاء التي يتم رصدها تلقائيًا بواسطة Crashlytics.
  • الأخطاء الإضافية التي يمكن تسجيلها عن قصد.
  • كيفية إضافة المزيد من المعلومات إلى هذه الأخطاء لتسهيل فهمها.

المتطلبات

  • Unity (الحد الأدنى الموصى به للإصدار 2019 والإصدارات الأحدث) مع أحد الإصدارين التاليَين أو كليهما:
    • دعم إصدار iOS
    • دعم إصدار Android
  • (لأجهزة Android فقط) واجهة سطر الأوامر في Firebase (المستخدَمة لتحميل الرموز لتقارير الأعطال)

2- إعداد بيئة التطوير

توضّح الأقسام التالية كيفية تنزيل رمز المستوى الأعلى باستخدام Firebase وفتحه في Unity.

تجدر الإشارة إلى أنّ نموذج لعبة الانتقال باستخدام Firebase هذا يتم استخدامه في العديد من الدروس التطبيقية الأخرى حول الترميز في Firebase وUnity، لذلك يُحتمل أن تكون قد أكملت المهام الواردة في هذا القسم. في هذه الحالة، يمكنك الانتقال مباشرةً إلى الخطوة الأخيرة في هذه الصفحة: "إضافة حِزم تطوير البرامج (SDK) لمنصة Firebase لبرنامج Unity".

تنزيل الرمز

استنسِخ مستودع GitHub في هذا الدرس التطبيقي من سطر الأوامر:

git clone https://github.com/firebase/level-up-with-firebase.git

يمكنك بدلاً من ذلك تنزيل المستودع كملف ZIP إذا لم يكن git مثبّتًا لديك.

افتح level Up باستخدام Firebase في محرِّر Unity

  1. افتح Unity Hub، ومن علامة التبويب المشاريع، انقر على سهم القائمة المنسدلة بجانب فتح.
  2. انقر على إضافة مشروع من القرص.
  3. انتقِل إلى الدليل الذي يحتوي على الرمز، ثم انقر على حسنًا.
  4. اختَر إصدار محرِّر Unity لاستخدامه والنظام الأساسي المستهدَف (Android أو iOS)، إذا طُلب منك ذلك.
  5. انقر على اسم المشروع، level-up-with-firebase، وسيتم فتح المشروع في محرِّر Unity.
  6. إذا لم يفتح المحرّر تلقائيًا، افتح MainGameScene في مواد العرض >. همستر في علامة التبويب المشروع في Unity Editor.
    ff4ea3f3c0d29379.png

لمزيد من المعلومات حول تثبيت Unity واستخدامه، يُرجى الاطّلاع على مقالة العمل في Unity.

3- إضافة Firebase إلى مشروع Unity

إنشاء مشروع على Firebase

  1. في وحدة تحكُّم Firebase، انقر على إضافة مشروع.
  2. لإنشاء مشروع جديد، أدخِل اسم المشروع المطلوب.
    سيؤدي ذلك أيضًا إلى ضبط رقم تعريف المشروع (المعروض أسفل اسم المشروع) على رقم استنادًا إلى اسم المشروع. يمكنك النقر على الرمز تعديل في رقم تعريف المشروع اختياريًا لتخصيصه بشكل أكبر.
  3. راجِع بنود Firebase واقبلها إذا طُلب منك ذلك.
  4. انقر على متابعة.
  5. حدِّد الخيار تفعيل "إحصاءات Google" لهذا المشروع، ثمّ انقر على متابعة.
  6. اختَر حسابًا حاليًا على "إحصاءات Google" لاستخدامه أو اختَر إنشاء حساب جديد لإنشاء حساب جديد.
  7. انقر على إنشاء مشروع.
  8. عند إنشاء المشروع، انقر على متابعة.

تسجيل تطبيقك في Firebase

  1. إذا كنت لا تزال في وحدة تحكُّم Firebase، انقر على رمز Unity لبدء سير عمل الإعداد من وسط صفحة النظرة العامة على المشروع. وإذا سبق لك إضافة تطبيق إلى مشروع Firebase، انقر على إضافة تطبيق لعرض خيارات النظام الأساسي.
  2. اختر تسجيل أهداف الإصدار من Apple (iOS) وAndroid.
  3. أدخِل أرقام التعريف الخاصة بالمنصّة الخاصة بمشروع Unity. بالنسبة إلى هذا الدرس التطبيقي، أدخِل ما يلي:
  4. (اختياري) أدخِل الأسماء المستعارة الخاصة بمنصة مشروع Unity.
  5. انقر على تسجيل التطبيق، ثم تابِع إلى القسم تنزيل ملف الإعداد.

إضافة ملفات إعداد Firebase

بعد النقر على تسجيل التطبيق، سيُطلب منك تنزيل ملفَّي إعداد (ملف إعداد واحد لكل هدف إصدار). يحتاج مشروع Unity إلى البيانات الوصفية لمنصّة Firebase في هذه الملفات للاتصال بمنصّة Firebase.

  1. تنزيل ملفي التهيئة المتاحين:
    • بالنسبة إلى Apple (iOS): نزِّل GoogleService-Info.plist.
    • على أجهزة Android: نزِّل google-services.json.
  2. افتح نافذة المشروع في مشروع Unity، ثم انقل ملفي الإعداد إلى مجلد Assets.
  3. في "وحدة تحكُّم Firebase" ضمن سير عمل الإعداد، انقر على التالي وانتقِل إلى "إضافة حِزم تطوير البرامج (SDK) لمنصة Firebase لبرنامج Unity".

إضافة حِزم تطوير البرامج (SDK) لمنصّة Firebase من أجل Unity

  1. انقر على تنزيل حزمة تطوير البرامج (SDK) لمنصة Firebase Unity في وحدة تحكّم Firebase.
  2. احرص على فكّ ضغط حزمة SDK في مكان مناسب.
  3. في مشروع Unity المفتوح، انتقِل إلى Assets > استيراد حزمة > الحزمة المخصّصة:
  4. في مربّع الحوار استيراد الحزمة، انتقِل إلى الدليل الذي يحتوي على حزمة SDK غير المضغوطة، واختَر FirebaseAnalytics.unitypackage، ثمّ انقر على فتح.
  5. من مربّع الحوار استيراد حزمة Unity الذي يظهر، انقر على استيراد.
  6. كرِّر الخطوات السابقة لاستيراد FirebaseCrashlytics.unitypackage.
  7. ارجع إلى "وحدة تحكُّم Firebase" وانقر على التالي في سير عمل الإعداد.

لمزيد من المعلومات حول إضافة حِزم تطوير البرامج (SDK) لمنصة Firebase إلى مشاريع Unity، يمكنك الاطّلاع على الخيارات الإضافية لتثبيت Unity.

4. ابدأ إعداد Crashlytics في مشروع Unity

لاستخدام Crashlytics في مشاريع Unity، عليك تنفيذ بعض خطوات الإعداد الإضافية. وبالطبع، يجب إعداد حزمة تطوير البرامج (SDK). ولكن أيضًا ستحتاج إلى تحميل رموزك لتتمكن من رؤية عمليات تتبُّع تسلسل استدعاء الدوال البرمجية التي تم ترميزها في وحدة تحكُّم Firebase، وستحتاج إلى فرض حدوث عطل تجريبي للتأكّد من تلقّي Firebase لأحداث الأعطال.

إعداد حزمة تطوير البرامج (SDK) في Crashlytics

  1. في Assets/Hamster/Scripts/MainGame.cs، أضِف عبارات using التالية:
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    تسمح لك الوحدة الأولى باستخدام الطرق من حزمة تطوير البرامج (SDK) لتطبيق Crashlytics وتحتوي الوحدة الثانية على بعض الإضافات في C# Tasks API. بدون كلا العبارتَين using، لن يعمل الرمز التالي.
  2. لا تزال في MainGame.cs، أضِف إعداد Firebase إلى طريقة Start() الحالية من خلال طلب InitializeFirebaseAndStartGame():
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. مرة أخرى، في MainGame.cs، ابحث عن InitializeFirebaseAndStartGame()، وأعلِن عن متغيّر تطبيق، ثم استبدِل تنفيذ الطريقة على النحو التالي:
    public Firebase.FirebaseApp app = null;
    
    // Begins the firebase initialization process and afterwards, opens the main menu.
    private void InitializeFirebaseAndStartGame()
    {
      Firebase.FirebaseApp.CheckAndFixDependenciesAsync()
      .ContinueWithOnMainThread(
        previousTask => 
        {
          var dependencyStatus = previousTask.Result;
          if (dependencyStatus == Firebase.DependencyStatus.Available) {
            // Create and hold a reference to your FirebaseApp,
            app = Firebase.FirebaseApp.DefaultInstance;
            // Set the recommended Crashlytics uncaught exception behavior.
            Crashlytics.ReportUncaughtExceptionsAsFatal = true;
            InitializeCommonDataAndStartGame();
          } else {
            UnityEngine.Debug.LogError(
              $"Could not resolve all Firebase dependencies: {dependencyStatus}\n" +
              "Firebase Unity SDK is not safe to use here");
          }
        });
    }
    

يؤدي وضع منطق الإعداد هنا إلى منع تفاعل اللاعب قبل إعداد تبعيات Firebase.

تتناول الأسئلة الشائعة حول Crashlytics مزايا وتأثير الإبلاغ عن الاستثناءات التي لم تتم معالجتها باعتبارها فادحة.

أنشِئ مشروعك وحمِّل الرموز

تختلف خطوات إنشاء الرموز وتحميلها بين تطبيقات iOS وAndroid.

iOS+ (نظام Apple الأساسي)

  1. من مربّع الحوار إعدادات التصميم، صدِّر مشروعك إلى مساحة عمل Xcode.
  2. يمكنك إنشاء تطبيقك.
    بالنسبة إلى أنظمة Apple الأساسية، يعمل المكوّن الإضافي لمنصة Unity Editor من Firebase على إعداد مشروع Xcode تلقائيًا لإنشاء ملف رموز متوافق مع Crashlytics وتحميله إلى خوادم Firebase لكل إصدار. يجب توفير معلومات الرموز هذه لعرض عمليات تتبُّع تسلسل استدعاء الدوال البرمجية التي تم ترميزها في لوحة بيانات Crashlytics.

Android

  1. (خلال عملية الإعداد الأوّلي فقط، وليس لكل إصدار) عليك إعداد الإصدار:
    1. أنشِئ مجلدًا جديدًا باسم الإنشاءات في جذر دليل مشروعك (على سبيل المثال، كفرع لدليل مواد العرض)، ثم أنشِئ مجلدًا فرعيًا باسم Android.
    2. في ملف > إعدادات الإصدار > إعدادات المشغّل > في الإعدادات، اضبط خلفية البرمجة النصية على IL2CPP.
      • بشكل عام، تساعد طريقة IL2CPP في أن تكون الإصدارات أصغر حجمًا وتحقِّق أداءً أفضل.
      • إنّ IL2CPP هو أيضًا الخيار المتاح "فقط" على نظام التشغيل iOS، ويؤدي تحديده هنا إلى أن تكون المنصّتان أفضل من حيث التكافؤ وتبسيط الاختلافات في تصحيح الأخطاء بينهما (إذا اخترت إنشاء كليهما).
  2. أنشئ تطبيقك. في ملف > إعدادات الإصدار، وأكمِل الخطوات التالية:
    1. تأكَّد من وضع علامة في المربّع Create symbols.zip (أو اختَر Debugging إذا تم عرضه مع قائمة منسدلة).
    2. يمكنك إنشاء ملف APK مباشرةً من Unity Editor في المجلد الفرعي Builds/Android الذي أنشأته للتو.
  3. بعد اكتمال عملية الإنشاء، يجب إنشاء ملف رموز متوافق مع Crashlytics وتحميله إلى خوادم Firebase. يجب توفير معلومات الرموز هذه لعرض عمليات تتبُّع تسلسُل استدعاء الدوال البرمجية التي تم ترميزها لأعطال المكتبة الأصلية في لوحة بيانات Crashlytics.

    يمكنك إنشاء ملف الرموز هذا وتحميله من خلال تنفيذ الأمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    • FIREBASE_APP_ID: رقم تعريف تطبيق Android في Firebase (وليس اسم الحزمة) يمكنك العثور على هذه القيمة في ملف google-services.json الذي نزّلته سابقًا. وهي قيمة mobilesdk_app_id.
      مثال على رقم تعريف تطبيق Android في Firebase: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS: مسار ملف الرمز المضغوط الذي تم إنشاؤه في الدليل Builds/Android عند انتهاء الإصدار (على سبيل المثال: Builds/Android/myapp-1.0-v100.symbols.zip).

فرض عطل في الاختبار لإنهاء عملية الإعداد

للانتهاء من إعداد Crashlytics والاطّلاع على البيانات الأولية في لوحة بيانات Crashlytics ضمن وحدة تحكُّم Firebase، يجب فرض عطل اختباري.

  1. في MainGameScene، ابحث عن إفراغ الكائن GameObject في المحرِّر التسلسل الهرمي، وأضِف النص البرمجي التالي إليه ثم احفظ المشهد. سيؤدي هذا النص البرمجي إلى حدوث عطل في الاختبار بعد بضع ثوانٍ من تشغيل تطبيقك.
    using System;
    using UnityEngine;
    
    public class CrashlyticsTester : MonoBehaviour {
        // Update is called once per frame
        void Update()
        {
            // Tests your Crashlytics implementation by
            // throwing an exception every 60 frames.
            // You should see reports in the Firebase console
            // a few minutes after running your app with this method.
            if(Time.frameCount >0 && (Time.frameCount%60) == 0)
            {
                throw new System.Exception("Test exception; please ignore");
            }
        }
    }
    
  2. أنشِئ تطبيقك وحمِّل معلومات الرموز بعد انتهاء الإصدار.
    • iOS: يعمل المكوّن الإضافي لمنصة Unity Editor من Firebase على إعداد مشروع Xcode تلقائيًا لتحميل ملف الرموز.
    • Android: شغِّل أمر Firebase CLI crashlytics:symbols:upload لتحميل ملف الرموز.
  3. شغِّل تطبيقك. بعد تشغيل تطبيقك، راقِب سجلّ الجهاز وانتظر حتى يتم تشغيل الاستثناء من CrashlyticsTester.
    • iOS: يمكنك عرض السجلّات في الجزء السفلي في Xcode.
    • Android: يمكنك عرض السجلّات من خلال تشغيل الأمر التالي في الوحدة الطرفية: adb logcat.
  4. يمكنك الانتقال إلى لوحة بيانات Crashlytics للاطّلاع على الاستثناء. ويمكنك الاطّلاع عليه في جدول المشاكل في أسفل لوحة البيانات. في وقت لاحق من الدرس التطبيقي حول الترميز، ستتعرّف على المزيد من المعلومات عن كيفية الاطّلاع على هذه التقارير.
  5. بعد التأكّد من تحميل الحدث إلى Crashlytics، انقر على إفراغ العنصر GameObject الذي أرفقته، وأزِل المكوِّن CrashlyticsTester فقط، ثم احفظ المشهد لاستعادته إلى حالته الأصلية.

5- تفعيل قائمة تصحيح الأخطاء وفهمها

لقد أضفت Crashlytics حتى الآن إلى مشروعك على Unity، وأتممت عملية الإعداد، وتأكّدت من أنّ حزمة تطوير برامج Crashlytics تُحمِّل الأحداث إلى Firebase. ستنشئ الآن قائمة في مشروعك على Unity والتي ستوضّح كيفية استخدام وظائف Crashlytics الأكثر تقدّمًا في لعبتك. يحتوي مشروع Unity على الترقية باستخدام Firebase يحتوي حاليًا على قائمة تصحيح أخطاء مخفية ستصبح مرئية وتكتب الوظائف لها.

تفعيل قائمة تصحيح الأخطاء

يتوفّر زر الوصول إلى "قائمة تصحيح الأخطاء" في مشروع Unity، ولكنه غير مفعّل حاليًا. يجب تفعيل الزرّ للوصول إلى البيانات من خلال الإعداد المسبق "MainMenu":

  1. في Unity Editor، افتح الإعدادات المسبقة المسماة MainMenu.4148538cbe9f36c5.png
  2. في التسلسل الهرمي Prefab، ابحث عن الكائن الفرعي الذي تم إيقافه باسم DebugMenuButton، ثم اختَره.816f8f9366280f6c.png
  3. يمكنك تفعيل DebugMenuButton بوضع علامة في المربّع في أعلى اليمين إلى يسار حقل النص الذي يحتوي على DebugMenuButton.8a8089d2b4886da2.png
  4. حفظ الإعداد المسبق.
  5. شغِّل اللعبة في المحرِّر أو على جهازك. يُفترض أن يمكن الوصول إلى القائمة الآن.

معاينة نصوص الطرق في قائمة تصحيح الأخطاء وفهمها

في وقت لاحق من هذا الدرس التطبيقي، ستكتب نصوص طُرق لبعض طرق تصحيح الأخطاء المضبوطة مسبقًا على Crashlytics. ومع ذلك، في مشروع Unity المستوى الأعلى باستخدام Firebase، يتم تحديد الطرق في DebugMenu.cs واستدعاؤها من خلالها.

على الرغم من أنّ بعض هذه الطرق ستستدعي طرق Crashlytics وأخطاء الطرح، فإن قدرة Crashlytics على اكتشاف هذه الأخطاء لا تعتمد على استدعاء هذه الطرق أولاً. بدلاً من ذلك، سيتم تحسين تقارير الأعطال التي تم إنشاؤها من رصد الأخطاء تلقائيًا من خلال المعلومات التي تضيفها هذه الطرق.

افتح DebugMenu.cs، ثم ابحث عن الطرق التالية:

طرق إنشاء مشاكل Crashlytics وإضافة تعليقات توضيحية إليها:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

طرق تسجيل أحداث "إحصاءات Google" للمساعدة في تصحيح الأخطاء:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

في الخطوات اللاحقة من هذا الدرس التطبيقي حول الترميز، ستنفّذ هذه الطرق وستتعرف على كيفية مساعدتها في معالجة مواقف محدّدة قد تحدث أثناء تطوير الألعاب.

6- التأكد من تسليم تقارير الأعطال في مرحلة التطوير

قبل البدء في تنفيذ طرق تصحيح الأخطاء هذه ومعرفة مدى تأثيرها في تقارير الأعطال، تأكَّد من فهم كيفية إبلاغ Crashlytics عن الأحداث.

بالنسبة إلى مشاريع Unity، تتم كتابة أحداث التعطّل والاستثناءات في لعبتك على الفور على القرص. بالنسبة إلى الاستثناءات غير المرصودة التي لا تؤدي إلى تعطُّل لعبتك (على سبيل المثال، استثناءات C# غير المرصودة في منطق اللعبة)، يمكنك أن تطلب من حزمة Crashlytics SDK الإبلاغ عنها كأحداث فادحة من خلال ضبط السمة Crashlytics.ReportUncaughtExceptionsAsFatal على true حيث يتم إعداد Crashlytics ضمن مشروع Unity. ويتم إبلاغ فريق Crashlytics بهذه الأحداث في الوقت الفعلي بدون أن يحتاج المستخدم النهائي إلى إعادة تشغيل اللعبة. تجدر الإشارة إلى أنّ الأعطال الأصلية دائمًا ما يتم الإبلاغ عنها على أنّها أحداث فادحة، ويتم إرسالها عندما يعيد المستخدم النهائي تشغيل اللعبة.

بالإضافة إلى ذلك، يجب الانتباه إلى الفروقات التالية الصغيرة ولكنها مهمة بين كيفية إرسال بيئات وقت التشغيل المختلفة لمعلومات Crashlytics إلى Firebase:

محاكي iOS:

  • يتم الإبلاغ عن معلومات Crashlytics فقط في حال فصل Xcode عن المحاكي. في حال إرفاق Xcode، ترصد الأخطاء من البداية، ما يمنع تسليم المعلومات.

الأجهزة الجوّالة (Android وiOS):

  • خاص بنظام Android: لا يتم الإبلاغ عن أخطاء ANR إلا في الإصدار 11 من نظام التشغيل Android والإصدارات الأحدث. يتم تسجيل أخطاء ANR والأحداث غير الفادحة في عملية التشغيل التالية.

محرِّر Unity:

اختبار تعطُّل لعبتك بلمسة زر في CrashNow()

بعد إعداد Crashlytics في لعبتك، تسجِّل حزمة تطوير برامج Crashlytics تلقائيًا الأعطال والاستثناءات غير المرصودة وتحمِّلها إلى Firebase لتحليلها. ويتم عرض التقارير في لوحة بيانات Crashlytics ضمن وحدة تحكُّم Firebase.

  1. لتوضيح أن هذا الإجراء تلقائي فعلاً: افتح DebugMenu.cs، ثم استبدل الطريقة CrashNow() على النحو التالي:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. أنشئ تطبيقك.
  3. (Android فقط) حمِّل الرموز من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. انقر على زر الأعطال الآن وانتقِل إلى الخطوة التالية في هذا الدرس التطبيقي حول الترميز لمعرفة كيفية عرض تقرير الأعطال وتفسيره.

7- فهم تقارير المشاكل في "وحدة تحكُّم Firebase"

عندما يتعلق الأمر بعرض تقارير الأعطال، يجب أن تعرف كيفية الاستفادة منها إلى أقصى حد. ستوضح كل طريقة من الطرق التي تكتبها كيفية إضافة أنواع مختلفة من المعلومات إلى تقارير Crashlytics.

  1. انقر على زر التعطُّل الآن، ثم أعِد تشغيل التطبيق.
  2. انتقِل إلى لوحة بيانات Crashlytics. انتقِل للأسفل إلى جدول المشاكل في أسفل لوحة البيانات حيث يجمع Crashlytics الأحداث التي لها السبب الأساسي نفسه ضمن "المشاكل".
  3. انقر على المشكلة الجديدة المُدرجة في جدول المشاكل. يؤدي هذا الإجراء إلى عرض ملخّص الحدث حول كل حدث فردي تم إرساله إلى Firebase.

    من المفترض أن يظهر لك محتوى مثل لقطة الشاشة التالية. لاحِظ كيف يعرض ملخّص الحدث بشكل بارز تتبُّع تسلسل استدعاء الدوال البرمجية للمكالمة التي أدت إلى التعطُّل.40c96abe7f90c3aa.png

البيانات الوصفية الإضافية

يمكنك أيضًا استخدام علامة التبويب البيانات الوصفية في Unity ضمن علامة التبويب المفيدة. يطلعك هذا القسم على سمات الجهاز الذي أُجري الحدث عليه، بما في ذلك الميزات المادية وطراز/مواصفات وحدة المعالجة المركزية (CPU) وجميع أنواع مقاييس وحدة معالجة الرسومات.

في ما يلي مثال يمكن أن تكون فيه المعلومات الواردة في علامة التبويب هذه مفيدة:
لنتخيل أنّ لعبتك تستخدم أدوات التظليل بشكل مكثّف للحصول على مظهر معيّن، إلا أنّ بعض الهواتف لا تحتوي على وحدات معالجة رسومات قادرة على عرض هذه الميزة. تمنحك المعلومات في علامة التبويب البيانات الوصفية Unity فكرة أفضل عن الأجهزة التي يجب أن يختبرها تطبيقك عند تحديد الميزات التي ستتم إتاحتها أو إيقافها بالكامل تلقائيًا.

قد لا يحدث أي خطأ أو تعطُّل على جهازك مطلقًا، ولكن بسبب التنوع الكبير في أجهزة Android الأخرى، يُساعد ذلك في التعرّف على "نقاط الاتصال" المعيّنة بشكل أفضل من أجهزة جمهورك.

41d8d7feaa87454d.png

8- رمي استثناءات وجمعها وتسجيلها

في كثير من الأحيان، بصفتك مطورًا، من الجيد ملاحظة حدوث ذلك وتحت أي ظرف منه حتى لو تمكنت التعليمة البرمجية من اكتشاف استثناء بيئة التشغيل والتعامل معه بشكل صحيح. ويمكن استخدام Crashlytics.LogException لهذا الغرض تحديدًا، وهو إرسال حدث استثناء إلى Firebase حتى تتمكّن من تصحيح المشكلة أكثر في "وحدة تحكُّم Firebase".

  1. في Assets/Hamster/Scripts/States/DebugMenu.cs، ألحق ما يلي بعبارات using:
    // Import Firebase
    using Firebase.Crashlytics;
    
  2. لا تزال في DebugMenu.cs، استبدِل LogNonfatalError() على النحو التالي:
    void LogNonfatalError()
    {
        try
        {
            throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}");
        }
        catch(System.Exception exception)
        {
            Crashlytics.LogException(exception);
        }
    }
    
  3. أنشئ تطبيقك.
  4. (Android فقط) حمِّل الرموز من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  5. انقر على الزر تسجيل خطأ غير فادح، ثم أعِد تشغيل التطبيق.
  6. انتقِل إلى لوحة بيانات Crashlytics، ومن المفترض أن تظهر لك نتيجة مشابهة لما رأيته في الخطوة الأخيرة من هذا الدرس التطبيقي حول الترميز.
  7. مع ذلك، احصر هذه المرة فلتر نوع الحدث على غير فادحة بحيث لا تعرض سوى الأخطاء غير الفادحة، مثل الخطأ الذي سجلته للتو.
    a39ea8d9944cbbd9.png

9- سجِّل السلاسل في Crashlytics لفهم عملية تنفيذ البرنامج بشكل أفضل.

هل حاولت معرفة السبب في حدوث استثناء أو تعطُّل فجأة لسطر من الرمز يتم استدعاؤه من مسارات متعددة، مئات بل آلاف المرات في كل جلسة؟ في حين أنه قد يكون من الجيد التنقل عبر التعليمات البرمجية في بيئة تطوير متكاملة (IDE) والنظر إلى القيم عن كثب، ماذا لو حدث هذا فقط بين نسبة صغيرة متلاشية من المستخدمين؟ والأسوأ من ذلك، ماذا ستفعل إذا لم تتمكن من تكرار هذا العطل بصرف النظر عن ما تفعله؟

في مثل هذه الحالات، يمكن أن يؤدي توفير بعض السياق إلى إحداث فرق. باستخدام "Crashlytics.Log"، يمكنك كتابة السياق الذي تريده. فكر في هذه الرسائل على أنها تلميحات لنفسك حول ما يمكن أن يحدث في المستقبل.

في حين يمكن استخدام السجلات بطرق لا حصر لها، إلا أنها عادةً ما تكون مفيدة للغاية لتسجيل الحالات التي يكون فيها ترتيب و/أو غياب المكالمات أحد المعلومات المهمة للغاية.

  1. في Assets/Hamster/Scripts/States/DebugMenu.cs، استبدِل LogStringsAndCrashNow() على النحو التالي:
    void LogStringsAndCrashNow()
    {
        Crashlytics.Log($"This is the first of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        const bool RUN_OPTIONAL_PATH = false;
        if(RUN_OPTIONAL_PATH)
        {
            Crashlytics.Log(" As it stands, this log should not appear in your records because it will never be called.");
        }
        else
        {
            Crashlytics.Log(" A log that will simply inform you which path of logic was taken. Akin to print debugging.");
        }
        Crashlytics.Log($"This is the second of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        TestCrash();
    }
    
  2. أنشئ تطبيقك.
  3. (Android فقط) حمِّل الرموز من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. انقر على زر تسجيل السلاسل النصية والأعطال الآن، ثم أعِد تشغيل تطبيقك.
  5. ارجع إلى لوحة بيانات Crashlytics وانقر على أحدث مشكلة مُدرَجة في جدول المشاكل. مرة أخرى، من المفترض أن تظهر لك مشكلة مشابهة للمشكلة السابقة.
    7aabe103b8589cc7.png
  6. ومع ذلك، إذا نقرت على علامة التبويب السجلات ضمن ملخّص الحدث، ستحصل على عرض مثل هذا:
    4e27aa407b7571cf.png

10- كتابة مفتاح مخصّص واستبداله

لنفترض أنّك تريد أن تفهم بشكل أفضل الأعطال المقابلة للمتغيّرات التي تم ضبطها على عدد صغير من القيم أو الإعدادات. قد يكون من الجيد أن تكون قادرًا على التصفية، بناءً على مجموعة المتغيرات والقيم المحتملة التي تنظر إليها، في أي وقت.

بالإضافة إلى تسجيل السلاسل العشوائية، يوفّر تطبيق Crashlytics شكلاً آخر من تصحيح الأخطاء عندما يكون من المفيد معرفة الحالة الدقيقة لبرنامجك عند تعطُّله، وهي المفاتيح المخصَّصة.

هذه أزواج المفتاح/القيمة التي يمكنك تعيينها لجلسة. وعلى عكس السجلات التي تتراكم وتكون قابلة للإضافة بشكل تام، يمكن استبدال المفاتيح لتعكس فقط أحدث حالة لمتغير أو شرط.

بالإضافة إلى كونها دفتر ملاحظات لآخر حالة مسجَّلة لبرنامجك، يمكن استخدام هذه المفاتيح كفلاتر فعّالة لمشاكل Crashlytics.

  1. في Assets/Hamster/Scripts/States/DebugMenu.cs، استبدِل SetAndOverwriteCustomKeyThenCrash() على النحو التالي:
    void SetAndOverwriteCustomKeyThenCrash()
    {
        const string CURRENT_TIME_KEY = "Current Time";
        System.TimeSpan currentTime = System.DateTime.Now.TimeOfDay;
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString() // Values must be strings
            );
    
        // Time Passes
        currentTime += DayDivision.DURATION_THAT_ENSURES_PHASE_CHANGE;
    
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString()
            );
        TestCrash();
    }
    
  2. أنشئ تطبيقك.
  3. (Android فقط) حمِّل الرموز من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. انقر على زر ضبط المفتاح المخصّص والتعطُّل، ثم أعِد تشغيل التطبيق.
  5. ارجع إلى لوحة بيانات Crashlytics وانقر على أحدث مشكلة مُدرَجة في جدول المشاكل. مرة أخرى، من المفترض أن تظهر لك مشكلة مشابهة للمشاكل السابقة.
  6. ولكن هذه المرة، انقر على علامة التبويب المفاتيح في ملخّص الحدث لتتمكن من الاطّلاع على قيمة المفاتيح، بما في ذلك Current Time:
    7dbe1eb00566af98.png

لماذا قد تحتاج إلى استخدام مفاتيح مخصّصة بدلاً من السجلات المخصَّصة؟

  • تُعدّ السجلّات مناسبة في تخزين البيانات التسلسلية، ولكنّ المفاتيح المخصَّصة تُفضّل استخدام المفاتيح المخصّصة إذا كنت تريد الحصول على القيمة الأحدث فقط.
  • في "وحدة تحكُّم Firebase"، يمكنك فلترة المشاكل بسهولة حسب قيم المفاتيح في مربّع البحث ضمن جدول المشاكل.

وعلى غرار السجلات، هناك حدّ أقصى للمفاتيح المخصّصة. يتيح تطبيق Crashlytics استخدام 64 زوجًا من المفاتيح والقيم كحدّ أقصى. وبعد الوصول إلى هذا الحدّ، لا يتم حفظ القيم الإضافية. يمكن أن يصل حجم كل زوج مفتاح/قيمة إلى 1 كيلوبايت.

11- (نظام التشغيل Android فقط) استخدام المفاتيح والسجلات المخصّصة لفهم أخطاء ANR وتشخيصها

بالنسبة إلى مطوّري برامج Android، من أصعب فئات المشاكل التي يجب تصحيحها هو الخطأ التطبيق لا يستجيب (ANR). تحدث أخطاء ANR عندما لا يستجِب تطبيقٌ لإدخال البيانات لمدة تزيد عن 5 ثوانٍ. إذا حدث ذلك، فهذا يعني أن التطبيق إما توقف أو يعمل ببطء شديد. يظهر مربّع حوار للمستخدمين، ويمكنهم اختيار "الانتظار" أو لا أو "إغلاق التطبيق".

إنّ أخطاء ANR هي تجربة سيئة للمستخدم ويمكن أن تؤثر (كما هو موضّح في رابط ANR أعلاه) في قابلية اكتشاف تطبيقك على "متجر Google Play". غالبًا ما يكون إعادة إنتاج أخطاء ANR أثناء تصحيح الأخطاء أمرًا صعبًا للغاية، بل قد يكون من الصعب إعادة إنتاج أخطاء ANR أثناء تصحيح الأخطاء وغالبًا ما تنتج عن استخدام رموز برمجية متعددة السلاسل مع سلوك مختلف إلى حدّ كبير في طُرز الهواتف المختلفة. على هذا النحو، عادةً ما يكون التعامل معها تحليليًا واستنتاجيًا هو أفضل نهج.

بهذه الطريقة، سنستخدم مجموعة من Crashlytics.LogException وCrashlytics.Log وCrashlytics.SetCustomKey لإكمال عملية التسجيل التلقائي للمشاكل ولتزويدنا بمزيد من المعلومات.

  1. في Assets/Hamster/Scripts/States/DebugMenu.cs، استبدِل SetLogsAndKeysBeforeANR() على النحو التالي:
    void SetLogsAndKeysBeforeANR()
    {
        System.Action<string,long> WaitAndRecord =
        (string methodName, long targetCallLength)=>
        {
            System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
            const string CURRENT_FUNCTION = "Current Async Function";
    
            // Initialize key and start timing
            Crashlytics.SetCustomKey(CURRENT_FUNCTION, methodName);
            stopWatch.Start();
    
            // The actual (simulated) work being timed.
            BusyWaitSimulator.WaitOnSimulatedBlockingWork(targetCallLength);
    
            // Stop timing
            stopWatch.Stop();
    
            if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.EXTREME_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough to cause an ANR.");
            }
            else if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.SEVERE_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough it may cause an ANR");
            }
        };
    
        WaitAndRecord("DoSafeWork",1000L);
        WaitAndRecord("DoSevereWork",BusyWaitSimulator.SEVERE_DURATION_MILLIS);
        WaitAndRecord("DoExtremeWork",2*BusyWaitSimulator.EXTREME_DURATION_MILLIS);
    }
    
  2. أنشئ تطبيقك.
  3. حمِّل رموزك من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. انقر على الزر المسمى ضبط السجلات والمفاتيح ← ANR، ثم أعِد تشغيل التطبيق.
  5. ارجع إلى لوحة بيانات Crashlytics، ثم انقر على المشكلة الجديدة في جدول المشاكل للاطّلاع على ملخّص الأحداث. إذا تمّت المكالمة على النحو الصحيح، من المفترض أن يظهر لك على النحو التالي:
    876c3cff7037bd07.png

    كما ترى، حددت منصة Firebase فترة الانتظار المشغولة على سلسلة المحادثات باعتبارها السبب الرئيسي الذي أدى إلى حدوث خطأ ANR.
  6. من خلال الاطّلاع على السجلات في علامة التبويب السجلات ضمن ملخّص الحدث، ستلاحظ أنّ آخر طريقة تم تسجيلها على أنّها مكتملة هي "DoSevereWork".
    5a4bec1cf06f6984.png

    وفي المقابل، آخر طريقة تم إدراجها باعتبارها بداية هي DoExtremeWork، ما يشير إلى حدوث خطأ ANR أثناء هذه الطريقة وإغلاق اللعبة قبل تسجيل DoExtremeWork.

    89d86d5f598ecf3a.png

ما أهمية إجراء ذلك؟

  • إنّ إعادة إنتاج أخطاء ANR عملية صعبة للغاية، لذا من المهم جدًا الحصول على معلومات وافرة عن منطقة الرمز البرمجي ومقاييسه لمعرفة ذلك بشكل استنتاجي.
  • بفضل المعلومات المخزَّنة في المفاتيح المخصّصة، يمكنك الآن معرفة سلسلة المحادثات غير المتزامنة التي استغرقت وقتًا أطول في التشغيل، والسلسلة التي كانت معرّضة لخطر التسبب في حدوث أخطاء ANR. وهذا النوع من البيانات المنطقية والرقمية ذات الصلة سيوضح لك المكان الذي يمثل فيه الرمز أهمية قصوى للتحسين.

12- تبادل أحداث "إحصاءات Google" لإثراء التقارير بشكلٍ أكبر

يمكن أيضًا طلب الطرق التالية من قائمة تصحيح الأخطاء، ولكن بدلاً من حدوث المشاكل نفسها، تستخدم هذه الطرق "إحصاءات Google" كمصدر آخر للمعلومات من أجل فهم طريقة عمل لعبتك بشكلٍ أفضل.

وعلى عكس الطرق الأخرى التي كتبتها في هذا الدرس التطبيقي حول الترميز، عليك استخدام هاتَين الطريقتَين بالإضافة إلى الطرق الأخرى. استدعِ هذه الطرق (عن طريق الضغط على الزر المقابل لها في قائمة تصحيح الأخطاء) بأي ترتيب عشوائي تريده قبل تشغيل إحدى الطرق الأخرى. وبعد ذلك، عند فحص المعلومات الواردة في مشكلة Crashlytics المحدّدة، سيظهر لك سجلّ مرتّب لأحداث "إحصاءات Google". ويمكن استخدام هذه البيانات في لعبة ما للتعرّف بشكل أفضل على مزيج من مسارات البرنامج أو إدخالات المستخدم، اعتمادًا على طريقة استخدامك للتطبيق.

  1. في Assets/Hamster/Scripts/States/DebugMenu.cs، يجب استبدال عمليات التنفيذ الحالية للطرق التالية:
    public void LogProgressEventWithStringLiterals()
    {
          Firebase.Analytics.FirebaseAnalytics.LogEvent("progress", "percent", 0.4f);
    }
    
    public void LogIntScoreWithBuiltInEventAndParams()
    {
          Firebase.Analytics.FirebaseAnalytics
            .LogEvent(
              Firebase.Analytics.FirebaseAnalytics.EventPostScore,
              Firebase.Analytics.FirebaseAnalytics.ParameterScore,
              42
            );
    }
    
  2. أنشِئ لعبتك وانشرها، ثم أدخِل قائمة تصحيح الأخطاء.
  3. (Android فقط) حمِّل الرموز من خلال تشغيل أمر Firebase CLI التالي:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. اضغط على أحد الأزرار التالية مرة واحدة على الأقل أو أكثر لطلب الوظائف الموضحة أعلاه:
    • حدث سلسلة السجلّ
    • حدث تسجيل الدخول
  5. اضغط على زر العطل الآن.
  6. أعِد تشغيل لعبتك لتحميل حدث التعطُّل إلى Firebase.
  7. عند تسجيل تسلسلات عشوائية مختلفة من أحداث "إحصاءات Google" ثم إنشاء لعبتك لحدث ينشئ Crashlytics تقريرًا منه (كما فعلت أنت فقط)، تتم إضافة الأحداث إلى علامة التبويب السجلات ضمن ملخّص الحدث في Crashlytics على النحو التالي:
    d3b16d78f76bfb04.png

13- مواصلة التقدم

وبناءً على ذلك، يجب أن يكون لديك أساس نظري أفضل لاستكمال تقارير الأعطال التي يتم إنشاؤها تلقائيًا. وتسمح لك هذه المعلومات الجديدة باستخدام الحالة الحالية وسجلّات الأحداث السابقة وأحداث "إحصاءات Google" الحالية لتقسيم تسلسل الأحداث والمنطق الذي أدى إلى نتائجها بشكل أفضل.

إذا كان تطبيقك يستهدف Android 11 (المستوى 30 لواجهة برمجة التطبيقات) أو إصدارًا أحدث، ننصحك بتضمين GWP-ASan، وهي ميزة أصلية لتخصيص الذاكرة، وهي ميزة مفيدة لتصحيح الأعطال الناتجة عن أخطاء الذاكرة الأصلية، مثل أخطاء use-after-free وheap-buffer-overflow. للاستفادة من ميزة تصحيح الأخطاء هذه، عليك تفعيل GWP-ASan صراحةً.

الخطوات التالية

انتقِل إلى الدرس التطبيقي حول كيفية استخدام أداة "الإعداد عن بُعد في أداة Unity" مع ميزة "الإعداد عن بُعد"، حيث ستتعرّف على كيفية استخدام ميزتَي "الإعداد عن بُعد" و"اختبار A/B" في Unity.