Awarie w grach na Unity przy użyciu zaawansowanych funkcji Crashlytics

1. Wprowadzenie

Z tego laboratorium dowiesz się, jak korzystać z zaawansowanych funkcji Crashlytics, które zapewnią Ci lepszy wgląd w awarie i okoliczności, które mogły je spowodować.

Dodasz nowe funkcje do przykładowej gry MechaHamster: Level Up with Firebase Edition. Ta przykładowa gra to nowa wersja klasycznej gry Firebase MechaHamster, w której usunięto większość wbudowanych funkcji Firebase. Dzięki temu możesz wdrożyć w ich miejsce nowe zastosowania Firebase.

Dodasz do gry menu debugowania. To menu debugowania wywołuje utworzone przez Ciebie metody i umożliwia korzystanie z różnych funkcji Crashlytics. Z tych metod dowiesz się, jak dodawać do automatycznych raportów o awariach adnotacje z użyciem kluczy niestandardowych, logów niestandardowych, błędów niekrytycznych i innych elementów.

Po utworzeniu gry użyj menu debugowania i sprawdź wyniki, aby dowiedzieć się, jak gra działa w rzeczywistych warunkach.

Czego się nauczysz

  • Rodzaje błędów, które są automatycznie wykrywane przez Crashlytics.
  • Dodatkowe błędy, które można celowo rejestrować.
  • Jak dodać więcej informacji o tych błędach, aby ułatwić ich zrozumienie.

Czego potrzebujesz

  • Unity (zalecana minimalna wersja to 2019 lub nowsza) z jednym z tych elementów lub z obydwoma:
    • Obsługa kompilacji na iOS
    • Obsługa kompilacji Androida
  • (Tylko w przypadku Androida) Wiersz poleceń Firebase (używany do przesyłania symboli na potrzeby raportów o awariach)

2. Konfigurowanie środowiska programistycznego

W kolejnych sekcjach dowiesz się, jak pobrać kod Level Up with Firebase i otworzyć go w Unity.

Pamiętaj, że przykładowa gra Level Up with Firebase jest używana w kilku innych samouczkach Firebase + Unity, więc zadania w tej sekcji mogły już zostać przez Ciebie wykonane. Jeśli tak, możesz przejść od razu do ostatniego kroku na tej stronie: „Dodawanie pakietów SDK Firebase dla Unity”.

Pobieranie kodu

Sklonuj repozytorium GitHub tego laboratorium z poziomu wiersza poleceń:

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

Jeśli nie masz zainstalowanego narzędzia git, możesz pobrać repozytorium jako plik ZIP.

Otwórz Level Up with Firebase w edytorze Unity.

  1. Uruchom Unity Hub i na karcie Projects (Projekty) kliknij strzałkę w dół obok opcji Open (Otwórz).
  2. Kliknij Dodaj projekt z dysku.
  3. Przejdź do katalogu zawierającego kod i kliknij OK.
  4. Jeśli pojawi się prośba, wybierz wersję edytora Unity, której chcesz używać, oraz platformę docelową (Android lub iOS).
  5. Kliknij nazwę projektu level-up-with-firebase, a projekt otworzy się w edytorze Unity.
  6. Jeśli edytor nie otworzy go automatycznie, otwórz MainGameSceneAssets > Hamster na karcie Project w edytorze Unity.
    ff4ea3f3c0d29379.png

Więcej informacji o instalowaniu i używaniu Unity znajdziesz w artykule Praca w Unity.

3. Dodawanie Firebase do projektu Unity

