1. 簡介
在本程式碼研究室中,您將瞭解如何使用 Crashlytics 的進階功能,更清楚掌握當機情形,以及可能導致當機的狀況。
您將為範例遊戲「MechaHamster: Level Up with Firebase Edition」新增功能。這個遊戲範例是經典 Firebase 遊戲 MechaHamster 的新版本,移除了大部分內建的 Firebase 功能,讓您有機會實作新的 Firebase 用途。
您將在遊戲中新增偵錯選單。這個偵錯選單會呼叫您建立的方法,並讓您使用 Crashlytics 的不同功能。這些方法會說明如何使用自訂鍵、自訂記錄、非致命錯誤等項目,為自動當機報告加上註解。
建構遊戲後,您可以使用偵錯選單檢查結果,瞭解這些結果提供的獨特檢視畫面,進而掌握遊戲在實際環境中的執行方式。
課程內容
- Crashlytics 會自動偵測的錯誤類型。
- 可刻意記錄的其他錯誤。
- 如何為這些錯誤新增更多資訊,方便瞭解。
事前準備
- Unity (建議最低版本為 2019 以上),並具備下列一或兩項:
- 支援 iOS 建構作業
- Android 版本支援
- (僅適用於 Android) Firebase CLI (用於上傳當機報告的符號)
- 按照操作說明安裝 Firebase CLI。
如果您已安裝 CLI,請務必更新至最新版本。
- 按照操作說明安裝 Firebase CLI。
2. 設定開發環境
以下各節說明如何下載「Level Up with Firebase」程式碼,並在 Unity 中開啟。
請注意,其他幾個 Firebase + Unity 程式碼研究室也會使用這個「Level Up with Firebase」範例遊戲,因此您可能已完成本節中的工作。如果是,您可以直接前往本頁的最後一個步驟:「新增適用於 Unity 的 Firebase SDK」。
下載程式碼
從指令列複製本程式碼研究室的 GitHub 存放區:
git clone https://github.com/firebase/level-up-with-firebase.git
或者,如果您未安裝 Git,可以將存放區下載為 ZIP 檔案。
在 Unity 編輯器中開啟「Level Up with Firebase」
- 啟動 Unity Hub,然後在「Projects」(專案) 分頁中,按一下「Open」(開啟) 旁邊的下拉式箭頭。
- 按一下「從磁碟新增專案」。
- 前往包含程式碼的目錄,然後按一下「確定」。
- 如果系統提示,請選取要使用的 Unity 編輯器版本和目標平台 (Android 或 iOS)。
- 按一下專案名稱「level-up-with-firebase」,專案就會在 Unity 編輯器中開啟。
- 如果編輯器未自動開啟,請在 Unity 編輯器的「Project」分頁中,依序開啟「Assets」 >「Hamster」。
MainGameScene
如要進一步瞭解如何安裝及使用 Unity,請參閱「在 Unity 中工作」。
3. 將 Firebase 新增至 Unity 專案
建立 Firebase 專案
- 使用 Google 帳戶登入 Firebase 控制台。
- 按一下按鈕建立新專案,然後輸入專案名稱 (例如
Mechahamster Codelab)。
- 按一下「繼續」。
- 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」。
- (選用) 在 Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」)。
- 在本程式碼研究室中,您需要 Google Analytics 才能充分運用 Firebase 產品,因此請開啟 Google Analytics 選項的切換按鈕。按照畫面上的指示設定 Google Analytics。
- 按一下「建立專案」,等待專案佈建完成,然後按一下「繼續」。
向 Firebase 註冊應用程式
- 在 Firebase 控制台中,從專案總覽頁面中央點按 Unity 圖示,啟動設定工作流程。如果已將應用程式新增至 Firebase 專案,請點按「新增應用程式」,顯示平台選項。
- 選取要同時註冊 Apple (iOS) 和 Android 版本目標。
- 輸入 Unity 專案的平台專屬 ID。在本程式碼研究室中,請輸入以下內容:
- (選用) 輸入 Unity 專案的平台專屬暱稱。
- 按一下「註冊應用程式」,然後前往「下載設定檔」部分。
新增 Firebase 設定檔
按一下「註冊應用程式」後,系統會提示您下載兩個設定檔 (每個建構目標各一個設定檔)。Unity 專案需要這些檔案中的 Firebase 中繼資料,才能連結至 Firebase。
- 下載兩個可用的設定檔:
- Apple (iOS):下載 GoogleService-Info.plist。
- Android:下載 google-services.json。
- 開啟 Unity 專案的「Project」視窗,然後將兩個設定檔都移入「Assets」資料夾。
- 返回 Firebase 主控台,在設定工作流程中點選「下一步」,然後繼續新增適用於 Unity 的 Firebase SDK。
新增 Firebase Unity SDK
- 在 Firebase 主控台中,按一下「下載 Firebase Unity SDK」。
- 將 SDK 解壓縮至方便使用的位置。
- 在開啟的 Unity 專案中,依序前往「Assets」 >「Import Package」 >「Custom Package」。
- 在「Import package」對話方塊中,前往包含已解壓縮 SDK 的目錄,選取
FirebaseAnalytics.unitypackage,然後按一下「Open」。 - 在隨即顯示的「Import Unity Package」對話方塊中,按一下「Import」。
- 重複上述步驟,匯入
FirebaseCrashlytics.unitypackage。 - 返回 Firebase 控制台,然後在設定工作流程中按一下「下一步」。
如要進一步瞭解如何將 Firebase SDK 新增至 Unity 專案,請參閱「其他 Unity 安裝選項」。
4. 在 Unity 專案中設定 Crashlytics
如要在 Unity 專案中使用 Crashlytics,您還需要完成幾個設定步驟。當然,您需要初始化 SDK。此外,您還需要上傳符號,才能在 Firebase 控制台中查看經過符號化的堆疊追蹤記錄,並強制測試當機,確保 Firebase 收到當機事件。
初始化 Crashlytics SDK
- 在
Assets/Hamster/Scripts/MainGame.cs中新增下列using陳述式: 第一個模組可讓您使用 Crashlytics SDK 的方法,第二個模組則包含 C# Tasks API 的部分擴充功能。如果缺少其中一個using Firebase.Crashlytics; using Firebase.Extensions;using陳述式,下列程式碼就無法運作。 - 在
MainGame.cs中,呼叫InitializeFirebaseAndStartGame(),將 Firebase 初始化作業新增至現有的Start()方法:void Start() { Screen.SetResolution(Screen.width / 2, Screen.height / 2, true); InitializeFirebaseAndStartGame(); } - 同樣地,在
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 平台)
- 在「Build Settings」對話方塊中,將專案匯出至 Xcode 工作區。
- 建構應用程式。
如果是 Apple 平台,Firebase Unity 編輯器外掛程式會自動設定 Xcode 專案,為每個建構作業產生並上傳與 Crashlytics 相容的符號檔案至 Firebase 伺服器。您必須提供這些符號資訊,才能在 Crashlytics 資訊主頁中查看符號化的堆疊追蹤。
Android
- (僅限初始設定期間,不適用於每個版本)設定版本:
- 在專案目錄的根層級 (即「Assets」目錄的同層級) 建立名為「Builds」的新資料夾,然後建立名為「Android」的子資料夾。
- 依序前往「File」>「Build Settings」>「Player Settings」>「Configuration」,將「Scripting Backend」設為「IL2CPP」。
- 一般來說,IL2CPP 會縮小建構大小並提升效能。
- IL2CPP 也是 iOS 上唯一可用的選項,在此選取這個選項可讓這兩個平台更趨於一致,並簡化兩者之間的偵錯差異 (如果您選擇同時建構兩者)。
- 建構應用程式。在「File」 >「Build Settings」中,完成下列步驟:
- 請務必勾選「建立 symbols.zip」 (或選取下拉式選單中的「偵錯」)。
- 直接從 Unity 編輯器將 APK 建構到剛建立的 Builds/Android 子資料夾。
- 建構完成後,您需要產生與 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:17104a2ced0c9b9bPATH/TO/SYMBOLS:建構完成時,在「Builds/Android」目錄中產生的符號 ZIP 檔案路徑 (例如:Builds/Android/myapp-1.0-v100.symbols.zip)。
強制測試當機以完成設定
您需要強制測試當機,才能完成設定 Crashlytics,並在 Firebase 控制台的 Crashlytics 資訊主頁中看見初始資料。
- 在 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"); } } } - 建構應用程式,並在建構完成後上傳符號資訊。
- iOS:Firebase Unity 編輯器外掛程式會自動設定 Xcode 專案,以上傳符號檔案。
- Android:執行 Firebase CLI
crashlytics:symbols:upload指令,上傳符號檔案。
- 執行應用程式。應用程式執行後,請查看裝置記錄,並等待
CrashlyticsTester觸發例外狀況。- iOS:在 Xcode 的底部窗格中查看記錄。
- Android:在終端機中執行
adb logcat指令,即可查看記錄。
- 前往 Crashlytics 資訊主頁查看例外狀況!您可以在資訊主頁底部的「問題」表格中查看。在本程式碼研究室的後續部分,您將進一步瞭解如何查看這些報表。
- 確認事件已上傳至 Crashlytics 後,選取附加事件的「EmptyObject」
GameObject,只移除CrashlyticsTester元件,然後儲存場景,將其還原為原始狀態。
5. 啟用及瞭解偵錯選單
到目前為止,您已將 Crashlytics 新增至 Unity 專案、完成設定,並確認 Crashlytics SDK 會將事件上傳至 Firebase。您現在要在 Unity 專案中建立選單,示範如何在遊戲中使用更進階的 Crashlytics 功能。「Level Up with Firebase」Unity 專案已具備隱藏的「Debug Menu」,您將顯示這個選單並編寫相關功能。
啟用偵錯選單
Unity 專案中設有存取「偵錯選單」的按鈕,但目前未啟用。您必須啟用按鈕,才能從 MainMenu 預先設定的項目存取按鈕:
- 在 Unity 編輯器中,開啟名為
MainMenu的預製物件。
- 在預先建構的階層中,找出名為
DebugMenuButton的已停用子物件,然後選取該物件。
- 勾選文字欄位左側左上角的核取方塊,啟用
DebugMenuButton。
DebugMenuButton - 儲存預製物件。
- 在編輯器或裝置上執行遊戲。現在應該可以存取選單了。
預覽及瞭解「偵錯選單」的方法主體
在本程式碼研究室的後續部分,您將為一些預先設定的 Crashlytics 偵錯方法編寫方法主體。不過,在「Level Up with Firebase」Unity 專案中,方法是在 DebugMenu.cs 中定義及呼叫。
雖然部分方法會同時呼叫 Crashlytics 方法並擲回錯誤,但 Crashlytics 擷取這些錯誤的能力,並非取決於是否先呼叫這些方法。而是會透過這些方法新增的資訊,強化自動擷取錯誤時產生的當機報告。
開啟 DebugMenu.cs,然後找出下列方法:
產生及註解 Crashlytics 問題的方法:
CrashNowLogNonfatalErrorLogStringsAndCrashNowSetAndOverwriteCustomKeyThenCrashSetLogsAndKeysBeforeANR
記錄 Analytics 事件的方法,有助於偵錯:
LogProgressEventWithStringLiteralsLogIntScoreWithBuiltInEventAndParams
在本程式碼研究室的後續步驟中,您將實作這些方法,並瞭解這些方法如何協助解決遊戲開發過程中可能發生的特定情況。
6. 確保在開發期間傳送當機報告
開始導入這些偵錯方法並瞭解其對當機報告的影響前,請務必先瞭解事件回報給 Crashlytics 的方式。
如果是 Unity 專案,遊戲中的當機和例外狀況事件會立即寫入磁碟。對於不會導致遊戲當機的未偵測到例外狀況 (例如遊戲邏輯中未偵測到的 C# 例外狀況),您可以將 Crashlytics.ReportUncaughtExceptionsAsFatal 屬性設為 true,讓 Crashlytics SDK 將這些例外狀況回報為嚴重事件。您可以在 Unity 專案中初始化 Crashlytics 時進行這項設定。系統會即時向 Crashlytics 回報這些事件,使用者不必重新啟動遊戲。請注意,系統一律會將原生當機情形回報為重大事件,並在使用者重新啟動遊戲時一併傳送。
此外,請注意以下細微但重要的差異:不同執行階段環境將 Crashlytics 資訊傳送至 Firebase 的方式有所不同:
iOS 模擬器:
- 只有在將 Xcode 從模擬器中分離時,系統才會回報 Crashlytics 資訊。如果附加 Xcode,Xcode 會在上游擷取錯誤,防止資訊傳送。
行動實體裝置 (Android 和 iOS):
- Android 專屬:系統只會回報 Android 11 以上版本發生的 ANR。ANR 和不嚴重事件會在下次執行時回報。
Unity 編輯器:
- 在播放模式或獨立模式下,編輯器中的 Crashlytics 資訊不會記錄或上傳至 Firebase。此外,Firebase Desktop 開發工作流程不支援 Crashlytics。
在「CrashNow()」中輕觸按鈕,測試遊戲是否會當機
在遊戲中設定 Crashlytics 後,Crashlytics SDK 會自動記錄當機和未處理的例外狀況,並上傳至 Firebase 進行分析。報表會顯示在 Firebase 控制台的 Crashlytics 資訊主頁中。
- 如要證明這確實是自動作業,請開啟
DebugMenu.cs,然後覆寫方法CrashNow(),如下所示:void CrashNow() { TestCrash(); } - 建構應用程式。
- (僅限 Android) 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 輕觸「Crash Now」(立即當機) 按鈕,然後繼續進行本程式碼研究室的下一個步驟,瞭解如何查看及解讀當機報告。
7. 瞭解 Firebase 控制台中的問題報告
查看當機報告時,您需要瞭解如何充分運用這些報告。您編寫的每個方法都會說明如何在 Crashlytics 報告中新增不同類型的資訊。
- 輕觸「立即異常終止」按鈕,然後重新啟動應用程式。
- 前往 Crashlytics 資訊主頁。向下捲動至資訊主頁底部的「問題」表格,Crashlytics 會將根本原因相同的事件歸類為「問題」。
- 按一下「問題」表格中列出的新問題。這樣做會顯示傳送至 Firebase 的每個個別事件的「事件摘要」。
您應該會看到類似下方的螢幕截圖。請注意,事件摘要會醒目顯示導致當機的呼叫堆疊追蹤記錄。
其他中繼資料
另一個實用的分頁是「Unity Metadata」(Unity 中繼資料) 分頁。本節會說明發生事件的裝置屬性,包括實體功能、CPU 型號/規格,以及各種 GPU 指標。
以下是這個分頁資訊的實用範例:
假設您的遊戲大量使用著色器來呈現特定外觀,但並非所有手機的 GPU 都能算繪這項功能。「Unity 中繼資料」分頁中的資訊可協助您瞭解應用程式應測試哪些硬體,進而決定要自動啟用或完全停用哪些功能。
雖然錯誤或當機可能永遠不會發生在您的裝置上,但由於市面上的 Android 裝置種類繁多,因此瞭解目標對象裝置的特定「熱點」有助於改善應用程式。

8. 擲回、攔截及記錄例外狀況
通常,即使開發人員的程式碼能正確擷取及處理執行階段例外狀況,最好還是要記錄例外狀況的發生情形和發生時的狀況。Crashlytics.LogException 正是為此而生,可將例外狀況事件傳送至 Firebase,方便您在 Firebase 控制台中進一步偵錯。
- 在
Assets/Hamster/Scripts/States/DebugMenu.cs中,將下列內容附加至using陳述式:// Import Firebase using Firebase.Crashlytics; - 還是在
DebugMenu.cs中,按照下列方式覆寫LogNonfatalError():void LogNonfatalError() { try { throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}"); } catch(System.Exception exception) { Crashlytics.LogException(exception); } } - 建構應用程式。
- (僅限 Android) 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 輕觸「Log Nonfatal Error」(記錄非嚴重錯誤) 按鈕,然後重新啟動應用程式。
- 前往 Crashlytics 資訊主頁,您應該會看到類似於本程式碼研究室上一個步驟的內容。
- 不過,這次請將「事件類型」篩選器限制為「非嚴重」,這樣您就只會查看非嚴重錯誤,例如您剛記錄的錯誤。

9. 將字串記錄到 Crashlytics,以便更瞭解程式執行流程
您是否曾嘗試找出某行程式碼突然產生例外狀況或當機的原因?這行程式碼會從多個路徑呼叫,每個工作階段呼叫數百次 (甚至數千次)。雖然在 IDE 中逐步執行程式碼並仔細查看值可能很不錯,但如果只有極少數使用者發生這種情況,該怎麼辦?更糟的是,如果無論如何都無法重現這個當機問題,該怎麼辦?
在這種情況下,瞭解一些背景資訊會大有幫助。使用 Crashlytics.Log,您可以寫出所需的情境。這些訊息就像是給未來自己的提示,說明當時可能發生的情況。
記錄檔的用途非常廣泛,但通常最適合用於記錄通話順序和/或通話遺漏的情況,因為這些資訊非常重要。
- 在
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(); } - 建構應用程式。
- (僅限 Android) 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 輕觸「Log Strings and Crash Now」按鈕,然後重新啟動應用程式。
- 返回 Crashlytics 資訊主頁,然後點按「問題」表格中列出的最新問題。您應該會再次看到類似先前問題的內容。

- 不過,如果您點選「事件摘要」中的「記錄」分頁,就會看到如下畫面:

10. 撰寫及覆寫自訂鍵
假設您想進一步瞭解與變數相關的當機問題,而這些變數設為少量的值或設定。如果能根據您在任何特定時間查看的變數和可能值組合進行篩選,或許會很方便。
除了記錄任意字串,當您需要瞭解程式當機時的確切狀態,Crashlytics 還提供另一種偵錯方式:自訂鍵。
這些是您可以為工作階段設定的鍵/值組合。與會累積且純粹是加法的記錄不同,鍵可以覆寫,只反映變數或條件的最新狀態。
除了做為程式最後記錄狀態的分類帳,這些金鑰還可做為 Crashlytics 問題的強大篩選器。
- 在
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(); } - 建構應用程式。
- (僅限 Android) 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 輕觸「Set Custom Key and Crash」按鈕,然後重新啟動應用程式。
- 返回 Crashlytics 資訊主頁,然後點按「問題」表格中列出的最新問題。您應該會再次看到類似先前問題的內容。
- 不過,這次請點選「事件摘要」中的「鍵」分頁,查看鍵的值,包括
Current Time:
為什麼要使用自訂金鑰,而不是自訂記錄?
- 記錄適合儲存序列資料,但如果您只需要最新值,自訂鍵會是更好的選擇。
- 在 Firebase 控制台中,您可以在「問題」表格的搜尋框中,依據鍵的值輕鬆篩選問題。
不過,自訂鍵與記錄類似,都有數量限制。Crashlytics 最多支援 64 組鍵/值組合。達到這個門檻後,系統就不會再儲存其他值。每個鍵/值組的大小上限為 1 KB。
11. (僅限 Android) 使用自訂金鑰和記錄,瞭解及診斷 ANR
對 Android 開發人員來說,最難偵錯的問題類別之一就是「應用程式無回應」(ANR) 錯誤。如果應用程式未在 5 秒內回應輸入事件,就會發生 ANR。這代表應用程式凍結或速度緩慢。系統會向使用者顯示對話方塊,讓他們選擇「等待」或「關閉應用程式」。
ANR 會造成不良的使用者體驗,且 (如上述 ANR 連結所述) 可能會影響應用程式在 Google Play 商店的曝光度。由於 ANR 複雜,且通常是由多執行緒程式碼所致,不同手機型號的行為差異極大,因此在偵錯時,重現 ANR 往往非常困難,甚至幾乎不可能。因此,通常最好以分析和演繹的方式處理。
在這個方法中,我們會結合 Crashlytics.LogException、Crashlytics.Log 和 Crashlytics.SetCustomKey,補充自動記錄的問題,並提供更多資訊。
- 在
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); } - 建構應用程式。
- 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 輕觸標示為「Set Logs And Keys → ANR」的按鈕,然後重新啟動應用程式。
- 返回 Crashlytics 資訊主頁,然後按一下「問題」表格中的新問題,即可查看「事件摘要」。如果呼叫順利完成,您應該會看到類似以下內容:

