0%

【文章翻譯】Firebase Crashlytics and the Flutter Casual Games Toolkit

【文章內容使用 Gemini 1.5 Pro 自動產生】

了解如何在 Flutter Games 範例中啟用 Crashlytics,讓您更容易偵測和修復遊戲中的問題

Flutter 休閒遊戲工具包 (FCGT) 是一個針對想要建立行動遊戲應用程式的開發人員的入門範本。它已經透過主選單、遊戲關卡、設定畫面、音效、音樂等等進行自訂。除了範本應用程式之外,您也可以下載一個基於此範本的 井字遊戲應用程式

以下螢幕截圖依序顯示開箱即用的主選單、遊戲關卡頁面和設定頁面:

Screenshots of the 3 main screens from the FCGT sample app: Main menu, Select Level & Settings
FCGT 螢幕截圖

FCGT 包含一些在開發您自己的遊戲時很有用的服務整合:Apple Game Center、Google Play Games 服務、Google 行動廣告 SDK 和應用程式內購套件。這些更進階的整合最初是被停用的,因為它們需要您(開發人員)在使用它們之前進行一些設定。如果您查看遊戲範本的 main.dart 檔案,並向下捲動到第一個「TODO」,您將看到廣告、遊戲服務和應用程式內購 Plugin 的程式碼,處於休眠狀態,等待啟用。

Screenshot of disabled integration code from main.dart file: AdsController, GamesServices, and InAppPurchases.
停用的廣告、遊戲服務和應用程式內購程式碼

FCGT 中也包含了 Firebase Crashlytics,這是一個功能強大的錯誤報告解決方案,可幫助您實時偵測、追蹤、優先處理和修復問題。Crashlytics 儀表板讓您能夠將程式碼中的問題視覺化,查看受影響的使用者數量,並找出哪些程式碼行導致了這些問題。

Screenshot of Firebase Crashlytics dashboard showing Crash-free statistics, trends & issues.
Firebase Crashlytics 儀表板

在初始狀態下,未啟用 Crashlytics 時,crashlytics/crashlytics.dart 檔案中的程式碼會收集錯誤訊息、日誌和堆疊追蹤,並將它們寫入主控台。此資訊僅在本地開發設備上測試時可用。啟用 Crashlytics 後,您可以從在自己的設備上運行生產程式碼的使用者那裡接收資料,並在 Crashlytics 儀表板上查看它。

本文將向您展示如何在 FCGT 中啟用 Firebase Crashlytics,拋出一些測試異常,並演示這些異常如何在 Crashlytics 儀表板上顯示。如果您有興趣將 Crashlytics 用於您的 Flutter App,但不想使用 FCGT 開發遊戲,那麼有關拋出異常和 Crashlytics 儀表板的資訊適用於託管在 Firebase 上的任何應用程式。

main.dart 檔案 的頂部,您可以看到 Crashlytics 整合的程式碼:

Disabled Crashlytics code in main.dart file // To enable Firebase Crashlytics, uncomment the following lines and // the import statements at the top of this file. // See the ‘Crashlytics’ section of the main README.md file for details. FirebaseCrashlytics? crashlytics; // if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) { // try …
main.dart:停用的 Firebase Crashlytics 程式碼

此 Crashlytics Firebase 程式碼未包含在原始的 FCGT YouTube 影片教學中,使用 Flutter 建立遊戲的快速入門 - 這個程式碼很快就會說明。

在 FCGT 中啟用 Crashlytics 的步驟列在 FCGT 的 Crashlytics 區段README.md 檔案 中,但請繼續閱讀以了解每個步驟的逐步指南,以及 Crashlytics 儀表板中事物的外觀。

要開始,請使用以下說明:

  1. Flutter 專案 GitHub 頁面 下載最新版本的遊戲範本副本。

  2. 確保您已在電腦上安裝 Flutter,並且能夠在 iOS 模擬器或 Android 模擬器上運行應用程式。如果您對如何執行此操作有任何疑問,請參閱您的目標平台的 Flutter 入門指南

  3. 在您的 IDE 或終端機中打開遊戲範本資料夾,並升級到最新版本的 Flutter:

1
$ > flutter upgrade
  1. 選擇您要運行應用程式的設備或模擬器。

  2. 運行應用程式:

1
$ > flutter run

如果一切順利,應用程式將啟動,您將看到主畫面:

Screenshot of FCGT app main screen
遊戲範本主畫面

FCGT 的設計目的是讓開發人員能夠快速輕鬆地建立建立遊戲的基礎。在應用程式運行時,請在各個地方瀏覽並查看它可以做些什麼。您會很快發現 FCGT 中的「遊戲玩法」並不是最令人興奮的(除非您喜歡滑桿)。遊戲程式碼的淺層結構是一個刻意的設計選擇,讓您在開始撰寫自己的遊戲時保持簡單。

Animated gif of FCGT “game play”. User clicks “play” on main menu, selects “level #1", drags the slider to complete the level & the “You Won” screen is displayed.
FCGT「遊戲玩法」