Tworzenie projektu Firebase

  1. Zaloguj się w konsoli Firebase, korzystając ze swojego konta Google.
  2. Kliknij przycisk, aby utworzyć nowy projekt, a potem wpisz jego nazwę (np. Mechahamster Codelab).
  3. Kliknij Dalej.
  4. Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
  5. (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
  6. W tym samouczku Google Analytics jest potrzebne do optymalnego korzystania z usług Firebase, więc pozostaw włączony przełącznik opcji Google Analytics. Aby skonfigurować Google Analytics, postępuj zgodnie z instrukcjami wyświetlanymi na ekranie.
  7. Kliknij Utwórz projekt, poczekaj, aż projekt zostanie udostępniony, a następnie kliknij Dalej.

Rejestrowanie aplikacji w Firebase

  1. W konsoli Firebase w centrum strony „Opis” projektu kliknij ikonę Unity, aby uruchomić proces konfiguracji. Jeśli masz już dodaną aplikację do projektu Firebase, kliknij Dodaj aplikację, aby wyświetlić opcje platformy.
  2. Zarejestruj cele kompilacji na urządzenia Apple (iOS) i z Androidem.
  3. Wpisz identyfikatory specyficzne dla platformy projektu Unity. W tym ćwiczeniu wpisz te informacje:
  4. (Opcjonalnie) Wpisz pseudonimy specyficzne dla platformy w projekcie Unity.
  5. Kliknij Zarejestruj aplikację, a potem przejdź do sekcji Pobierz plik konfiguracyjny.

Dodawanie plików konfiguracyjnych Firebase

Po kliknięciu Zarejestruj aplikację pojawi się prośba o pobranie 2 plików konfiguracyjnych (po 1 na każdy docelowy typ kompilacji). Aby połączyć projekt Unity z Firebase, musisz dodać do tych plików metadane Firebase.

  1. Pobierz oba dostępne pliki konfiguracyjne:
    • W przypadku urządzeń Apple (iOS): pobierz plik GoogleService-Info.plist.
    • Android: pobierz plik google-services.json.
  2. Otwórz okno Project (Projekt) w projekcie Unity, a następnie przenieś oba pliki konfiguracyjne do folderu Assets (Zasoby).
  3. Wróć do konsoli Firebase i w procesie konfiguracji kliknij Dalej, a potem przejdź do sekcji Dodawanie pakietów SDK Firebase do Unity.

Dodawanie pakietów SDK Firebase dla Unity

  1. W konsoli Firebase kliknij Pobierz pakiet Firebase Unity SDK.
  2. Rozpakuj pakiet SDK w dogodnym miejscu.
  3. W otwartym projekcie Unity kliknij Assets (Zasoby) > Import Package (Importuj pakiet) > Custom Package (Własny pakiet).
  4. W oknie dialogowym Import package (Importuj pakiet) przejdź do katalogu zawierającego rozpakowany pakiet SDK, wybierz FirebaseAnalytics.unitypackage, a następnie kliknij Open (Otwórz).
  5. W wyświetlonym oknie Import Unity Package (Importowanie pakietu dla Unity) kliknij Import (Importuj).
  6. Powtórz poprzednie kroki, aby zaimportować FirebaseCrashlytics.unitypackage.
  7. Wróć do konsoli Firebase i w przepływie pracy konfiguracji kliknij Dalej.

Więcej informacji o dodawaniu pakietów SDK Firebase do projektów Unity znajdziesz w sekcji Dodatkowe opcje instalacji w Unity.

4. Konfigurowanie Crashlytics w projekcie Unity

Aby używać Crashlytics w projektach Unity, musisz wykonać kilka dodatkowych czynności konfiguracyjnych. Oczywiście musisz zainicjować pakiet SDK. Musisz też przesłać symbole, aby w konsoli Firebase wyświetlać ślady stosu z symbolami, oraz wymusić testowe awarie, aby mieć pewność, że Firebase otrzymuje zdarzenia awarii.

Inicjowanie pakietu SDK Crashlytics

  1. W sekcji Assets/Hamster/Scripts/MainGame.cs dodaj te instrukcje using:
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    Pierwszy moduł umożliwia korzystanie z metod z pakietu SDK Crashlytics, a drugi zawiera rozszerzenia interfejsu C# Tasks API. Bez obu using stwierdzeń poniższy kod nie będzie działać.
  2. W dalszym ciągu w MainGame.cs dodaj inicjowanie Firebase do istniejącej metody Start(), wywołując InitializeFirebaseAndStartGame():
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. Ponownie w MainGame.cs znajdź InitializeFirebaseAndStartGame(), zadeklaruj zmienną aplikacji, a następnie zastąp implementację metody w ten sposób:
    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");
          }
        });
    }
    

