スマレジの テックファーム(SES 部門) でWebエンジニアとして働いている やまて(@r_yamate) と申します。
実務では 2023 年 3 月末まで、 SES の派遣先のテーブルオーダーシステムの機能改修の設計などを担当しました。
2023 年 4 月からは、スマレジの関連アプリの開発業務を担当しています。触ったことのなかった Flutter での開発で、日々奮闘中です。
はじめに
今回は、 Flutter プロジェクトに個別のプロダクトの追加例として Firebase Crashlytics を追加する手順についてまとめます。
以下の記事「Flutter アプリに Firebase を導入する手順」の次のステップとして書いていきます。
目次
環境
- MacBook Pro(intel)
- macOS Monterey 12.6.5
- Flutter 3.7.1
- Dart 2.19.1
Firebase Crashlytics とは
Firebase Crashlytics は軽量なリアルタイムのクラッシュ レポートツールで、アプリの品質を低下させる安定性の問題を追跡し、優先順位を付け、修正するのに役立ちます。
ということで、 Android や iOS などのモバイルプラットフォーム上でアプリがクラッシュした際の情報を収集して、開発者にリアルタイムで報告されるように設定することができるツールです。
1. プラグイン firebase_crashlytics の追加
1-1. プラグイン firebase_crashlytics の追加
Firebase プラグイン firebase_crashlytics を追加します。
編集:pubspec.yaml
dependencies:
flutter:
sdk: flutter
firebase_core: ^2.15.1
+ firebase_crashlytics: ^3.3.5
pub get
を実行します。
flutter pub get
1-2. クラッシュハンドラを構成する
エラーを捕捉して Crashlytics に送信するための設定を行います。
import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; import 'routers/router.dart'; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError; runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: goRouter, ); } }
1-3. flutterfire configure
の再実行
flutterfire configure
を再実行します。
flutterfire configure
2. 強制的にテストクラッシュを発生させて設定を完了する
2-1. firebase_analytics
のサンプルプログラムを使用してテスト
サンプルプログラムを使用してテストするため、ドキュメントのとおり、以下を追記します。
TextButton( onPressed: () => throw Exception(), child: const Text("Throw Test Exception"), ),
import 'package:flutter/material.dart'; import '../routers/router.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('ホーム')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ TextButton( onPressed: () => throw Exception(), child: const Text("Throw Test Exception"), ), ElevatedButton( onPressed: () => goRouter.go('logout'), child: const Text('ログアウト'), ), ], ), ), ); } }
TextButton をタップしたところ、以下のデバッグログが確認できました。
Launching lib/main.dart on sdk gphone x86 64 in debug mode... Running Gradle task 'assembleDebug'... ✓ Built build/app/outputs/flutter-apk/app-debug.apk. Installing build/app/outputs/flutter-apk/app-debug.apk... Debug service listening on ws://127.0.0.1:65521/WVEYsJ8Iap4=/ws Syncing files to device sdk gphone x86 64... E/SurfaceSyncer(11735): Failed to find sync for id=0 W/Parcel (11735): Expecting binder but got null! I/example.yomikey(11735): NativeAlloc concurrent copying GC freed 54903(3613KB) AllocSpace objects, 19(388KB) LOS objects, 49% free, 3386KB/6773KB, paused 3.387ms,21us total 2.043s ======== Exception caught by gesture =============================================================== The following _Exception was thrown while handling a gesture: Exception When the exception was thrown, this was the stack: #0 HomeScreen.build.<anonymous closure> (package:yomikey/screens/home_screen.dart:18:32) #1 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1096:21) #2 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24) #3 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11) #4 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:306:5) #5 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:239:7) #6 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:615:9) #7 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12) #8 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:143:9) #9 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13) #10 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18) #11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7) #12 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:460:19) #13 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:440:22) #14 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:336:11) #15 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:395:7) #16 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:357:5) #17 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:314:7) #18 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:295:7) #19 _invoke1 (dart:ui/hooks.dart:164:13) #20 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:361:7) #21 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:31) Handler: "onTap" Recognizer: TapGestureRecognizer#11d15 debugOwner: GestureDetector state: possible won arena finalPosition: Offset(210.3, 465.9) finalLocalPosition: Offset(80.1, 8.8) button: 1 sent tap down ==================================================================================================== D/EGL_emulation(11735): app_time_stats: avg=12225.54ms min=875.03ms max=23576.06ms count=2 I/TRuntime.CctTransportBackend(11735): Making request to: https://firebaselogging-pa.googleapis.com/v1/firelog/legacy/batchlog D/TrafficStats(11735): tagSocket(98) with statsTag=0xffffffff, statsUid=-1 I/TRuntime.CctTransportBackend(11735): Status Code: 200
3. Firebase コンソールでの確認
Firebase コンソールで Crashlytics のページを確認します。
Crashlytics のクラッシュレポートがまだ記録されていない時は、以下の初期画面が表示されます。
該当のプロジェクトのアプリでクラッシュが発生して送信されると、クラッシュレポートがされて、以下のような画面が閲覧できるようになり、内容を確認することができます。
クラッシュレポートをカスタマイズしたい場合は、以下のページを手順を確認できます。
おわりに
今回は、 Flutter プロジェクトに個別のプロダクトの追加例として Firebase Crashlytics を追加する手順についてまとめました。
ありがとうございました。
エンジニアの仕事は、未経験の頃に想像していた以上に難しくて、刺激的で、楽しい。嬉しい誤算。
— やまて|ソフトウェアエンジニア2年目 (@r_yamate) 2023年8月26日
モノづくりの仕事、楽しい。