使用高級 Crashlytics 功能了解 Unity 遊戲的崩潰

一、簡介

在此 Codelab 中,您將學習如何使用 Crashlytics 的高級功能,這將使您更了解崩潰以及可能導致崩潰的情況。

您將為範例遊戲MechaHamster: Level Up with Firebase Edition新增功能。此範例遊戲是經典 Firebase 遊戲 MechaHamster 的新版本,刪除了大部分內建 Firebase 功能,讓您有機會在原來的位置實現 Firebase 的新用途。

您將向遊戲添加調試菜單。此偵錯功能表呼叫您將建立的方法,並允許您練習 Crashlytics 的不同功能。這些方法將向您展示如何使用自訂鍵、自訂日誌、非致命錯誤等來註解自動崩潰報告。

建立遊戲後,您將使用偵錯選單,並檢查結果以了解它們為您的遊戲在野外運行方式提供的獨特視圖。

你將學到什麼

  • Crashlytics 自動捕獲的錯誤類型。
  • 可以有目的地記錄的其他錯誤。
  • 如何為這些錯誤添加更多資訊以使它們更容易理解。

你需要什麼

  • Unity(最低推薦版本 2019+)有以下一項或兩項:
    • iOS 建置支援
    • Android 建置支援
  • (僅適用於 Android) Firebase CLI(用於上傳崩潰報告的符號)

2. 設定您的開發環境

以下部分介紹如何下載Level Up with Firebase程式碼並在 Unity 中開啟它。

請注意,此Level Up with Firebase範例遊戲已被其他幾個 Firebase + Unity Codelab 使用,因此您可能已經完成了本部分中的任務。如果是這樣,您可以直接轉到此頁面的最後一步:「為 Unity 新增 Firebase SDK」。

下載程式碼

從命令列克隆此 Codelab 的GitHub 儲存庫

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

或者,如果您沒有安裝 git,則可以將儲存庫下載為 ZIP 檔案

在 Unity 編輯器中使用 Firebase 開啟 Level Up

  1. 啟動 Unity Hub,然後從「專案」標籤中按一下「開啟」旁邊的下拉箭頭
  2. 按一下從磁碟新增項目
  3. 導航至包含程式碼的目錄,然後按一下「確定」
  4. 如果出現提示,請選擇要使用的 Unity 編輯器版本以及您的目標平台(Android 或 iOS)。
  5. 按一下專案名稱level-up-with-firebase ,該專案將在 Unity 編輯器中開啟。
  6. 如果您的編輯器沒有自動開啟它,請在 Unity 編輯器的「專案」標籤中的「資源」 > “Hamster”中開啟MainGameScene
    ff4ea3f3c0d29379.png

有關安裝和使用 Unity 的更多信息,請參閱在 Unity 中工作

3. 將 Firebase 新增到您的 Unity 項目

創建 Firebase 項目

  1. Firebase 控制台中,按一下新增項目
  2. 若要建立新項目,請輸入所需的項目名稱。
    這也將根據項目名稱將項目 ID(顯示在項目名稱下方)設定為某些內容。您可以選擇單擊項目 ID 上的編輯圖示以進一步自訂它。
  3. 如果出現提示,請查看並接受Firebase 條款
  4. 單擊繼續
  5. 選擇為此項目啟用 Google Analytics選項,然後按一下繼續
  6. 選擇要使用的現有 Google Analytics 帳戶,或選擇建立新帳戶來建立新帳戶。
  7. 點選建立項目
  8. 建立項目後,按一下「繼續」

向 Firebase 註冊您的應用

  1. 仍然在Firebase 控制台中,從項目概述頁面的中心,按一下 Unity 圖示以啟動設定工作流程,或者,如果您已將應用程式新增至 Firebase 項目,請按一下新增應用程式以顯示平台選項。
  2. 選擇註冊 Apple (iOS) 和 Android 建置目標。
  3. 輸入 Unity 專案的平台特定 ID。對於此 Codelab,請輸入以下內容:
  4. (可選)輸入 Unity 項目的平台特定暱稱。
  5. 點擊註冊應用程序,然後轉到下載設定檔部分。

新增 Firebase 設定檔

點擊Register app後,系統將提示您下載兩個設定檔(每個建置目標一個設定檔)。您的 Unity 專案需要這些檔案中的 Firebase 元資料才能與 Firebase 連線。

  1. 下載兩個可用的設定檔:
    • 對於 Apple (iOS) :下載GoogleService-Info.plist
    • 對於 Android :下載google-services.json
  2. 開啟 Unity 專案的「專案」窗口,然後將兩個設定檔移至Assets資料夾。
  3. 返回 Firebase 控制台的設定工作流程中,按一下下一步並繼續新增適用於 Unity 的 Firebase SDK。