Umieszczenie logiki inicjalizacji w tym miejscu uniemożliwia interakcję odtwarzacza przed zainicjowaniem zależności Firebase.

Korzyści i skutki zgłaszania nieobsłużonych wyjątków jako błędów krytycznych zostały omówione w tym artykule z odpowiedziami na najczęstsze pytania dotyczące Crashlytics.

Tworzenie projektu i przesyłanie symboli

Procedury tworzenia i przesyłania symboli różnią się w przypadku aplikacji na iOS i Androida.

iOS+ (platforma Apple)

  1. W oknie Ustawienia kompilacji wyeksportuj projekt do obszaru roboczego Xcode.
  2. Zbuduj aplikację.
    W przypadku platform Apple wtyczka Firebase Unity Editor automatycznie konfiguruje projekt Xcode, aby generować i przesyłać do serwerów Firebase plik symboli zgodny z Crashlytics dla każdej kompilacji. Te informacje o symbolach są wymagane, aby wyświetlać w panelu Crashlytics ślady stosu z symbolami.

Android

  1. (tylko podczas konfiguracji początkowej, nie w przypadku każdej kompilacji) Skonfiguruj kompilację:
    1. W katalogu głównym projektu (czyli obok katalogu Assets) utwórz nowy folder o nazwie Builds, a następnie utwórz w nim podfolder o nazwie Android.
    2. Wybierz File (Plik) > Build Settings (Ustawienia kompilacji) > Player Settings (Ustawienia odtwarzacza) > Configuration (Konfiguracja) i ustaw Scripting Backend (Backend skryptów) na IL2CPP.
      • IL2CPP zwykle powoduje, że kompilacje są mniejsze i mają lepszą wydajność.
      • IL2CPP to JEDYNA dostępna opcja na iOS. Wybranie jej tutaj pozwala na lepsze dopasowanie obu platform i ułatwia debugowanie różnic między nimi (jeśli zdecydujesz się na kompilację na obie platformy).
  2. Zbuduj aplikację. W menu File (Plik) > Build Settings (Ustawienia kompilacji) wykonaj te czynności:
    1. Upewnij się, że pole Create symbols.zip jest zaznaczone (lub jeśli pojawi się menu, wybierz Debugging).
    2. Skompiluj pakiet APK bezpośrednio z edytora Unity do utworzonego właśnie podfolderu Builds/Android.
  3. Po zakończeniu kompilacji musisz wygenerować plik symboli zgodny z Crashlytics i przesłać go na serwery Firebase. Te informacje o symbolach są wymagane, aby wyświetlać w panelu Crashlytics zsymbolizowane ślady stosu w przypadku awarii bibliotek natywnych.

    Wygeneruj i prześlij ten plik symboli, uruchamiając to polecenie wiersza poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    • FIREBASE_APP_ID: identyfikator aplikacji Firebase na Androida (nie nazwa pakietu). Znajdź tę wartość w google-services.json pliku pobranym wcześniej. Jest to wartość mobilesdk_app_id.
      Przykładowy identyfikator aplikacji Firebase na Androida: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS: ścieżka do spakowanego pliku symboli wygenerowanego w katalogu Builds/Android po zakończeniu kompilacji (np. Builds/Android/myapp-1.0-v100.symbols.zip).

Wymuszanie testowego awarii, aby dokończyć konfigurację