現在您有了程式碼,請前往 Firebase 網站 並設定一個免費帳戶(如果您沒有帳戶)。然後,打開 Firebase 主控台 並點擊 新增專案。從那裡開始,建立一個新的專案是一個 3 步驟的過程,只要按照螢幕上的指示操作即可。系統會詢問您是否要啟用 Google Analytics (GA)。建議您啟用 Google Analytics,因為除了免費之外,它還解鎖了一些 功能強大的分析功能,例如無錯誤使用者資料、會話麵包屑、速度警報和 BigQuery 整合。

如果您啟用了 Google Analytics,請使用以下命令安裝 Google Analytics Flutter Plugin:

1
$ > flutter pub add firebase_analytics

若要進一步了解,請參閱 使用 Google Analytics 取得錯誤報告的指標 指南中的步驟 1 和 2,但無需遵循指南中概述的其他步驟,因為這些步驟已在下面說明。

接下來,安裝 Firebase CLI。前往 Firebase CLI 文件,選擇您的作業系統,並按照說明操作。登入後,在終端機中運行以下命令,它應該會顯示一個 Firebase 專案名稱列表:

1
$ > flutterfire configure

選擇您之前建立的 Firebase 專案的名稱。然後,選擇您的應用程式支援哪些目標平台。目前,Crashlytics 主控台僅支援 iOS 和 Android,因此最多選擇這兩個平台。

Result of typing “flutterfire configure” into the terminal. User is prompted to select a Firebase project, choose which platforms to support & then confirm Firebase configuration and gradle build plugins updates and FirebaseOptions file overwrite. Final result is the Firebase app IDs for the selected platforms.
FlutterFire 設定命令的輸出

FlutterFire CLI 會產生連接 Firebase 所需的所有金鑰和用戶端 ID,並將它們覆蓋到 src/firebase_options.dart 檔案中。如果您在未來添加更多 Plugin 或想要啟用更多平台,只需重新運行 flutterfire configure 命令即可。

要啟用 Crashlytics,請返回 lib/main.dart 檔案並取消註釋 Crashlytics 程式碼。在檔案的頂部,還有 3 個必須取消註釋的匯入語句:

3 import statements at the top of the main.dart file that need to be uncommented: dart:io, firebase_core.dart & firebase_options.dart.
取消註釋的 Crashlytics 匯入語句

然後,在同一檔案的下方,取消註釋您之前看過的 Crashlytics 整合程式碼。此程式碼會初始化一個 Crashlytics 的實例(如果還沒有實例),然後檢查應用程式是否正在 Android 或 iOS 上運行。如果應用程式正在桌面或網頁上運行,Crashlytics 程式碼將不會執行,因為 Crashlytics 儀表板還不支持這些平台。

Crashlytics code in main.dart file: FirebaseCrashlytics? crashlytics; if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) { try { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); crashlytics = FirebaseCrashlytics.instance; } catch (e) { debugPrint(“Firebase couldn’t be initialized: $e”); } }
Crashlytics 整合程式碼

取消註釋 Crashlytics 整合程式碼後,請再次使用 flutter run 命令運行應用程式,以確保一切正常。

是時候讓您的應用程式當機了!

事實上,您只會拋出一些測試異常,但您也會了解如何在 Crashlytics 儀表板中找到它們。這很有用,因為未捕獲的異常可能不會導致您的應用程式當機,但仍然會導致糟糕的使用者體驗,而且如果沒有啟用 Crashlytics,它們可能會被忽略。crashlytics/crashlytics.dart 檔案中使用的 Crashlytics 致命錯誤 API 將未捕獲的異常報告為致命事件,因此它們將出現在 Crashlytics 儀表板中,並且可以適當優先處理。

Crashlytics Fatal Error API: FlutterError.onError = crashlytics.recordFlutterFatalError;
Crashlytics 致命錯誤 API

若要進一步了解如何實作此日誌記錄,請查看有關如何 自訂 Firebase Crashlytics 錯誤報告 的指南,並閱讀 crashlytics.dart 檔案中的註釋。

在您選擇的文字編輯器或 IDE 中,導航到 main_menu 資料夾,並打開 main_menu_screen.dart 檔案。向下捲動,直到找到 設定 按鈕的程式碼。

Code for settings button on main screen of app. ElevatedButton( onPressed: () => GoRouter.of(context).go(‘/settings’), child: const Text(‘Settings’), ),
之前(原始程式碼)

複製 ElevatedButton,然後在 onPressed 回呼中,不要呼叫 GoRouter 導航到 設定 頁面,而是拋出異常。在此過程中,請將按鈕的名稱更改為類似 拋出測試異常 的內容,如下所示:

1
2
3
4
5
6
7
8
9
ElevatedButton(
onPressed: () => GoRouter.of(context).go('/settings'),
child: const Text('Settings'),
),
_gap,
ElevatedButton(
onPressed: () => throw Exception(),
child: const Text("Throw Test Exception"),
),