新增適用於 Unity 的 Firebase SDK

  1. 按一下 Firebase 控制台中的「下載 Firebase Unity SDK」
  2. 將 SDK 解壓縮到方便的地方。
  3. 在開啟的 Unity 專案中,導覽至Assets > Import Package > Custom Package
  4. 「導入套件」對話方塊中,導覽至包含解壓縮的 SDK 的目錄,選擇FirebaseAnalytics.unitypackage ,然後按一下「開啟」
  5. 在出現的「匯入 Unity 套件」對話方塊中,按一下「匯入」
  6. 重複前面的步驟以導入FirebaseCrashlytics.unitypackage
  7. 返回 Firebase 控制台,然後在設定工作流程中按一下「下一步」

有關將 Firebase SDK 添加到 Unity 專案的更多信息,請參閱其他 Unity 安裝選項

4. 在 Unity 專案中設定 Crashlytics

要在 Unity 專案中使用 Crashlytics,您需要執行更多設定步驟。當然,您需要初始化SDK。而且,您還需要上傳符號,以便可以在 Firebase 控制台中看到符號化的堆疊跟踪,並且需要強制測試崩潰以確保 Firebase 獲取崩潰事件。

初始化 Crashlytics SDK

  1. Assets/Hamster/Scripts/MainGame.cs中,加入以下using語句:
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    第一個模組可讓您使用 Crashlytics SDK 中的方法,第二個模組包含C# Tasks API的一些擴充。如果沒有這兩個using語句,下面的程式碼將無法運作。
  2. 仍在MainGame.cs中,透過呼叫InitializeFirebaseAndStartGame()將 Firebase 初始化新增至現有Start()方法:
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. 再一次,在MainGame.cs中,找到InitializeFirebaseAndStartGame() ,宣告一個 app 變量,然後覆寫該方法的實現,如下所示:
    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+(蘋果平台)

  1. 「建置設定」對話方塊中,將專案匯出到 Xcode 工作區。
  2. 建立您的應用程式。
    對於 Apple 平台,Firebase Unity 編輯器外掛程式會自動設定您的 Xcode 項目,以便為每個建置產生相容 Crashlytics 的符號檔案並將其上傳到 Firebase 伺服器。需要此符號資訊才能在 Crashlytics 儀表板中查看符號化堆疊追蹤。

安卓

  1. (僅在初始設定期間,不適用於每個建置)設定您的建置:
    1. 在專案目錄的根目錄下建立一個名為Builds的新資料夾(即,作為Assets目錄的同級資料夾),然後建立一個名為Android的子資料夾。
    2. File > Build Settings > Player Settings > Configuration中,將 Scripting Backend 設定為 IL2CPP。
      • IL2CPP 通常會導致建置更小並具有更好的效能。
      • IL2CPP 也是 iOS 上唯一可用的選項,在這裡選擇它可以使兩個平台具有更好的一致性,並使兩者之間的調試差異(如果您選擇構建兩者)更簡單。
  2. 建立您的應用程式。在File > Build Settings中,完成以下操作:
    1. 確保選取“建立符號.zip” (或如果出現下拉列表,請選擇“調試”)。
    2. 直接從 Unity 編輯器將 APK 建置到您剛剛建立的Builds/Android子資料夾中。
  3. 建置完成後,您需要產生與 Crashlytics 相容的符號檔案並將其上傳到 Firebase 伺服器。需要此符號資訊才能在 Crashlytics 儀表板中查看本機庫崩潰的符號化堆疊追蹤。

    透過執行以下Firebase CLI指令產生並上傳此符號檔:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    • FIREBASE_APP_ID :您的 Firebase Android 應用程式 ID(不是您的套件名稱)。在您之前下載的google-services.json檔案中找到該值。這是mobilesdk_app_id值。
      範例 Firebase Android 應用程式 ID: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS :建置完成後在Builds/Android目錄中產生的壓縮符號檔案的路徑(例如: Builds/Android/myapp-1.0-v100.symbols.zip )。

強制測試崩潰以完成設置

要完成 Crashlytics 的設定並在 Firebase 控制台的 Crashlytics 儀表板中查看初始數據,您需要強制測試崩潰。

  1. MainGameScene 的編輯器Hierarchy中找到EmptyObject 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 :Firebase Unity 編輯器外掛程式會自動設定您的 Xcode 專案以上傳符號檔案。
    • Android :執行 Firebase CLI crashlytics:symbols:upload指令來上傳符號檔。
  3. 運行您的應用程式。應用程式運行後,觀察設備日誌並等待CrashlyticsTester觸發異常。
    • iOS :在 Xcode 底部窗格中查看日誌。
    • Android :透過在終端機中執行以下命令來查看日誌: adb logcat
  4. 造訪Crashlytics 儀表板查看異常!您將在儀表板底部的問題表中看到它。稍後在 Codelab 中,您將詳細了解如何探索這些報告。
  5. 確認事件已上傳至 Crashlytics 後,選擇您附加到的EmptyObject GameObject ,僅刪除CrashlyticsTester元件,然後儲存場景以將其恢復到原始狀態。