Aby dokończyć konfigurowanie Crashlytics i wyświetlić wstępne dane na panelu Crashlytics w konsoli Firebase, musisz wymusić testową awarię.

  1. MainGameScene znajdź EmptyObjectGameObject w edytorze Hierarchy, dodaj do niego ten skrypt, a potem zapisz scenę. Ten skrypt spowoduje testowe awarie kilka sekund po uruchomieniu aplikacji.
    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. Skompiluj aplikację i prześlij informacje o symbolach po zakończeniu kompilacji.
    • iOS: wtyczka Firebase Unity Editor automatycznie konfiguruje projekt Xcode pod kątem przesyłania pliku symboli.
    • Android: uruchom polecenie crashlytics:symbols:upload wiersza poleceń Firebase, aby przesłać plik symboli.
  3. Uruchom aplikację. Gdy będzie działać, obserwuj dziennik urządzenia i poczekaj, aż wyjątek zostanie wywołany z CrashlyticsTester.
    • iOS: logi są widoczne w dolnym panelu Xcode.
    • Android: wyświetl logi, uruchamiając w terminalu to polecenie: adb logcat.
  4. Aby wyświetlić wyjątek, otwórz panel Crashlytics. Znajdziesz go w tabeli Problemy u dołu panelu. W dalszej części ćwiczeń z programowania dowiesz się więcej o tym, jak przeglądać te raporty.
  5. Po potwierdzeniu, że zdarzenie zostało przesłane do Crashlytics, wybierz obiekt EmptyObject GameObject, do którego zostało dołączone, usuń tylko komponent CrashlyticsTester, a następnie zapisz scenę, aby przywrócić ją do pierwotnego stanu.

5. Włączanie i poznawanie menu debugowania

Do tej pory udało Ci się dodać Crashlytics do projektu Unity, zakończyć konfigurację i potwierdzić, że pakiet SDK Crashlytics przesyła zdarzenia do Firebase. Teraz utworzysz w projekcie Unity menu, które pokaże, jak korzystać z bardziej zaawansowanych funkcji Crashlytics w grze. Projekt Unity Level Up with Firebase ma już ukryte menu debugowania, które musisz ujawnić i dodać do niego funkcje.

Włączanie menu debugowania

Przycisk dostępu do menu debugowania istnieje w Twoim projekcie Unity, ale nie jest obecnie włączony. Aby uzyskać dostęp do przycisku z prefabrykatu MainMenu, musisz go włączyć:

  1. W edytorze Unity otwórz prefab o nazwie MainMenu.4148538cbe9f36c5.png
  2. W hierarchii prefabrykatów znajdź wyłączony podobiekt o nazwie DebugMenuButton i wybierz go.816f8f9366280f6c.png
  3. Włącz DebugMenuButton, zaznaczając pole w lewym górnym rogu po lewej stronie pola tekstowego zawierającego DebugMenuButton.8a8089d2b4886da2.png
  4. Zapisz prefabrykat.
  5. Uruchom grę w edytorze lub na urządzeniu. Menu powinno być teraz dostępne.

Wyświetlanie i interpretowanie treści metod w menu debugowania

W dalszej części tego modułu napiszesz treści metod dla niektórych wstępnie skonfigurowanych metod debugowania Crashlytics. W projekcie Unity Level Up with Firebase metody są jednak zdefiniowane w pliku DebugMenu.cs i z niego wywoływane.

Niektóre z tych metod wywołują metody Crashlytics i zgłaszają błędy, ale możliwość przechwytywania tych błędów przez Crashlytics nie zależy od wcześniejszego wywołania tych metod. Raporty o awariach generowane w wyniku automatycznego wykrywania błędów będą wzbogacane o informacje dodawane za pomocą tych metod.

Otwórz DebugMenu.cs i znajdź te metody:

Metody generowania i dodawania adnotacji do problemów w Crashlytics:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

Metody rejestrowania zdarzeń Analytics, które pomagają w debugowaniu:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

W dalszej części tego laboratorium kodu zaimplementujesz te metody i dowiesz się, jak pomagają one w rozwiązywaniu konkretnych sytuacji, które mogą wystąpić podczas tworzenia gier.

6. Zapewnianie dostarczania raportów o awariach w trakcie tworzenia

Zanim zaczniesz wdrażać te metody debugowania i sprawdzać, jak wpływają one na raporty o awariach, upewnij się, że rozumiesz, jak zdarzenia są zgłaszane do Crashlytics.