如您所見,Firebase 指出執行緒上的忙碌等待是應用程式觸發 ANR 的主要原因。 - 查看「事件摘要」的「記錄」分頁時,您會發現最後記錄為完成的方法是
DoSevereWork。
相反地,最後列為開始的方法是DoExtremeWork,這表示 ANR 發生在這個方法期間,且遊戲在記錄DoExtremeWork前關閉。
為什麼這樣做?
- 重現 ANR 非常困難,因此取得程式碼區域和指標的豐富資訊,對於演繹式找出 ANR 來說非常重要。
- 有了儲存在自訂鍵中的資訊,您現在可以瞭解哪個非同步執行緒的執行時間最長,以及哪些執行緒可能觸發 ANR。這類相關的邏輯和數值資料會顯示程式碼中最需要最佳化的部分。
12. 穿插 Analytics 事件,進一步豐富報表內容
下列方法也可從「Debug Menu」呼叫,但這些方法不會自行產生問題,而是將 Google Analytics 做為另一個資訊來源,進一步瞭解遊戲的運作方式。
與您在本程式碼研究室中編寫的其他方法不同,您應該將這些方法與其他方法搭配使用。在執行其他方法之前,請以任意順序呼叫這些方法 (按下「Debug Menu」中的對應按鈕)。接著,當您檢查特定 Crashlytics 問題中的資訊時,會看到 Analytics 事件的排序記錄。視應用程式的插碼方式而定,遊戲可使用這項資料,進一步瞭解程式流程或使用者輸入內容的組合。
- 在
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 ); } - 建構及部署遊戲,然後進入「Debug Menu」。
- (僅限 Android) 執行下列 Firebase CLI 指令,上傳符號:
firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
- 按一下下列至少一個按鈕,即可呼叫上述功能:
- 記錄字串事件
- 記錄 Int 事件
- 按下「立即當機」按鈕。
- 重新啟動遊戲,將當機事件上傳至 Firebase。
- 當您記錄各種任意的 Analytics 事件序列,然後讓遊戲產生 Crashlytics 會據此建立報表的事件 (如您剛才所做),這些事件就會新增至 Crashlytics 事件摘要的「記錄」分頁,如下所示:

13. 後續行動
有了這些資訊,您就能更深入瞭解自動產生的當機報告,有了這些新資訊,您就能運用目前狀態、過往事件記錄和現有的 Google Analytics 事件,進一步分析導致結果的事件序列和邏輯。
如果應用程式指定的是 Android 11 (API 級別 30) 以上版本,建議加入 GWP-ASan,此為原生記憶體配置器功能,有助於偵錯因原生記憶體錯誤 (例如 use-after-free 和 heap-buffer-overflow 錯誤) 導致的當機問題。如要使用這項偵錯功能,請明確啟用 GWP-ASan。
後續步驟
請繼續前往「使用遠端設定為 Unity 遊戲進行插碼」程式碼研究室,瞭解如何在 Unity 中使用遠端設定和 A/B 測試。