5. 啟用並了解調試選單

到目前為止,您已將 Crashlytics 新增至 Unity 專案、完成設定並確認 Crashlytics SDK 正在將事件上傳到 Firebase。現在,您將在 Unity 專案中建立一個選單,該選單將示範如何在遊戲中使用更高級的 Crashlytics 功能。 Level Up with Firebase Unity 專案已經有一個隱藏的偵錯選單,您將使其可見並為其編寫功能。

啟用調試選單

您的 Unity 專案中存在用於存取偵錯功能表的按鈕,但目前未啟用。您必須啟用該按鈕才能從MainMenu預製件中存取它:

  1. 在 Unity 編輯器中,開啟名為MainMenu的預製件。 4148538cbe9f36c5.png
  2. 在預製件層次結構中,找到名為DebugMenuButton停用子對象,然後選擇它。 816f8f9366280f6c.png
  3. 透過選取包含DebugMenuButton文字欄位左側左上角的方塊來啟用DebugMenuButton8a8089d2b4886da2.png
  4. 保存預製件。
  5. 在編輯器或您的裝置上執行遊戲。現在應該可以存取菜單了。

預覽並了解調試菜單的方法體

稍後在此 Codelab 中,您將為一些預先配置的偵錯 Crashlytics 方法編寫方法體。不過,在Level Up with Firebase Unity 專案中,這些方法是在DebugMenu.cs中定義並呼叫的。

雖然其中一些方法將呼叫 Crashlytics 方法並引發錯誤,但 Crashlytics 捕獲這些錯誤的能力並不依賴先呼叫這些方法。相反,自動捕獲錯誤產生的崩潰報告將透過這些方法添加的資訊得到增強。

開啟DebugMenu.cs ,然後找到以下方法:

產生和註釋 Crashlytics 問題的方法:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

用於記錄 Analytics 事件以幫助偵錯的方法:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

在此 Codelab 的後續步驟中,您將實現這些方法並了解它們如何幫助解決遊戲開發中可能出現的特定情況。

6. 確保開發過程中崩潰報告的交付

在開始實作這些偵錯方法並查看它們如何影響崩潰報告之前,請確保您了解如何將事件報告給 Crashlytics。