W przypadku projektów Unity zdarzenia związane z awariami i wyjątkami w grze są natychmiast zapisywane na dysku. W przypadku nieobsłużonych wyjątków, które nie powodują awarii gry (np. nieobsłużonych wyjątków C# w logice gry), możesz skonfigurować pakiet SDK Crashlytics tak, aby zgłaszał je jako zdarzenia krytyczne. W tym celu ustaw właściwość Crashlytics.ReportUncaughtExceptionsAsFatal na true w miejscu, w którym inicjujesz Crashlytics w projekcie Unity. Te zdarzenia są zgłaszane do Crashlytics w czasie rzeczywistym bez konieczności ponownego uruchamiania gry przez użytkownika. Pamiętaj, że awarie natywne są zawsze zgłaszane jako zdarzenia krytyczne i wysyłane, gdy użytkownik końcowy ponownie uruchomi grę.

Pamiętaj też o tych niewielkich, ale istotnych różnicach w sposobie, w jaki różne środowiska wykonawcze wysyłają informacje do Firebase:

Symulator iOS:

  • Informacje z Crashlytics są raportowane tylko wtedy, gdy odłączysz Xcode od symulatora. Jeśli Xcode jest dołączony, wyłapuje błędy na wcześniejszym etapie, co uniemożliwia dostarczanie informacji.

Urządzenia mobilne (Android i iOS):

  • Dotyczy Androida: błędy ANR są zgłaszane tylko w przypadku Androida 11 lub nowszego. Błędy ANR i niekrytyczne zdarzenia są zgłaszane podczas następnego uruchomienia.

Edytor Unity:

Testowanie awarii gry za pomocą jednego kliknięcia w CrashNow()

Po skonfigurowaniu Crashlytics w grze pakiet SDK Crashlytics automatycznie rejestruje awarie i nieobsłużone wyjątki oraz przesyła je do Firebase w celu analizy. Raporty są wyświetlane na panelu Crashlytics w konsoli Firebase.

  1. Aby pokazać, że jest to rzeczywiście automatyczne, otwórz DebugMenu.cs, a następnie zastąp metodę CrashNow() w ten sposób:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. Stwórz aplikację.
  3. (Tylko Android) Prześlij symbole, uruchamiając to polecenie w wierszu poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Kliknij przycisk Crash Now (Awaria teraz) i przejdź do następnego kroku tego samouczka, aby dowiedzieć się, jak wyświetlić i zinterpretować raport o awarii.

7. Informacje o raportach o problemach w konsoli Firebase

Jeśli chodzi o wyświetlanie raportów o awariach, musisz wiedzieć nieco więcej o tym, jak w pełni wykorzystać ich potencjał. Każda z metod, które napiszesz, pokaże, jak dodawać do raportów Crashlytics różne typy informacji.

  1. Kliknij przycisk Crash Now (Wymuś awarię), a potem ponownie uruchom aplikację.
  2. Otwórz panel Crashlytics. Przewiń w dół do tabeli Problemy u dołu panelu, w której Crashlytics grupuje zdarzenia o tej samej przyczynie głównej w „problemy”.
  3. Kliknij nowy problem, który jest wymieniony w tabeli Problemy. Spowoduje to wyświetlenie podsumowania zdarzenia dotyczącego każdego zdarzenia wysłanego do Firebase.

    Powinno to wyglądać podobnie jak na tym zrzucie ekranu. Zwróć uwagę, że w sekcji Podsumowanie zdarzenia jest dobrze widoczny ślad stosu wywołania, które doprowadziło do awarii.40c96abe7f90c3aa.png

Dodatkowe metadane

Kolejną przydatną kartą jest Unity Metadata (Metadane Unity). Ta sekcja zawiera informacje o atrybutach urządzenia, na którym wystąpiło zdarzenie, w tym o cechach fizycznych, modelu i specyfikacji procesora oraz różnych danych dotyczących procesora graficznego.

Oto przykład, w którym informacje na tej karcie mogą być przydatne:
wyobraź sobie, że Twoja gra w dużym stopniu wykorzystuje shadery, aby uzyskać określony wygląd, ale nie wszystkie telefony mają procesory graficzne, które są w stanie renderować tę funkcję. Informacje na karcie Metadane Unity mogą pomóc Ci lepiej określić, na jakim sprzęcie powinna być testowana Twoja aplikacja, gdy decydujesz, które funkcje mają być automatycznie udostępniane lub całkowicie wyłączane.

Chociaż błąd lub awaria mogą nigdy nie wystąpić na Twoim urządzeniu, ze względu na ogromną różnorodność urządzeń z Androidem warto lepiej poznać konkretne „hotspoty” urządzeń Twoich odbiorców.

41d8d7feaa87454d.png

8. Zgłaszanie, przechwytywanie i rejestrowanie wyjątku

Często, nawet jeśli kod dewelopera prawidłowo wykrywa i obsługuje wyjątek czasu działania, warto odnotować, że wystąpił i w jakich okolicznościach. Crashlytics.LogException można użyć właśnie w tym celu – aby wysłać do Firebase zdarzenie wyjątku, dzięki czemu możesz dalej debugować problem w konsoli Firebase.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs dołącz do instrukcji using te informacje:
    // Import Firebase
    using Firebase.Crashlytics;
    
  2. W dalszym ciągu w DebugMenu.cs zastąp LogNonfatalError() w ten sposób:
    void LogNonfatalError()
    {
        try
        {
            throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}");
        }
        catch(System.Exception exception)
        {
            Crashlytics.LogException(exception);
        }
    }
    
  3. Stwórz aplikację.
  4. (Tylko Android) Prześlij symbole, uruchamiając to polecenie w wierszu poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  5. Kliknij przycisk Log Nonfatal Error (Zapisz błąd niekrytyczny), a następnie ponownie uruchom aplikację.
  6. Otwórz panel Crashlytics. Powinien on wyglądać podobnie do tego, co było widoczne w ostatnim kroku tego samouczka.
  7. Tym razem jednak ogranicz filtr Typ zdarzenia do Błędów niekrytycznych, aby wyświetlać tylko błędy niekrytyczne, takie jak ten, który właśnie zarejestrowano.
    a39ea8d9944cbbd9.png