接下來,導航到 audio 資料夾,並打開 audio_controller.dart 檔案。向下捲動,直到找到 _musicOnHandler 函數。當使用者在 設定 畫面中切換音樂播放時,框架會呼叫此函數。

Original code for _musicOnHandler() function from audio_controller.dart file.
之前(原始程式碼)

在 else 語句中,在呼叫 _stopMusic() 函數的地方下方,使用 _log.severe() 方法將訊息寫入主控台。任何等級為 Level.severe 或更高的日誌訊息都會發送給 Crashlytics,因此此訊息也會出現在 Crashlytics 主控台中。為了演示說明,請在此處也拋出另一個異常:

1
2
3
4
5
6
7
8
9
10
11
12
13
void _musicOnHandler() {
if (_settings!.musicOn.value) {
// Music got turned on.
if (!_settings!.muted.value) {
_resumeMusic();
}
} else {
// Music got turned off.
_stopMusic();
_log.severe("Someone is messing with the music!");
throw Exception();
}
}

現在,應用程式中有兩個地方可以點擊按鈕並拋出異常。再次運行您的應用程式,並確認在主選單中有一個 拋出測試異常 按鈕。

Screenshot of FCGT Main Menu with new “Throw Test Exception” button shown below the “Settings” button.
帶有拋出異常按鈕的主選單

點擊 拋出測試異常 按鈕會產生一個關於拋出異常時的完整堆疊追蹤,並將其寫入主控台:

Example console output after an exception is thrown with full stack trace. First 3 lines are: EXCEPTION CAUGHT BY GESTURE. The following _Exception was thrown while handling a gesture: Exception When the exception was thrown, this was the stack: …
拋出異常後的主控台輸出

如果點擊 設定 打開設定視圖,然後點擊樂符按鈕幾次,主控台中將會出現更多異常和堆疊追蹤。現在您啟用了 Crashlytics,此資料可以在 Crashlytics 儀表板中使用。

打開 Firebase 主控台,選擇您的專案,然後從左側的選單中選擇 Crashlytics。選擇您正在運行的專案版本(Android 或 iOS),您應該能夠看到 Crashlytics 儀表板。

Screenshot of Firebase Crashlytics dashboard showing Crash-free statistics, trends & issues.
Firebase Crashlytics 儀表板
如果幾分鐘後,當您嘗試存取 Crashlytics 儀表板時,只看到這個傢伙在錯誤中晃動,可能是因為 Crashlytics 還沒有偵測到任何事件。
在這種情況下,請停止應用程式運行,然後返回您的設備或模擬器,關閉應用程式,並透過點擊應用程式圖示再次啟動它。現在,嘗試在應用程式中拋出一些異常,並再次檢查 Crashlytics 儀表板。如果您刷新了 Firebase 主控台,手動重新啟動了應用程式,並且在五分鐘後仍然沒有看到測試錯誤,請 [啟用除錯日誌記錄](https://firebase.google.com/docs/crashlytics/test-implementation#enable-debug-logging) 以查看您的應用程式是否正在發送錯誤報告。
Cartoon image of man with butterfly net trying to catch bugs. This is displayed on the Crashlytics site when events haven’t been detected yet.
Crashlytics 尚未偵測到任何事件

如果您啟用了 Google Analytics,無錯誤統計資料窗格將會顯示在選定時間範圍內未遇到錯誤的使用者百分比。

Screenshot of the crash-free statistics pane from the Firebase Crashlytics dashboard
Crashlytics 儀表板無錯誤統計資料窗格

Crashlytics 儀表板底部 的 問題 表格顯示了拋出的異常。

Screenshot of the Issues table at the bottom of the Crashlytics dashboard. There are 2 example issues in the table. 1) Crash Fresh issue audio_controller.dart line 197 AudioController._musicOnHandler 2) Crash Fresh issue dart:async _BroadcastStreamController.add
Crashlytics 儀表板問題表格

點擊表格中的一個特定問題會顯示每當發生此問題時的卡片,以及有關該問題的更多詳細資訊。預設情況下,會顯示堆疊追蹤,這讓您能夠識別錯誤發生的程式碼位置。從下面的螢幕截圖中可以看出,異常是在 audio_controller.dart 檔案的第 197 行的 _musicOnHandler() 函數中拋出的。這並不奇怪,因為您正是將該異常放置在程式碼中的位置,但想像一下,這對於追蹤複雜的生產應用程式中的問題會有多有用。

Screenshot of an events summary in Crashlytics dashboard events table with a specific event selected and the stack trace tab selected.
Crashlytics 儀表板堆疊追蹤

如果您點擊 日誌 標籤,您可以看到 _log.severe() 方法寫入主控台的任何訊息:

Screenshot of an events summary in Crashlytics dashboard events table with a specific event selected and the log tab selected.
Crashlytics 儀表板日誌

恭喜您!現在,當您繼續撰寫獲獎遊戲(也許會有大量滑桿)時,您將啟用 Crashlytics 來幫助您找到和修復任何問題。


Firebase Crashlytics 和 Flutter 休閒遊戲工具包 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。