對於 Unity 項目,遊戲中的崩潰和異常事件會立即寫入磁碟。對於不會導致遊戲崩潰的未捕獲異常(例如,遊戲邏輯中未捕獲的 C# 異常),您可以在 Unity 專案中初始化 Crashlytics時將Crashlytics.ReportUncaughtExceptionsAsFatal屬性設為true ,讓 Crashlytics SDK 將它們報告為致命事件。這些事件會即時報告給 Crashlytics,而無需最終用戶重新啟動遊戲。請注意,本機崩潰始終會報告為致命事件,並在最終用戶重新啟動遊戲時發送。

此外,請注意不同執行時間環境向 Firebase 發送 Crashlytics 資訊的方式之間存在以下微小但重要的差異:

iOS模擬器:

  • 當且僅當您從模擬器中分離 Xcode 時,才會報告 Crashlytics 資訊。如果附加了 Xcode,它會捕獲上游的錯誤,從而阻止訊息傳遞。

行動實體裝置(Android 和 iOS):

  • Android 特定:僅在 Android 11+ 上報告 ANR。 ANR 和非致命事件將在下次運行時報告。

統一編輯器:

測試在CrashNow()中按一下按鈕會導致遊戲崩潰

在遊戲中設定 Crashlytics 後,Crashlytics SDK 會自動記錄崩潰和未捕獲的異常,並將其上傳到 Firebase 進行分析。報告顯示在 Firebase 控制台的Crashlytics 儀表板中。

  1. 要證明這確實是自動的:開啟DebugMenu.cs ,然後覆寫方法CrashNow()如下所示:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. 建立您的應用程式。
  3. (僅限 Android)透過執行以下 Firebase CLI 指令上傳符號:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. 點擊「立即崩潰」按鈕,然後繼續執行此 Codelab 的下一步,了解如何查看和解釋崩潰報告。

7. 了解 Firebase 控制台中的問題報告

在查看崩潰報告時,您需要了解更多有關如何充分利用它們的資訊。您編寫的每種方法都將展示如何將不同類型的信息添加到 Crashlytics 報告中。

  1. 點擊“立即崩潰”按鈕,然後重新啟動您的應用程式。
  2. 轉到Crashlytics 儀表板。向下捲動到儀表板底部的「問題」表,其中 Crashlytics 將所有具有相同根本原因的事件分組為「問題」。
  3. 按一下問題表中列出的新問題。執行此操作會顯示傳送至 Firebase 的每個單獨事件的事件摘要

    您應該會看到類似以下螢幕截圖的內容。請注意事件摘要如何突出顯示導致崩潰的呼叫的堆疊追蹤。 40c96abe7f90c3aa.png

附加元數據

另一個有用的選項卡是「Unity 元資料」標籤。本部分向您介紹發生事件的裝置的屬性,包括實體功能、CPU 型號/規格以及各種 GPU 指標。

以下是此選項卡中的信息可能有用的範例:
想像一下,您的遊戲大量使用著色器來實現某種外觀,但並非所有手機都具有能夠渲染此功能的 GPU。 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 儀表板,您應該會看到與此 Codelab 最後一步中看到的內容類似的內容。
  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 KB。

11.(僅限 Android)使用自訂鍵和日誌來了解和診斷 ANR

對於 Android 開發人員來說,最難調試的一類問題是應用程式無回應(ANR) 錯誤。當應用程式無法回應輸入超過 5 秒時,就會發生 ANR。如果發生這種情況,則表示應用程式要么凍結,要么運行速度非常慢。將向用戶顯示一個對話框,他們可以選擇是「等待」還是「關閉應用程式」。

ANR 是一種糟糕的使用者體驗,並且(如上面的 ANR 連結中所述)可能會影響您的應用程式在 Google Play 商店中的可發現性。由於它們的複雜性,而且它們通常是由在不同手機型號上行為截然不同的多執行緒程式碼引起的,因此在調試時重現 ANR 通常非常困難,甚至幾乎不可能。因此,透過分析和演繹的方式來處理它們通常是最好的方法。

在此方法中,我們將使用Crashlytics.LogExceptionCrashlytics.LogCrashlytics.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. 點擊標記為Set Logs And Keys → ANR 的按鈕,然後重新啟動您的應用程式。
  5. 返回Crashlytics 儀表板,然後按一下問題表中的新問題以查看事件摘要。如果呼叫正常進行,您應該看到如下內容:
    876c3cff7037bd07.png

    如您所見,Firebase 指出線程上的繁忙等待是您的應用程式觸發 ANR 的主要原因。
  6. 如果您查看「事件摘要」「日誌」標籤中的日誌,您將看到最後記錄為完成的方法是DoSevereWork
    5a4bec1cf06f6984.png

    相較之下,最後列出的啟動方法是DoExtremeWork ,這表明在此方法期間發生了 ANR,並且遊戲在記錄DoExtremeWork之前就關閉了。

    89d86d5f598ecf3a.png

為什麼要這樣做?

  • 重現 ANR 非常困難,因此能夠獲得有關程式碼區域和指標的豐富資訊對於演繹地找出它非常重要。
  • 透過儲存在自訂鍵中的信息,您現在可以知道哪個非同步執行緒運行時間最長,以及哪些執行緒有觸發 ANR 的危險。這種相關的邏輯和數字資料將向您顯示程式碼中最需要最佳化的位置。

12. 穿插Analytics事件,進一步豐富報告

也可以從「偵錯」功能表呼叫以下方法,但它們本身不會產生問題,而是使用 Google Analytics 作為另一個資訊來源,以便更好地了解遊戲的工作原理。

與您在此 Codelab 中編寫的其他方法不同,您應該將這些方法與其他方法結合使用。在運行其他方法之一之前,以您想要的任意順序呼叫這些方法(透過按偵錯功能表中對應的按鈕)。然後,當您檢查特定 Crashlytics 問題中的資訊時,您將看到 Analytics 事件的有序日誌。這些數據可用於遊戲中,以便更好地理解程式流程或使用者輸入的組合,具體取決於您如何檢測應用程式。

  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. 當您記錄各種任意的 Analytics 事件序列,然後讓您的遊戲產生一個事件,Crashlytics 從中建立一個報告(就像您剛剛所做的那樣)時,它們會添加到 Crashlytics事件摘要「日誌」標籤中,如下圖所示:
    d3b16d78f76bfb04.png

13. 展望未來

這樣,您應該有更好的理論基礎來補充自動產生的崩潰報告。這些新資訊可讓您使用當前狀態、過去事件的記錄和現有的 Google Analytics 事件來更好地分解事件的順序和導致其結果的邏輯。

如果您的應用程式面向 Android 11(API 等級 30)或更高版本,請考慮合併GWP-ASan ,這是本機記憶體分配器功能,可用於偵錯由本機記憶體錯誤(例如use-after-freeheap-buffer-overflow錯誤)造成的崩潰。若要利用此偵錯功能,請明確啟用 GWP-ASan

下一步

繼續使用遠端配置測試您的 Unity 遊戲Codelab,您將在其中了解如何在 Unity 中使用遠端配置和 A/B 測試。