9. Rejestrowanie ciągów znaków w Crashlytics, aby lepiej zrozumieć przebieg wykonywania programu

Czy zdarzyło Ci się kiedyś zastanawiać, dlaczego wiersz kodu wywoływany z wielu ścieżek, setki, a nawet tysiące razy w ciągu sesji, może nagle wygenerować wyjątek lub spowodować awarię? Chociaż prześledzenie kodu w IDE i dokładniejsze przyjrzenie się wartościom może być przydatne, co jeśli problem występuje tylko u bardzo małego odsetka użytkowników? Co gorsza, co zrobisz, jeśli nie uda Ci się odtworzyć tego błędu, niezależnie od tego, co zrobisz?

W takich sytuacjach kontekst może mieć ogromne znaczenie. Dzięki Crashlytics.Log możesz wpisać potrzebny kontekst. Traktuj te wiadomości jako wskazówki dla siebie z przyszłości, które pomogą Ci zrozumieć, co się dzieje.

Dzienniki mogą być używane na wiele sposobów, ale zwykle są najbardziej przydatne do rejestrowania sytuacji, w których kolejność lub brak wywołań jest bardzo ważną informacją.

  1. W polu Assets/Hamster/Scripts/States/DebugMenu.cs zastąp wartość LogStringsAndCrashNow() w ten sposób:
    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. Stwórz aplikację.
  3. (Tylko Android) Prześlij symbole, uruchamiając to polecenie w wierszu poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Kliknij przycisk Log Strings and Crash Now (Zapisz ciągi znaków i spowoduj awarię), a potem uruchom ponownie aplikację.
  5. Wróć do panelu Crashlytics i kliknij najnowszy problem na liście w tabeli Problemy. Ponownie zobaczysz coś podobnego do poprzednich problemów.
    7aabe103b8589cc7.png
  6. Jeśli jednak na karcie DziennikiPodsumowaniu zdarzeń klikniesz
    4e27aa407b7571cf.png, zobaczysz taki widok:

10. Zapisywanie i zastępowanie klucza niestandardowego

Załóżmy, że chcesz lepiej zrozumieć awarię odpowiadającą zmiennym ustawionym na niewielką liczbę wartości lub konfiguracji. Warto byłoby mieć możliwość filtrowania na podstawie kombinacji zmiennych i możliwych wartości, które w danym momencie Cię interesują.

Oprócz rejestrowania dowolnych ciągów znaków Crashlytics oferuje inną formę debugowania, która jest przydatna, gdy chcesz poznać dokładny stan programu w momencie awarii: klucze niestandardowe.

Są to pary klucz-wartość, które możesz ustawić dla sesji. W odróżnieniu od dzienników, które się kumulują i są czysto addytywne, klucze można zastępować, aby odzwierciedlały tylko najnowszy stan zmiennej lub warunku.

Oprócz tego, że klucze te stanowią rejestr ostatniego zarejestrowanego stanu programu, mogą być też używane jako zaawansowane filtry problemów w Crashlytics.

  1. W polu Assets/Hamster/Scripts/States/DebugMenu.cs zastąp wartość SetAndOverwriteCustomKeyThenCrash() w ten sposób:
    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. Stwórz aplikację.
  3. (Tylko Android) Prześlij symbole, uruchamiając to polecenie w wierszu poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Kliknij przycisk Set Custom Key and Crash (Ustaw niestandardowy klucz i awarię), a następnie uruchom ponownie aplikację.
  5. Wróć do panelu Crashlytics i kliknij najnowszy problem na liście w tabeli Problemy. Ponownie zobaczysz coś podobnego do poprzednich problemów.
  6. Tym razem jednak na karcie Klucze w sekcji Podsumowanie zdarzenia możesz wyświetlić wartości kluczy, w tym Current Time:
    7dbe1eb00566af98.png

Dlaczego warto używać kluczy niestandardowych zamiast logów niestandardowych?

  • Dzienniki dobrze sprawdzają się w przypadku przechowywania danych sekwencyjnych, ale klucze niestandardowe są lepsze, jeśli chcesz mieć tylko najnowszą wartość.
  • W konsoli Firebase możesz łatwo filtrować problemy według wartości kluczy w polu wyszukiwania tabeli Problemy.

Podobnie jak w przypadku logów, klucze niestandardowe mają limit. Crashlytics obsługuje maksymalnie 64 pary klucz-wartość. Po osiągnięciu tego progu dodatkowe wartości nie są zapisywane. Każda para klucz-wartość może mieć rozmiar do 1 KB.

11. (Tylko Android) Używanie kluczy niestandardowych i dzienników do analizowania i diagnozowania błędów ANR

Jednym z najtrudniejszych do debugowania problemów dla deweloperów Androida jest błąd Aplikacja nie odpowiada (ANR). Błędy ANR występują, gdy aplikacja nie odpowiada na dane wejściowe przez ponad 5 sekund. Jeśli tak się stanie, oznacza to, że aplikacja zawiesiła się lub działa bardzo wolno. Użytkownikom wyświetla się okno, w którym mogą wybrać opcję „Poczekaj” lub „Zamknij aplikację”.

Błędy ANR negatywnie wpływają na wrażenia użytkowników i (jak wspomnieliśmy w linku powyżej) mogą utrudniać odkrycie Twojej aplikacji w Sklepie Google Play. Ze względu na ich złożoność i fakt, że często są one spowodowane przez kod wielowątkowy, który na różnych modelach telefonów zachowuje się zupełnie inaczej, odtworzenie błędów ANR podczas debugowania jest często bardzo trudne, a nawet niemożliwe. Dlatego najlepszym podejściem jest zwykle analiza i dedukcja.

W tej metodzie będziemy używać kombinacji Crashlytics.LogException, Crashlytics.LogCrashlytics.SetCustomKey, aby uzupełniać automatyczne rejestrowanie problemów i uzyskiwać więcej informacji.

  1. W polu Assets/Hamster/Scripts/States/DebugMenu.cs zastąp wartość SetLogsAndKeysBeforeANR() w ten sposób:
    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. Stwórz aplikację.
  3. Prześlij symbole, uruchamiając to polecenie wiersza poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Kliknij przycisk Set Logs And Keys → ANR, a następnie ponownie uruchom aplikację.
  5. Wróć do panelu Crashlytics, a potem kliknij nowy problem w tabeli Problemy, aby wyświetlić Podsumowanie zdarzeń. Jeśli wywołanie przebiegło prawidłowo, zobaczysz coś takiego:
    876c3cff7037bd07.png

    Jak widać, Firebase wskazał, że główną przyczyną błędu ANR w Twojej aplikacji było długie oczekiwanie wątku.
  6. Jeśli w dziennikach na karcie DziennikiPodsumowaniu zdarzeń sprawdzisz ostatnią metodę zarejestrowaną jako ukończoną, zobaczysz DoSevereWork.
    5a4bec1cf06f6984.png

    . Ostatnią metodą zarejestrowaną jako rozpoczętą jest natomiast DoExtremeWork, co oznacza, że błąd ANR wystąpił podczas tej metody, a gra została zamknięta, zanim udało się zarejestrować DoExtremeWork.

    89d86d5f598ecf3a.png

Jakie są korzyści?

  • Odtwarzanie błędów ANR jest niezwykle trudne, dlatego możliwość uzyskania szczegółowych informacji o obszarze kodu i danych ma ogromne znaczenie w przypadku wnioskowania o przyczynach tych błędów.
  • Dzięki informacjom przechowywanym w kluczach niestandardowych wiesz teraz, który wątek asynchroniczny działał najdłużej i które z nich były zagrożone wywołaniem błędów ANR. Takie powiązane dane logiczne i numeryczne pokażą Ci, które części kodu wymagają optymalizacji.

12. Wplatanie zdarzeń Analytics w celu wzbogacenia raportów

Poniższe metody można też wywoływać z menu debugowania, ale zamiast generować problemy, korzystają one z Google Analytics jako innego źródła informacji, aby lepiej zrozumieć działanie gry.

W przeciwieństwie do innych metod opisanych w tym laboratorium kodu te metody należy stosować w połączeniu z innymi. Wywołuj te metody (naciskając odpowiedni przycisk w menu debugowania) w dowolnej kolejności przed uruchomieniem jednej z pozostałych. Gdy sprawdzisz informacje o konkretnym problemie w Crashlytics, zobaczysz uporządkowany dziennik zdarzeń Analytics. Dane te mogą być używane w grze, aby lepiej zrozumieć kombinację przepływu programu lub danych wejściowych użytkownika, w zależności od tego, jak skonfigurowano aplikację.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs zastąp istniejące implementacje tych metod:
    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. Zbuduj i wdroż grę, a następnie otwórz menu debugowania.
  3. (Tylko Android) Prześlij symbole, uruchamiając to polecenie w wierszu poleceń Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Naciśnij co najmniej jeden z tych przycisków co najmniej raz, aby wywołać powyższe funkcje:
    • Zdarzenie Log String
    • Log Int Event
  5. Naciśnij przycisk Crash Now (Awaria teraz).
  6. Uruchom ponownie grę, aby przesłać zdarzenie awarii do Firebase.
  7. Gdy rejestrujesz różne dowolne sekwencje zdarzeń Analytics, a potem gra generuje zdarzenie, na podstawie którego Crashlytics tworzy raport (tak jak w tym przypadku), zdarzenia te są dodawane do karty Dziennikipodsumowaniu zdarzeń Crashlytics w ten sposób:
    d3b16d78f76bfb04.png

13. Dalsze działania

Dzięki temu będziesz mieć lepsze podstawy teoretyczne do uzupełniania automatycznie generowanych raportów o awariach. Te nowe informacje pozwalają Ci korzystać z bieżącego stanu, zapisów poprzednich zdarzeń i dotychczasowych zdarzeń Google Analytics, aby lepiej analizować sekwencję zdarzeń i logikę, które doprowadziły do danego wyniku.

Jeśli Twoja aplikacja jest kierowana na Androida 11 (API na poziomie 30) lub nowszego, rozważ wdrożenie GWP-ASan, czyli natywnej funkcji przydzielania pamięci, która jest przydatna do debugowania awarii spowodowanych przez błędy natywnej pamięci, takie jak błędy use-after-freeheap-buffer-overflow. Aby korzystać z tej funkcji debugowania, wyraźnie włącz GWP-ASan.

Następne kroki

Przejdź do samouczka dotyczącego implementowania Zdalnej konfiguracji w grze na platformie Unity, w którym dowiesz się, jak używać Zdalnej konfiguracji i testów A/B w Unity.