Flutter error catching & handling plugin. Handles and reports exceptions in your app!

Overview

Catcher

pub package pub package pub package pub package

Catcher is Flutter plugin which automatically catches error/exceptions and handle them. Catcher offers multiple way to handle errors. Catcher is heavily inspired from ACRA: https://github.com/ACRA/acra. Catcher supports Android, iOS, Web, Linux, Windows and MacOS platforms.

Install

Add this line to your pubspec.yaml:

dependencies:
  catcher: ^0.6.9

Then run this command:

$ flutter packages get

Then add this import:

import 'package:catcher/catcher.dart';

Table of contents

Platform support
Basic example
Catcher usage Adding navigator key
Catcher configuration
Report catched exception
Localization

Report modes

Handlers

Test Exception
Explicit exception report handler map
Explicit exception report mode map
Error widget
Current config
Update config
Screenshots

Platform support

To check which features of Catcher are available in given platform visit this page: Platform support

Basic example

Basic example utilizes debug config with Dialog Report Mode and Console Handler and release config with Dialog Report Mode and Email Manual Handler.

To start using Catcher, you have to:

  1. Create Catcher configuration (you can use only debug config at start)
  2. Create Catcher instance and pass your root widget along with catcher configuration
  3. Add navigator key to MaterialApp or CupertinoApp

Here is complete example:

import 'package:flutter/material.dart';
import 'package:catcher/catcher.dart';

main() {
  /// STEP 1. Create catcher configuration. 
  /// Debug configuration with dialog report mode and console handler. It will show dialog and once user accepts it, error will be shown   /// in console.
  CatcherOptions debugOptions =
      CatcherOptions(DialogReportMode(), [ConsoleHandler()]);
      
  /// Release configuration. Same as above, but once user accepts dialog, user will be prompted to send email with crash to support.
  CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
    EmailManualHandler(["[email protected]"])
  ]);

  /// STEP 2. Pass your root widget (MyApp) along with Catcher configuration:
  Catcher(rootWidget: MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      /// STEP 3. Add navigator key from Catcher. It will be used to navigate user to report page or to show dialog.
      navigatorKey: Catcher.navigatorKey,
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget()),
    );
  }
}

class ChildWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
            child: TextButton(
                child: Text("Generate error"),
                onPressed: () => generateError()));
  }

  generateError() async {
    throw "Test exception";
  }
}

If you run this code you will see screen with "Generate error" button on the screen. After clicking on it, it will generate test exception, which will be handled by Catcher. Before Catcher process exception to handler, it will show dialog with information for user. This dialog is shown because we have used DialogReportHandler. Once user confirms action in this dialog, report will be send to console handler which will log to console error informations.


Dialog with default confirmation message

I/flutter ( 7457): [2019-02-09 12:40:21.527271 | ConsoleHandler | INFO] ============================== CATCHER LOG ==============================
I/flutter ( 7457): [2019-02-09 12:40:21.527742 | ConsoleHandler | INFO] Crash occured on 2019-02-09 12:40:20.424286
I/flutter ( 7457): [2019-02-09 12:40:21.527827 | ConsoleHandler | INFO] 
I/flutter ( 7457): [2019-02-09 12:40:21.527908 | ConsoleHandler | INFO] ------- DEVICE INFO -------
I/flutter ( 7457): [2019-02-09 12:40:21.528233 | ConsoleHandler | INFO] id: PSR1.180720.061
I/flutter ( 7457): [2019-02-09 12:40:21.528337 | ConsoleHandler | INFO] androidId: 726e4abc58dde277
I/flutter ( 7457): [2019-02-09 12:40:21.528431 | ConsoleHandler | INFO] board: goldfish_x86
I/flutter ( 7457): [2019-02-09 12:40:21.528512 | ConsoleHandler | INFO] bootloader: unknown
I/flutter ( 7457): [2019-02-09 12:40:21.528595 | ConsoleHandler | INFO] brand: google
I/flutter ( 7457): [2019-02-09 12:40:21.528694 | ConsoleHandler | INFO] device: generic_x86
I/flutter ( 7457): [2019-02-09 12:40:21.528774 | ConsoleHandler | INFO] display: sdk_gphone_x86-userdebug 9 PSR1.180720.061 5075414 dev-keys
I/flutter ( 7457): [2019-02-09 12:40:21.528855 | ConsoleHandler | INFO] fingerprint: google/sdk_gphone_x86/generic_x86:9/PSR1.180720.061/5075414:userdebug/dev-keys
I/flutter ( 7457): [2019-02-09 12:40:21.528939 | ConsoleHandler | INFO] hardware: ranchu
I/flutter ( 7457): [2019-02-09 12:40:21.529023 | ConsoleHandler | INFO] host: vped9.mtv.corp.google.com
I/flutter ( 7457): [2019-02-09 12:40:21.529813 | ConsoleHandler | INFO] isPsychicalDevice: false
I/flutter ( 7457): [2019-02-09 12:40:21.530178 | ConsoleHandler | INFO] manufacturer: Google
I/flutter ( 7457): [2019-02-09 12:40:21.530345 | ConsoleHandler | INFO] model: Android SDK built for x86
I/flutter ( 7457): [2019-02-09 12:40:21.530443 | ConsoleHandler | INFO] product: sdk_gphone_x86
I/flutter ( 7457): [2019-02-09 12:40:21.530610 | ConsoleHandler | INFO] tags: dev-keys
I/flutter ( 7457): [2019-02-09 12:40:21.530713 | ConsoleHandler | INFO] type: userdebug
I/flutter ( 7457): [2019-02-09 12:40:21.530825 | ConsoleHandler | INFO] versionBaseOs: 
I/flutter ( 7457): [2019-02-09 12:40:21.530922 | ConsoleHandler | INFO] versionCodename: REL
I/flutter ( 7457): [2019-02-09 12:40:21.531074 | ConsoleHandler | INFO] versionIncremental: 5075414
I/flutter ( 7457): [2019-02-09 12:40:21.531573 | ConsoleHandler | INFO] versionPreviewSdk: 0
I/flutter ( 7457): [2019-02-09 12:40:21.531659 | ConsoleHandler | INFO] versionRelase: 9
I/flutter ( 7457): [2019-02-09 12:40:21.531740 | ConsoleHandler | INFO] versionSdk: 28
I/flutter ( 7457): [2019-02-09 12:40:21.531870 | ConsoleHandler | INFO] versionSecurityPatch: 2018-08-05
I/flutter ( 7457): [2019-02-09 12:40:21.532002 | ConsoleHandler | INFO] 
I/flutter ( 7457): [2019-02-09 12:40:21.532078 | ConsoleHandler | INFO] ------- APP INFO -------
I/flutter ( 7457): [2019-02-09 12:40:21.532167 | ConsoleHandler | INFO] version: 1.0
I/flutter ( 7457): [2019-02-09 12:40:21.532250 | ConsoleHandler | INFO] appName: catcher_example
I/flutter ( 7457): [2019-02-09 12:40:21.532345 | ConsoleHandler | INFO] buildNumber: 1
I/flutter ( 7457): [2019-02-09 12:40:21.532426 | ConsoleHandler | INFO] packageName: com.jhomlala.catcherexample
I/flutter ( 7457): [2019-02-09 12:40:21.532667 | ConsoleHandler | INFO] 
I/flutter ( 7457): [2019-02-09 12:40:21.532944 | ConsoleHandler | INFO] ---------- ERROR ----------
I/flutter ( 7457): [2019-02-09 12:40:21.533096 | ConsoleHandler | INFO] Test exception
I/flutter ( 7457): [2019-02-09 12:40:21.533179 | ConsoleHandler | INFO] 
I/flutter ( 7457): [2019-02-09 12:40:21.533257 | ConsoleHandler | INFO] ------- STACK TRACE -------
I/flutter ( 7457): [2019-02-09 12:40:21.533695 | ConsoleHandler | INFO] #0      ChildWidget.generateError (package:catcher_example/file_example.dart:62:5)
I/flutter ( 7457): [2019-02-09 12:40:21.533799 | ConsoleHandler | INFO] <asynchronous suspension>
I/flutter ( 7457): [2019-02-09 12:40:21.533879 | ConsoleHandler | INFO] #1      ChildWidget.build.<anonymous closure> (package:catcher_example/file_example.dart:53:61)
I/flutter ( 7457): [2019-02-09 12:40:21.534149 | ConsoleHandler | INFO] #2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
I/flutter ( 7457): [2019-02-09 12:40:21.534230 | ConsoleHandler | INFO] #3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
I/flutter ( 7457): [2019-02-09 12:40:21.534321 | ConsoleHandler | INFO] #4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 7457): [2019-02-09 12:40:21.534419 | ConsoleHandler | INFO] #5      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter ( 7457): [2019-02-09 12:40:21.534524 | ConsoleHandler | INFO] #6      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
I/flutter ( 7457): [2019-02-09 12:40:21.534608 | ConsoleHandler | INFO] #7      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 7457): [2019-02-09 12:40:21.534686 | ConsoleHandler | INFO] #8      PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 7457): [2019-02-09 12:40:21.534765 | ConsoleHandler | INFO] #9      PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 7457): [2019-02-09 12:40:21.534843 | ConsoleHandler | INFO] #10     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
I/flutter ( 7457): [2019-02-09 12:40:21.534973 | ConsoleHandler | INFO] #11     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
I/flutter ( 7457): [2019-02-09 12:40:21.535052 | ConsoleHandler | INFO] #12     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
I/flutter ( 7457): [2019-02-09 12:40:21.535136 | ConsoleHandler | INFO] #13     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
I/flutter ( 7457): [2019-02-09 12:40:21.535216 | ConsoleHandler | INFO] #14     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
I/flutter ( 7457): [2019-02-09 12:40:21.535600 | ConsoleHandler | INFO] #15     _rootRunUnary (dart:async/zone.dart:1136:13)
I/flutter ( 7457): [2019-02-09 12:40:21.535753 | ConsoleHandler | INFO] #16     _CustomZone.runUnary (dart:async/zone.dart:1029:19)
I/flutter ( 7457): [2019-02-09 12:40:21.536008 | ConsoleHandler | INFO] #17     _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
I/flutter ( 7457): [2019-02-09 12:40:21.536138 | ConsoleHandler | INFO] #18     _invoke1 (dart:ui/hooks.dart:170:10)
I/flutter ( 7457): [2019-02-09 12:40:21.536271 | ConsoleHandler | INFO] #19     _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
I/flutter ( 7457): [2019-02-09 12:40:21.536375 | ConsoleHandler | INFO] 
I/flutter ( 7457): [2019-02-09 12:40:21.536539 | ConsoleHandler | INFO] ======================================================================

Console handler output

Catcher usage

Adding navigator key

In order to make work Page Report Mode and Dialog Report Mode, you must include navigator key. Catcher plugin exposes key which must be included in your MaterialApp or WidgetApp:

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //********************************************
      navigatorKey: Catcher.navigatorKey,
      //********************************************
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget()),
    );
  }

You need to provide this key, because Catcher needs context of navigator to show dialogs/pages. There is no need to include this navigator key if you won't use Page/Dialog Report Mode. You can also provide your own navigator key if need to. You can provide it with Catcher constructor (see below). Please check custom navigator key example to see basic example.

Catcher configuration

Catcher instance needs rootWidget or runAppFunction in setup time. Please provide one of it.

  • rootWidget (optional) - instance of your root application widget
  • runAppFunction (optional) - function where runApp() will be called
  • debugConfig (optional) - config used when Catcher detects that application runs in debug mode
  • releaseConfig (optional) - config used when Catcher detects that application runs in release mode
  • profileConfig (optional) - config used when Catcher detects that application runs in profile mode
  • enableLogger (optional) - enable/disable internal Catcher logs
  • navigatorKey (optional) - provide optional navigator key from outside of Catcher
  • ensureInitialized (optional) - should Catcher run WidgetsFlutterBinding.ensureInitialized() during initialization
main() {
  CatcherOptions debugOptions =
  CatcherOptions(DialogReportMode(), [ConsoleHandler()]);
  CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
    EmailManualHandler(["[email protected]"])
  ]);
  CatcherOptions profileOptions = CatcherOptions(
    NotificationReportMode(), [ConsoleHandler(), ToastHandler()],
    handlerTimeout: 10000, customParameters: {"example"c: "example_parameter"},);
  Catcher(rootWidget: MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions, profileConfig: profileOptions, enableLogger: false, navigatorKey: navigatorKey);
}

CatcherOptions parameters: handlers - list of handlers, which will process report, see handlers to get more information.
handlerTimeout - timeout in milliseconds, this parameter describes max time of handling report by handler.
reportMode - describes how error report will be shown to user, see report modes to get more information.
localizationOptions - translations used by report modes nad report handlers.
explicitExceptionReportModesMap - explicit report modes map which will be used to trigger specific report mode for specific error.
explicitExceptionHandlersMap - Explicit report handler map which will be used to trigger specific report report handler for specific error.
customParameters - map of additional parameters that will be included in report (for example user id or user name).
handleSilentError - should handle silent errors reported, see FlutterErrorDetails.silent for more details.
screenshotsPath - path where screenshots will be saved.
excludedParameters - parameters which will be excluded from report.
filterFunction - function used to filter errors which shouldn't be handled.

Report catched exception

Catcher won't process exceptions catched in try/catch block. You can send exception from try catch block to Catcher:

try {
  ...
} catch (error,stackTrace) {
  Catcher.reportCheckedError(error, stackTrace);
}

Localization

Catcher allows to create localizations for Report modes. To add localization support, you need setup few things:

Add navigatorKey in your MaterialApp:

 navigatorKey: Catcher.navigatorKey,

Add flutter localizations delegates and locales in your MaterialApp:

 localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('pl', 'PL'),
      ],

Add localizationOptions in catcherOptions:

CatcherOptions(
...
    localizationOptions: [
        LocalizationOptions("pl", notificationReportModeTitle: "My translation" ...),
        LocalizationOptions("de", notificationReportModeTitle: "My translation" ...),
    ]
)

You can add translate for given parameters:

  • notificationReportModeTitle - notification report mode title
  • notificationReportModeContent - notification report mode subtitle
  • dialogReportModeTitle - dialog report mode title
  • dialogReportModeDescription - dialog report mode description
  • dialogReportModeAccept - dialog report mode accept button
  • dialogReportModeCancel - dialog report mode cancel button
  • pageReportModeTitle - page report mode toolbar title
  • pageReportModeDescription - page report mode description
  • pageReportModeAccept - page report mode accept button
  • pageReportModeCancel - page report mode cancel button
  • toastHandlerDescription - toast handler message

If you want to override default english texts, just add simply localization options for "en" language.

There are build in support for languages:

  • english
LocalizationOptions.buildDefaultEnglishOptions();
  • chinese
LocalizationOptions.buildDefaultChineseOptions();
  • hindi
LocalizationOptions.buildDefaultHindiOptions();
  • spanish
LocalizationOptions.buildDefaultSpanishOptions();
  • malay
LocalizationOptions.buildDefaultMalayOptions();
  • russian
LocalizationOptions.buildDefaultRussianOptions();
  • portuguese
LocalizationOptions.buildDefaultPortugueseOptions();
  • french
LocalizationOptions.buildDefaultFrenchOptions();
  • polish
LocalizationOptions.buildDefaultPolishOptions();
  • italian
LocalizationOptions.buildDefaultItalianOptions();
  • korean
LocalizationOptions.buildDefaultKoreanOptions();
  • dutch
LocalizationOptions.buildDefaultDutchOptions();

Complete Example:

import 'package:flutter/material.dart';
import 'package:catcher/catcher.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

main() {
  CatcherOptions debugOptions = CatcherOptions(DialogReportMode(), [
    ConsoleHandler(),
    HttpHandler(HttpRequestType.post, Uri.parse("https://httpstat.us/200"),
        printLogs: true)
  ], localizationOptions: [
    LocalizationOptions("pl",
        notificationReportModeTitle: "Wystąpił błąd aplikacji",
        notificationReportModeContent:
            "Naciśnij tutaj aby wysłać raport do zespołu wpsarcia",
        dialogReportModeTitle: "Błąd aplikacji",
        dialogReportModeDescription:
            "Wystąpił niespodziewany błąd aplikacji. Raport z błędem jest gotowy do wysłania do zespołu wsparcia. Naciśnij akceptuj aby wysłać raport lub odrzuć aby odrzucić raport.",
        dialogReportModeAccept: "Akceptuj",
        dialogReportModeCancel: "Odrzuć",
        pageReportModeTitle: "Błąd aplikacji",
        pageReportModeDescription:
            "Wystąpił niespodziewany błąd aplikacji. Raport z błędem jest gotowy do wysłania do zespołu wsparcia. Naciśnij akceptuj aby wysłać raport lub odrzuć aby odrzucić raport.",
        pageReportModeAccept: "Akceptuj",
        pageReportModeCancel: "Odrzuć",
        toastHandlerDescription: "Wystąpił błąd:",
    ) 
  ]);
  CatcherOptions releaseOptions = CatcherOptions(NotificationReportMode(), [
    EmailManualHandler(["[email protected]"])
  ]);

  Catcher(rootWidget: MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: Catcher.navigatorKey,
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('pl', 'PL'),
      ],
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget()),
    );
  }
}

class ChildWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
        child: TextButton(
            child: Text("Generate error"), onPressed: () => generateError()));
  }

  generateError() async {
    throw "Test exception";
  }
}

Report modes

Report mode is the process of gathering user permission to handle error. User can accept or deny permission to handle error. There are 4 types of report mode:

Silent Report Mode

Silent Report Mode is default report mode. This report mode doesn't ask user for permission to handle crash logs. It will push logs automatically to handlers.

ReportMode reportMode = SilentReportMode();

Notification Report Mode

Notification Report Mode has been removed because of incompatibility with firebase. Please check local_notifications_example to re-add local notificaitons to your app.

Dialog Report Mode

Dialog Report Mode shows dialog with information about error. Dialog has title, description and 2 buttons: Accept and Cancel. Once user clicks on Accept button, report will be pushed to handlers.

  ReportMode reportMode = DialogReportMode();

See localization options to change default texts.


Dialog report mode

Page Report Mode

Page Report Mode shows new page with information about error. Page has title, description, stack trace view and 2 buttons: Accept and Cancel. Once user clicks on Accept button, report will be pushed to handlers.

  ReportMode reportMode = PageReportMode(showStackTrace: false);

Page Report Mode can be configured with optional parameters: showStackTrace (optional) - enables/disables stack trace view

See localization options to change default texts.


Page report mode

Handlers

Handlers are an last point in error processing flow. They are doing specific task with error report, for example logging report to console.

Console Handler

Console Handler is the default and basic handler. It show crash log in console. Console logger allows you to parametrize log output:

ConsoleHandler(
          enableApplicationParameters: true,
          enableDeviceParameters: true,
          enableCustomParameters: true,
          enableStackTrace: true,
          handleWhenRejected: false
          )
  • enableApplicationParameters (optional) - display in log section with application data:
I/flutter ( 4820): ------- APP INFO -------
I/flutter ( 4820): version: 1.0
I/flutter ( 4820): appName: catcher_example
I/flutter ( 4820): buildNumber: 1
I/flutter ( 4820): packageName: com.jhomlala.catcherexample
I/flutter ( 4820): 
  • enableDeviceParameters (optional) - display in log section with device data (it will show android/ios data):
I/flutter ( 4820): ------- DEVICE INFO -------
I/flutter ( 4820): id: PSR1.180720.061
I/flutter ( 4820): androidId: fd97a76448e87410
I/flutter ( 4820): board: goldfish_x86
I/flutter ( 4820): bootloader: unknown
I/flutter ( 4820): brand: google
I/flutter ( 4820): device: generic_x86
I/flutter ( 4820): display: sdk_gphone_x86-userdebug 9 PSR1.180720.061 5075414 dev-keys
I/flutter ( 4820): fingerprint: google/sdk_gphone_x86/generic_x86:9/PSR1.180720.061/5075414:userdebug/dev-keys
I/flutter ( 4820): hardware: ranchu
I/flutter ( 4820): host: vped9.mtv.corp.google.com
I/flutter ( 4820): isPsychicalDevice: false
I/flutter ( 4820): manufacturer: Google
I/flutter ( 4820): model: Android SDK built for x86
I/flutter ( 4820): product: sdk_gphone_x86
I/flutter ( 4820): tags: dev-keys
I/flutter ( 4820): type: userdebug
I/flutter ( 4820): versionBaseOs: 
I/flutter ( 4820): versionCodename: REL
I/flutter ( 4820): versionIncremental: 5075414
I/flutter ( 4820): versionPreviewSdk: 0
I/flutter ( 4820): versionRelase: 9
I/flutter ( 4820): versionSdk: 28
I/flutter ( 4820): versionSecurityPatch: 2018-08-05
  • enableCustomParameters (optional) - display in log section with custom parameters passed to Catcher constructor

  • enableStackTrace (optional) - display in log section with stack trace:

I/flutter ( 5073): ------- STACK TRACE -------
I/flutter ( 5073): #0      _MyAppState.generateError (package:catcher_example/main.dart:38:5)
I/flutter ( 5073): <asynchronous suspension>
I/flutter ( 5073): #1      _MyAppState.build.<anonymous closure> (package:catcher_example/main.dart:31:69)
I/flutter ( 5073): #2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
I/flutter ( 5073): #3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
I/flutter ( 5073): #4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 5073): #5      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter ( 5073): #6      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
I/flutter ( 5073): #7      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 5073): #8      PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 5073): #9      PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 5073): #10     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter
  • handleWhenRejected - should report be handled even if user rejects it

Email Manual Handler

Email manual handler can be used to send email manually by user. It opens default email application with prepared email.

EmailManualHandler(
      ["[email protected]", "[email protected]"],
      enableDeviceParameters: true,
      enableStackTrace: true,
      enableCustomParameters: true,
      enableApplicationParameters: true,
      sendHtml: true,
      emailTitle: "Sample Title",
      emailHeader: "Sample Header",
      printLogs: true)

Email Manual Handler parameters:

  • recipients (required) - list of email addresses of recipients
  • enableDeviceParameters (optional) - see Console Handler description
  • enableStackTrace (optional) - see Console Handler description
  • enableCustomParameters (optional) - see Console Handler description
  • enableApplicationParameters (optional) - see Console Handler description
  • sendHtml (optional) - enable/disable html email formatting
  • emailTitle (optional) - set custom email title
  • emailHeader (optional) - set additional email text header
  • printLogs (optional) - enable/disable debug logs

Email Auto Handler

Email handler can be used to send automatically email with error reports. Email handler has multiple configuration parameters. Few of them are required, other are optional. These parameters are required:

 EmailAutoHandler("smtp.gmail.com", 587, "[email protected]", "Catcher",
          "FakePassword", ["[email protected]"])

We need to setup email smtp server, email account and recipient. Currently, only Gmail was tested and worked. You can try use other email providers, but there can be errors.

List of all parameters:

  • smtpHost (required) - host address of your email, for example host for gmail is smtp.gmail.com
  • smtpPort (required) - smtp port of your email, for example port for gmail is 587
  • senderEmail (required) - email from which Catcher will send email (it will be sender of error emails)
  • senderName (required) - name of sender email
  • senderPassword (required) - password for sender email
  • recipients (required) - list which contains recipient emails
  • enableSSL (optional) - if your email provider supports SSL, you can enable this option
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableStackTrace (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description
  • emailTitle (optional) - custom title of report email, if not set then title will be: Handled Error: >> [Error name] <<
  • emailHeader (optional)- custom header message before report data
  • sendHtml (optional) - enable/disable html data in your email, if enabled then html will be sent and your report will look much better
  • printLog (optional) - enable/disable debug logs

Example email:

Http Handler

Http Handler provides feature for sending report to external server. Data will be encoded in JSON and sent to specified server. Currently only POST request can be send. Minimal example:

HttpHandler(HttpRequestType.post, Uri.parse("http://logs.server.com")

All parameters list:

  • requestType (required) - type of request, currently only POST is supported
  • endpointUri (required) - uri address of server
  • headers (optional) - map of additional headers that can be send in http request
  • requestTimeout (optional) - request time in milliseconds
  • printLogs (optional) - show debug logs
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableStackTrace (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description

You can try using example backend server which handles logs. It's written in Java 8 and Spring Framework and uses material design. You can find code of backend server here: https://github.com/jhomlala/catcher/tree/master/backend

Note: Remeber to add Internet permission in Android Manifest:

<uses-permission android:name="android.permission.INTERNET"/>

File Handler

File handler allows to store logs in file. Minimal example:

main() {
  String path = "/storage/emulated/0/log.txt";
  CatcherOptions debugOptions = CatcherOptions(
      DialogReportMode(), [FileHandler(File(path), printLogs: true)]);
  CatcherOptions releaseOptions =
      CatcherOptions(DialogReportMode(), [FileHandler(File(path))]);

  Catcher(rootWidget: MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}

All parameters list:

  • file (required) - the file where you want to store your logs
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableStackTrace (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description
  • printLogs (optional) - enable/disable debug logs
  • handleWhenRejected - please look in console handler description

Example of logging to file in external directory: https://github.com/jhomlala/catcher/blob/master/example/lib/file_example.dart

If you want to get file path with path_provider lib, you need to call Catcher constructor with ensureInitialized = true. Then you need to pass your catcher config with updateConfig. This is required because WidgetBindings ensureInitialized must be called first before accessing path_provider methods. See example here: https://github.com/jhomlala/catcher/blob/master/example/lib/file_example.dart

Toast Handler

Toast handler allows to show short message in toast. Minimal example:

All parameters list:

  • gravity (optional) - location of the toast on screen top/middle/bottom
  • length (optional) - length of toast: long or short
  • backgroundColor (optional) - background color of toast
  • textColor (optional) - text color of toast
  • fontSize (optional) - text size
  • customMessage (optional) - custom message for toast, if not set then "Error occured: error" will be displayed.
  • handleWhenRejected - please look in console handler description

Sentry Handler

Sentry handler allows to send handled errors to Sentry.io. Before using sentry handler, you need to create your project in Sentry.io page and then copy DSN link. Example:

main() {

  CatcherOptions debugOptions = CatcherOptions(
      DialogReportMode(), [SentryHandler(SentryClient("YOUR_DSN_HERE"))]);
  CatcherOptions releaseOptions = CatcherOptions(NotificationReportMode(), [
    EmailManualHandler(["[email protected]"])
  ]);

  Catcher(rootWidget: MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}

All parameters list:

  • sentryClient - sentry client instance
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description
  • customEnvironment (optional) - custom environment string, if null, Catcher will generate it
  • customRelease (optional) - custom release string , if null, Catcher will generate it
  • printLogs (optional) - enable/disable debug logs

Slack Handler

Slack Handler allows to send messages to your Slack workspace. You can specify destination of your message and format. You need to register webhook in your workspace to make this handler works: https://api.slack.com/incoming-webhooks.

main() {

 CatcherOptions debugOptions = CatcherOptions(SilentReportMode(), [
     SlackHandler(
         "<web_hook_url>",
         "#catcher",
         username: "CatcherTest",
         iconEmoji: ":thinking_face:",
         enableDeviceParameters: true,
         enableApplicationParameters: true,
         enableCustomParameters: true,
         enableStackTrace: true,
         printLogs: true),
   ]);
   Catcher(rootWidget: MyApp(), debugConfig: debugOptions);
}

All parameters list:

  • webhookUrl (required) - url of your webhook
  • channel (required) - your channel name (i.e. #catcher)
  • username (optional) - name of the integration bot
  • iconEmoji (optional) - avatar of the integration bot
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description
  • enableStackTrace (optional) - please look in console handler description
  • printLogs (optional) - enable/disable debug logs
  • customMessageBuilder - provide custom message

Discord Handler

Discord Handler allows to send messages to your Discord workspace. You need to register webhook in your server to make this handler works: https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks.

main() {
 CatcherOptions debugOptions = CatcherOptions(SilentReportMode(), [
     DiscordHandler(
         "<web_hook_url>",
         enableDeviceParameters: true,
         enableApplicationParameters: true,
         enableCustomParameters: true,
         enableStackTrace: true,
         printLogs: true),
   ]);

   Catcher(rootWidget: MyApp(), debugConfig: debugOptions);
}

All parameters list:

  • webhookUrl (required) - url of your webhook
  • enableDeviceParameters (optional) - please look in console handler description
  • enableApplicationParameters (optional) - please look in console handler description
  • enableCustomParameters (optional) - please look in console handler description
  • enableStackTrace (optional) - please look in console handler description
  • printLogs (optional) - enable/disable debug logs
  • customMessageBuilder - provide custom message

Snackbar Handler

Snackbar handler allows to show customized snackbar message.

void main() {
  CatcherOptions debugOptions = CatcherOptions(DialogReportMode(), [
    SnackbarHandler(
      Duration(seconds: 5),
      backgroundColor: Colors.green,
      elevation: 2,
      margin: EdgeInsets.all(16),
      padding: EdgeInsets.all(16),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      behavior: SnackBarBehavior.floating,
      action: SnackBarAction(
          label: "Button",
          onPressed: () {
            print("Click!");
          }),
      textStyle: TextStyle(
        color: Colors.white,
        fontSize: 16,
      ),
    ),
  ]);

  Catcher(
    runAppFunction: () {
      runApp(MyApp());
    },
    debugConfig: debugOptions,
  );
}

All parameters list:

  • duration - See [SnackBar] in Flutter docs for details.
  • backgroundColor - See [SnackBar] in Flutter docs for details.
  • elevation - See [SnackBar] in Flutter docs for details.
  • margin - See [SnackBar] in Flutter docs for details.
  • padding - See [SnackBar] in Flutter docs for details.
  • width - See [SnackBar] in Flutter docs for details.
  • shape - See [SnackBar] in Flutter docs for details.
  • behavior - See [SnackBar] in Flutter docs for details.
  • action - See [SnackBar] in Flutter docs for details.
  • animation - See [SnackBar] in Flutter docs for details.
  • onVisible - See [SnackBar] in Flutter docs for details.
  • customMessage - Custom message which can be displayed instead default one.
  • textStyle - Custom text style for text displayed within snackbar.
  • printLogs - Enable additional logs printing

Crashlytics Handler

Crashlytics handler has been removed from core package. You can re-enable it in your project by using custom report mode presented in crashlytics_example in example project.

Explicit exception report handler map

Explicit exception report handler map allows you to setup report handler for specific exception. For example if you want to setup Console Handler for FormatException, you can write:

var explicitMap = {"FormatException": ConsoleHandler()};
CatcherOptions debugOptions = CatcherOptions(
      DialogReportMode(),
      [
        ConsoleHandler(),
        HttpHandler(HttpRequestType.post, Uri.parse("https://httpstat.us/200"),
            printLogs: true)
      ],
      explicitExceptionHandlersMap: explicitMap);

Now if FormatException will be catched, then Console Handler will be used. Warning: if you setup explicit exception map for specific exception, then only this handler will be used for this exception!

Explicit exception report mode map

Same as explicit report handler map, but it's for report mode. Let's say you want to use specific report mode for some exception:

 var explicitReportModesMap = {"FormatException": NotificationReportMode()};
  CatcherOptions debugOptions = CatcherOptions(
      DialogReportMode(),
      [
        ConsoleHandler(),
        HttpHandler(HttpRequestType.post, Uri.parse("https://httpstat.us/200"),
            printLogs: true)
      ],
      explicitExceptionReportModesMap: explicitReportModesMap,);

When FormatException will be catched, then NotificationReportMode will be used. For other exceptions, Catcher will use DialogReportMode.

Error widget

You can add error widget which will replace red screen of death. To add this into your app, see code below:

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: Catcher.navigatorKey,
      //********************************************
      builder: (BuildContext context, Widget widget) {
        Catcher.addDefaultErrorWidget(
            showStacktrace: true,
            title: "Custom error title",
            description: "Custom error description",
            maxWidthForSmallMode: 150);
        return widget;
      },
      //********************************************
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget()),
    );
  }

You need to add in your MaterialApp or CupertinoApp builder method with Catcher.addDefaultErrorWidget(). This will add error handler for each widget in your app.

You can provide optional parameters:

  • showStacktrace - show/hide stacktrace
  • title - custom title for error widget
  • description - custom description for error widget
  • maxWidthForSmallMode - max width for "small" mode, default is 150

Error widget will replace your widget if he fails to render. If width of widget is less than maxWidthForSmallMode then "small" mode will be enabled, which will show only error icon

With error widget Without error widget

Current config

You can get currently used config by using:

CatcherOptions options = catcher.getCurrentConfig();

This can be used for example to change custom parameters in runtime.

Test exception

Send test exception:

Catcher.sendTestException();

Update config

You can update Catcher config during runtime:

///Catcher instance initialized
Catcher catcher;
catcher.updateConfig(
     debugConfig: CatcherOptions(
       PageReportMode(),
       [ConsoleHandler()],
     ),
   );

Screenshots

Catcher can create screenshots automatically and include them in report handlers. To add screenshot support in your app, simply wrap your root widget with CatcherScreenshot widget:

MaterialApp(
      navigatorKey: Catcher.navigatorKey,
      home: CatcherScreenshot(
        catcher: Catcher.getInstance(),
        child: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget(),
        ),
      ),
    );

Also you need to provide directory path, where Catcher will store screenshot files:

  CatcherOptions debugOptions = CatcherOptions(
    DialogReportMode(),
    [
      ToastHandler(),
    ],
    screenshotsPath: path,
  );

Screenshots will work for all platforms, except Web. Screenshots will work in:

  • Http Handler
  • Email auto handler
  • Email manual handler
  • Discord
Comments
  • Update to Flutter 3

    Update to Flutter 3

    Closes #216 Closes #217 Closes #227 Closes #229

    Until this is merged, you can use this fork by declaring a dependency_override:

    dependency_overrides:
      catcher:
        git:
          url: https://github.com/ThexXTURBOXx/catcher.git
    
    opened by ThexXTURBOXx 28
  • Only Handles Async Exceptions?

    Only Handles Async Exceptions?

    Hi, thanks for creating useful plugin! Does this plugin only handles exceptions which thrown from async function?

    This is how I reproduced the issue:

    void main() {
      CatcherOptions debugOptions = CatcherOptions(PageReportMode(), [
        EmailManualHandler(['[email protected]'])
      ]);
      CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
        EmailManualHandler(['[email protected]'])
      ]);
    
      Catcher(MyAppDemo(),debugConfig: debugOptions, releaseConfig: releaseOptions);
    }
    
    class MyAppDemo extends StatelessWidget {
      void _generateErrorAsync() async {
        Catcher.sendTestException();
      }
    
      void _generateErrorSync() {
        Catcher.sendTestException();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          navigatorKey: Catcher.navigatorKey,
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Plugin example app'),
            ),
            body: Container(
              child: FlatButton(
                child: Text("Generate error"),
                onPressed: () => _generateErrorSync(),
                // onPressed: () => _generateErrorAsync(),
              ),
            ),
          ),
        );
      }
    }
    

    Using _generateErrorAsync would show page report mode as basic example using _generateErrorSync would show the following on console:

    Restarted application in 1,774ms.
    flutter: [2020-02-07 14:21:36.854522 | Catcher | FINE] Using debug config
    flutter: [2020-02-07 14:21:36.939119 | Catcher | FINE] Catcher configured successfully.
    
    ════════ Exception caught by gesture ═══════════════════════════════════════════
    The following FormatException was thrown while handling a gesture:
    Test
    
    When the exception was thrown, this was the stack
    #0      Catcher.sendTestException
    #1      MyAppDemo._generateErrorSync
    #2      MyAppDemo.build.<anonymous closure>
    #3      _InkResponseState._handleTap
    #4      _InkResponseState.build.<anonymous closure>
    ...
    Handler: "onTap"
    Recognizer: TapGestureRecognizer#44e47
        debugOwner: GestureDetector
        state: possible
        won arena
        finalPosition: Offset(59.0, 121.5)
        finalLocalPosition: Offset(64.5, 18.0)
        button: 1
        sent tap down
    ════════════════════════════════════════════════════════════════════════════════
    

    Thanks!

    bug help wanted 
    opened by iqbalmineraltown 12
  • The plugin flutter_mailer could not be built due to AndroidX incompatibilities

    The plugin flutter_mailer could not be built due to AndroidX incompatibilities

    When I build my app for release I get this error. I can post this to the flutter_mailer package, if nobody here is experiencing the same problem.

    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':shared_preferences:verifyReleaseResources'.
    > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
       > Android resource linking failed
         /Users/jeff/.gradle/caches/transforms-2/files-2.1/0a271e99b6771ad4a84318244d532fb7/core-1.0.0/res/values/values.xml:57:5-88:25: AAPT: error: resource android:attr/fontVariationSettings not found.
    
         /Users/jeff/.gradle/caches/transforms-2/files-2.1/0a271e99b6771ad4a84318244d532fb7/core-1.0.0/res/values/values.xml:57:5-88:25: AAPT: error: resource android:attr/ttcIndex not found.
    
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 13s
    The built failed likely due to AndroidX incompatibilities in a plugin. The tool is about to try using Jetfier to solve the incompatibility.
    Building plugin catcher...
    ✓ Built build/app/outputs/repo.
    Building plugin device_info...
    ✓ Built build/app/outputs/repo.
    Building plugin flutter_mailer...
    The plugin flutter_mailer could not be built due to the issue above.
    Exited (sigterm)
    
    bug 
    opened by codegrue 10
  • Failed assertion: !_debugLocked is not true when trying to use PageReportMode

    Failed assertion: !_debugLocked is not true when trying to use PageReportMode

    Hi. I'm using 0.0.10 version of this library since it is the latest build before AndroidX changes.

    I received this error when trying to use PageModeReport in Catcher.

    Dart Error: Unhandled exception:
    E/flutter ( 2453): 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1554 pos 12: '!_debugLocked': is not true.
    

    Steps to reproduce:

    1. Use PageReportMode
    2. Try to return null on any button to produce an error
    3. Exception will be thrown as per log below
    • Report Page doesn't seem to display
    • Still displaying the red page of errors on the app

    Seems like the error was thrown due to when Navigator.push is called to display the new page.

    Any idea how to fix this issue?

    P/s: I have to use an old version of the library because my project is still below Android 28.


    main.dart

    void main() {
      ReportMode reportMode = PageReportMode(
        titleText: 'Crash Bandicoot',
        showStackTrace: true,
      );
      ConsoleHandler consoleHandler = ConsoleHandler(
        enableApplicationParameters: true,
        enableCustomParameters: true,
        enableStackTrace: true,
        enableDeviceParameters: true
      );
      CatcherOptions debugOptions = CatcherOptions(reportMode, [consoleHandler]);
      print("main.dart catcher debug");
      Catcher(MyApp(), debugConfig: debugOptions);
    //  runApp(new MyApp());
    }
    
    class MyApp extends StatelessWidget {
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        final app = MaterialApp(
          title: 'My Big Project',
          theme: buildTheme(),
          navigatorKey: Catcher.navigatorKey,
          onGenerateRoute: AppRouter().router().generator,
        );
        return app;
      }
    }
    

    Full error log:

    E/flutter ( 2453): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception: E/flutter ( 2453): 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1554 pos 12: '!_debugLocked': is not true. E/flutter ( 2453): #0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39) E/flutter ( 2453): #1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5) E/flutter ( 2453): #2 NavigatorState.push (package:flutter/src/widgets/navigator.dart:1554:12) E/flutter ( 2453): #3 Navigator.push (package:flutter/src/widgets/navigator.dart:923:34) E/flutter ( 2453): #4 PageReportMode.requestAction (package:catcher/mode/page_report_mode.dart:25:15) E/flutter ( 2453): #5 Catcher._reportError (package:catcher/core/catcher.dart:208:35) E/flutter ( 2453): E/flutter ( 2453): #6 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart:113:13) E/flutter ( 2453): E/flutter ( 2453): #7 _rootRunBinary (dart:async/zone.dart:1148:13) E/flutter ( 2453): #8 _RootZone.runBinary (dart:async/zone.dart:1385:12) E/flutter ( 2453): #9 runZoned. (dart:async/zone.dart:1479:21) E/flutter ( 2453): #10 _CustomZone.handleUncaughtError (dart:async/zone.dart:1003:19) E/flutter ( 2453): #11 Future._propagateToListeners (dart:async/future_impl.dart:558:16) E/flutter ( 2453): #12 Future._completeError (dart:async/future_impl.dart:494:5) E/flutter ( 2453): #13 _SyncCompleter._completeError (dart:async/future_impl.dart:55:12) E/flutter ( 2453): #14 _Completer.completeError (dart:async/future_impl.dart:27:5) E/flutter ( 2453): #15 _AsyncAwaitCompleter.completeError (dart:async/runtime/libasync_patch.dart:40:18) E/flutter ( 2453): #16 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart) E/flutter ( 2453): E/flutter ( 2453): #17 FlutterError.reportError (package:flutter/src/foundation/assertions.dart:408:14) E/flutter ( 2453): #18 _debugReportException (package:flutter/src/widgets/framework.dart:5000:16) E/flutter ( 2453): #19 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3724:35) E/flutter ( 2453): #20 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5) E/flutter ( 2453): #21 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3701:5) E/flutter ( 2453): #22 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3848:11) E/flutter ( 2453): #23 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3696:5) E/flutter ( 2453): #24 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #25 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #26 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4643:32) E/flutter ( 2453): #27 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4975:17) E/flutter ( 2453): #28 Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15) E/flutter ( 2453): #29 _TheatreElement.update (package:flutter/src/widgets/overlay.dart:507:16) E/flutter ( 2453): #30 Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15) E/flutter ( 2453): #31 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16) E/flutter ( 2453): #32 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5) E/flutter ( 2453): #33 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33) E/flutter ( 2453): #34 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20) E/flutter ( 2453): #35 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5) E/flutter ( 2453): #36 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15) E/flutter ( 2453): #37 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9) E/flutter ( 2453): #38 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5) E/flutter ( 2453): #39 _rootRun (dart:async/zone.dart:1124:13) E/flutter ( 2453): #40 _CustomZone.run (dart:async/zone.dart:1021:19) E/flutter ( 2453): #41 _CustomZone.runGuard E/flutter ( 2453): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception: E/flutter ( 2453): 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1554 pos 12: '!_debugLocked': is not true. E/flutter ( 2453): #0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39) E/flutter ( 2453): #1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5) E/flutter ( 2453): #2 NavigatorState.push (package:flutter/src/widgets/navigator.dart:1554:12) E/flutter ( 2453): #3 Navigator.push (package:flutter/src/widgets/navigator.dart:923:34) E/flutter ( 2453): #4 PageReportMode.requestAction (package:catcher/mode/page_report_mode.dart:25:15) E/flutter ( 2453): #5 Catcher._reportError (package:catcher/core/catcher.dart:208:35) E/flutter ( 2453): E/flutter ( 2453): #6 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart:113:13) E/flutter ( 2453): E/flutter ( 2453): #7 _rootRunBinary (dart:async/zone.dart:1148:13) E/flutter ( 2453): #8 _RootZone.runBinary (dart:async/zone.dart:1385:12) E/flutter ( 2453): #9 runZoned. (dart:async/zone.dart:1479:21) E/flutter ( 2453): #10 _CustomZone.handleUncaughtError (dart:async/zone.dart:1003:19) E/flutter ( 2453): #11 Future._propagateToListeners (dart:async/future_impl.dart:558:16) E/flutter ( 2453): #12 Future._completeError (dart:async/future_impl.dart:494:5) E/flutter ( 2453): #13 _SyncCompleter._completeError (dart:async/future_impl.dart:55:12) E/flutter ( 2453): #14 _Completer.completeError (dart:async/future_impl.dart:27:5) E/flutter ( 2453): #15 _AsyncAwaitCompleter.completeError (dart:async/runtime/libasync_patch.dart:40:18) E/flutter ( 2453): #16 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart) E/flutter ( 2453): E/flutter ( 2453): #17 FlutterError.reportError (package:flutter/src/foundation/assertions.dart:408:14) E/flutter ( 2453): #18 _debugReportException (package:flutter/src/widgets/framework.dart:5000:16) E/flutter ( 2453): #19 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3724:35) E/flutter ( 2453): #20 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5) E/flutter ( 2453): #21 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3701:5) E/flutter ( 2453): #22 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3848:11) E/flutter ( 2453): #23 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3696:5) E/flutter ( 2453): #24 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #25 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #26 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4860:14) E/flutter ( 2453): #27 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #28 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #29 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16) E/flutter ( 2453): #30 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5) E/flutter ( 2453): #31 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3701:5) E/flutter ( 2453): #32 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3696:5) E/flutter ( 2453): #33 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #34 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #35 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4860:14) E/flutter ( 2453): #36 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #37 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #38 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16) E/flutter ( 2453): #39 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5) E/flutter ( 2453): #40 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3701:5) E/flutter ( 2453): #41 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3848:11) E/flutter ( 2453): #42 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3696:5) E/flutter ( 2453): #43 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14) E/flutter ( 2453): #44 Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12) E/flutter ( 2453): #45 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16) E/flutter ( 2453): #46 Element.rebuil

    old_version 
    opened by aemxn 10
  • NoSuchMethodError: The method 'onActionConfirmed' was called on null.

    NoSuchMethodError: The method 'onActionConfirmed' was called on null.

    I'm using a slack handler. Normal error message comes with such an error. What could be the reason?

    Error:

    NoSuchMethodError: The method 'onActionConfirmed' was called on null. Receiver: null Tried calling: onActionConfirmed(Instance of 'Report')

    Stack trace:

    #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5) #1 ReportMode.onActionConfirmed (package:catcher/model/report_mode.dart:19:23) #2 SilentReportMode.requestAction (package:catcher/mode/silent_report_mode.dart:9:11) #3 Catcher._reportError (package:catcher/core/catcher.dart:294:18) #4 Catcher.reportCheckedError (package:catcher/core/catcher.dart:271:15) #5 DijitalBasinApp.build (package:dijital_basin_app/main.dart:67:15) #6 StatelessElement.build (package:flutter/src/widgets/framework.dart:3974:28) #7 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15) #8 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5) #9 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5) #10 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3902:5) #11 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3084:14) #12 Element.updateChild (package:flutter/src/widgets/framework.dart:2887:12) #13 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:939:16) #14 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:910:5) #15 RenderObjectToWidgetAdapter.attachToRenderTree. (package:flutter/src/widgets/binding.dart:856:17) #16 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2320:19) #17 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:855:13) #18 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:736:7) #19 runApp (package:flutter/src/widgets/binding.dart:786:7) #20 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart:129:7) #21 _AsyncAwaitCompleter.start (dart:async-patch/async_patch.dart:49:6) #22 Catcher._setupErrorHooks. (package:catcher/core/catcher.dart:128:14) #23 _rootRun (dart:async/zone.dart:1124:13) #24 _CustomZone.run (dart:async/zone.dart:1021:19) #25 _runZoned (dart:async/zone.dart:1516:10) #26 runZoned (dart:async/zone.dart:1500:12) #27 Catcher._setupErrorHooks (package:catcher/core/catcher.dart:128:5) #28 Catcher._configure (package:catcher/core/catcher.dart:55:5) #29 new Catcher (package:catcher/core/catcher.dart:48:5) #30 main (package:dijital_basin_app/main.dart:54:3) #31 _AsyncAwaitCompleter.start (dart:async-patch/async_patch.dart:49:6) #32 main (package:dijital_basin_app/main.dart:21:12) #33 _runMainZoned.. (dart:ui/hooks.dart:216:25) #34 _rootRun (dart:async/zone.dart:1124:13) #35 _CustomZone.run (dart:async/zone.dart:1021:19) #36 _runZoned (dart:async/zone.dart:1516:10) #37 runZoned (dart:async/zone.dart:1500:12) #38 _runMainZoned. (dart:ui/hooks.dart:208:5) #39 _startIsolate. (dart:isolate-patch/isolate_patch.dart:301:19) #40 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)

    opened by hasimyerlikaya 9
  • Incompatibility with AndroidX

    Incompatibility with AndroidX

    I update your pubspec.yaml to: fluttertoast: ^2.2.11 device_info: ^0.4.0 package_info: ^0.4.0+1 mailer: ^2.2.0 dio: ^1.0.14 flutter_local_notifications: ^0.5.1 flutter_mailer: ^0.4.0+1 logging: ^0.11.3+2

    And works fine with Android 28 :)

    opened by vico-aguado 9
  • [BUG] FlutterToastPage context is used after disposed

    [BUG] FlutterToastPage context is used after disposed

    First of all, please add all platforms in getSupportedPlatforms.

    Describe the bug It may happen when several errors raised in a very short time.

    void testFunction() async {
      Catcher.reportCheckedError('Test Error 1', StackTrace.current);
      await Future.delayed(Duration(milliseconds: 50));
      Catcher.reportCheckedError('Test Error 2', StackTrace.current);
      await Future.delayed(Duration(milliseconds: 50));
      Catcher.reportCheckedError('Test Error 3', StackTrace.current);
      await Future.delayed(Duration(milliseconds: 50));
      Catcher.reportCheckedError('Test Error 4', StackTrace.current);
      await Future.delayed(Duration(milliseconds: 50));
      return;
    }
    

    Error 1:

    flutter: [2021-05-03 00:13:59.111809 | ConsoleHandler | INFO] ---------- ERROR ----------
    flutter: [2021-05-03 00:13:59.111945 | ConsoleHandler | INFO] This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
    Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
    flutter: [2021-05-03 00:13:59.111998 | ConsoleHandler | INFO] 
    flutter: [2021-05-03 00:13:59.112026 | ConsoleHandler | INFO] ------- STACK TRACE -------
    flutter: [2021-05-03 00:13:59.112156 | ConsoleHandler | INFO] #0      State.context.<anonymous closure> (package:flutter/src/widgets/framework.dart:909:9)
    flutter: [2021-05-03 00:13:59.112197 | ConsoleHandler | INFO] #1      State.context (package:flutter/src/widgets/framework.dart:915:6)
    flutter: [2021-05-03 00:13:59.112223 | ConsoleHandler | INFO] #2      _FlutterToastPageState.showToast.<anonymous closure> (package:catcher/handlers/toast_handler.dart:160:22)
    flutter: [2021-05-03 00:13:59.112259 | ConsoleHandler | INFO] #3      new Future.delayed.<anonymous closure> (dart:async/future.dart:315:39)
    flutter: [2021-05-03 00:13:59.112292 | ConsoleHandler | INFO] #4      _rootRun (dart:async/zone.dart:1420:47)
    flutter: [2021-05-03 00:13:59.112317 | ConsoleHandler | INFO] #5      _CustomZone.run (dart:async/zone.dart:1328:19)
    flutter: [2021-05-03 00:13:59.112344 | ConsoleHandler | INFO] #6      _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
    flutter: [2021-05-03 00:13:59.112368 | ConsoleHandler | INFO] #7      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
    flutter: [2021-05-03 00:13:59.112394 | ConsoleHandler | INFO] #8      _rootRun (dart:async/zone.dart:1428:13)
    flutter: [2021-05-03 00:13:59.112419 | ConsoleHandler | INFO] #9      _CustomZone.run (dart:async/zone.dart:1328:19)
    flutter: [2021-05-03 00:13:59.112445 | ConsoleHandler | INFO] #10     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
    flutter: [2021-05-03 00:13:59.112470 | ConsoleHandler | INFO] #11     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
    flutter: [2021-05-03 00:13:59.112499 | ConsoleHandler | INFO] #12     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
    flutter: [2021-05-03 00:13:59.112532 | ConsoleHandler | INFO] #13     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
    flutter: [2021-05-03 00:13:59.112566 | ConsoleHandler | INFO] #14     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
    flutter: [2021-05-03 00:13:59.112598 | ConsoleHandler | INFO] 
    flutter: [2021-05-03 00:13:59.112639 | ConsoleHandler | INFO] ======================================================================
    

    Or maybe Error 2

    flutter: [2021-05-03 00:42:02.729936 | ConsoleHandler | INFO] ---------- ERROR ----------
    flutter: [2021-05-03 00:42:02.730296 | ConsoleHandler | INFO] Looking up a deactivated widget's ancestor is unsafe.
    At this point the state of the widget's element tree is no longer stable.
    To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
    flutter: [2021-05-03 00:42:02.730455 | ConsoleHandler | INFO] 
    flutter: [2021-05-03 00:42:02.730553 | ConsoleHandler | INFO] ------- STACK TRACE -------
    flutter: [2021-05-03 00:42:02.730785 | ConsoleHandler | INFO] #0      Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3966:9)
    flutter: [2021-05-03 00:42:02.730844 | ConsoleHandler | INFO] #1      Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3980:6)
    flutter: [2021-05-03 00:42:02.730889 | ConsoleHandler | INFO] #2      Element.findAncestorStateOfType (package:flutter/src/widgets/framework.dart:4027:12)
    flutter: [2021-05-03 00:42:02.730927 | ConsoleHandler | INFO] #3      Overlay.of (package:flutter/src/widgets/overlay.dart:294:19)
    flutter: [2021-05-03 00:42:02.731064 | ConsoleHandler | INFO] #4      FToast._showOverlay (package:fluttertoast/fluttertoast.dart:145:13)
    flutter: [2021-05-03 00:42:02.731227 | ConsoleHandler | INFO] #5      FToast.removeCustomToast (package:fluttertoast/fluttertoast.dart:160:5)
    flutter: [2021-05-03 00:42:02.731438 | ConsoleHandler | INFO] #6      FToast._showOverlay.<anonymous closure>.<anonymous closure> (package:fluttertoast/fluttertoast.dart:149:9)
    flutter: [2021-05-03 00:42:02.731572 | ConsoleHandler | INFO] #7      new Future.delayed.<anonymous closure> (dart:async/future.dart:315:39)
    flutter: [2021-05-03 00:42:02.731676 | ConsoleHandler | INFO] #8      _rootRun (dart:async/zone.dart:1420:47)
    flutter: [2021-05-03 00:42:02.731752 | ConsoleHandler | INFO] #9      _CustomZone.run (dart:async/zone.dart:1328:19)
    flutter: [2021-05-03 00:42:02.731828 | ConsoleHandler | INFO] #10     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
    flutter: [2021-05-03 00:42:02.732035 | ConsoleHandler | INFO] #11     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
    flutter: [2021-05-03 00:42:02.732131 | ConsoleHandler | INFO] #12     _rootRun (dart:async/zone.dart:1428:13)
    flutter: [2021-05-03 00:42:02.732182 | ConsoleHandler | INFO] #13     _CustomZone.run (dart:async/zone.dart:1328:19)
    flutter: [2021-05-03 00:42:02.732261 | ConsoleHandler | INFO] #14     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
    flutter: [2021-05-03 00:42:02.732302 | ConsoleHandler | INFO] #15     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
    flutter: [2021-05-03 00:42:02.732343 | ConsoleHandler | INFO] #16     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
    flutter: [2021-05-03 00:42:02.732383 | ConsoleHandler | INFO] #17     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
    flutter: [2021-05-03 00:42:02.732427 | ConsoleHandler | INFO] #18     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
    flutter: [2021-05-03 00:42:02.732464 | ConsoleHandler | INFO] 
    flutter: [2021-05-03 00:42:02.732504 | ConsoleHandler | INFO] ======================================================================
    

    I think the FlutterToastPage is unnecessary. This widget here is to pass context to FToast right? It seems not safe here. Maybe it will be popped by other code. So its context is never valid: Navigator.of(context) and FToast.

    Why not directly pass context in ToastHandler.handle?

    See the changed code, at least the test code above passed.

    import 'package:catcher/core/application_profile_manager.dart';
    import 'package:catcher/model/platform_type.dart';
    import 'package:catcher/model/report.dart';
    import 'package:catcher/model/report_handler.dart';
    import 'package:catcher/model/toast_handler_gravity.dart';
    import 'package:catcher/model/toast_handler_length.dart';
    import 'package:flutter/material.dart';
    import 'package:fluttertoast/fluttertoast.dart';
    
    class ToastHandler extends ReportHandler {
      final ToastHandlerGravity gravity;
      final ToastHandlerLength length;
      final Color backgroundColor;
      final Color textColor;
      final double textSize;
      final String? customMessage;
    
      ToastHandler({
        this.gravity = ToastHandlerGravity.bottom,
        this.length = ToastHandlerLength.long,
        this.backgroundColor = Colors.black87,
        this.textColor = Colors.white,
        this.textSize = 12,
        this.customMessage,
      });
    
      FToast fToast = FToast();
    
      @override
      Future<bool> handle(Report error, BuildContext? buildContext) async {
        if (ApplicationProfileManager.isAndroid() ||
            ApplicationProfileManager.isIos() ||
            ApplicationProfileManager.isWeb()) {
          Fluttertoast.showToast(
              msg: _getErrorMessage(error),
              toastLength: _getLength(),
              gravity: _getGravity(),
              timeInSecForIosWeb: _getLengthIos(),
              backgroundColor: backgroundColor,
              textColor: textColor,
              fontSize: textSize);
        } else {
          // If error raised before app initiated
          if (buildContext == null) {
            return false;
          }
          fToast.init(buildContext);
          Duration duration = Duration(seconds: _getLengthIos());
          Future.delayed(const Duration(milliseconds: 500), () {
            fToast.showToast(
              child: Container(
                color: backgroundColor,
                child: Text(
                  _getErrorMessage(error),
                  style: TextStyle(
                    color: textColor,
                    fontSize: textSize,
                  ),
                ),
              ),
              gravity: _getGravity(),
              toastDuration: duration,
            );
          });
        }
    
        return true;
      }
    
      ToastGravity _getGravity() {
        switch (gravity) {
          case ToastHandlerGravity.bottom:
            return ToastGravity.BOTTOM;
          case ToastHandlerGravity.center:
            return ToastGravity.CENTER;
          case ToastHandlerGravity.top:
            return ToastGravity.TOP;
        }
      }
    
      Toast _getLength() {
        if (length == ToastHandlerLength.long) {
          return Toast.LENGTH_LONG;
        } else {
          return Toast.LENGTH_SHORT;
        }
      }
    
      int _getLengthIos() {
        if (length == ToastHandlerLength.long) {
          return 5;
        } else {
          return 1;
        }
      }
    
      String _getErrorMessage(Report error) {
        if (customMessage?.isNotEmpty == true) {
          return customMessage!;
        } else {
          return "${localizationOptions.toastHandlerDescription} ${error.error}";
        }
      }
    
      @override
      List<PlatformType> getSupportedPlatforms() => [
            PlatformType.web,
            PlatformType.android,
            PlatformType.iOS,
            PlatformType.linux,
            PlatformType.macOS,
            PlatformType.windows,
          ];
    
      @override
      bool isContextRequired() {
        return true;
      }
    }
    

    Catcher version

    • Version: 0.6.5, macOS

    Another thing said in the closed issue: Add error detail in ErrorWidget too https://github.com/jhomlala/catcher/issues/163#issuecomment-822032376

    bug 
    opened by narumi147 8
  • Couldn't use report mode becuase you didn't provide navigator key. Add navigator key to use this report mode.

    Couldn't use report mode becuase you didn't provide navigator key. Add navigator key to use this report mode.

    Hi,

    Im using Flutter (Channel stable, 1.20.2, on Microsoft Windows [Version 10.0.18363.1016], locale en-IN)

    and using Plugin version catcher: 0.3.2

    Pls see below code how i use Catcher

      ReportHandler emailReportHandler = EmailManualHandler(["[email protected]"],
          enableDeviceParameters: true,
          enableStackTrace: true,
          enableCustomParameters: true,
          enableApplicationParameters: false,
          sendHtml: true,
          emailTitle: 'Application Crash Report',
          emailHeader: Texts.EMAIL_TEMPLATE,
          printLogs: true);
    
      var explicitMap = {
        "FormatException": ConsoleHandler(),
        "RenderFlex": ConsoleHandler(),
        "Exception": ConsoleHandler(),
        "MissingPluginException": ConsoleHandler(),
       };
    
      var explicitReportModesMap = {
        "FormatException": SilentReportMode(),
        "RenderFlex": SilentReportMode(),
        "Exception": SilentReportMode(),
        "MissingPluginException": SilentReportMode(),
      };
    
    
      Map<String, dynamic> customParams=
      {
        "AppVersion": '$appVersion',
        "Host": 'Test',
      };
     
    
      CatcherOptions debugOptions = CatcherOptions(DialogReportMode(), [ConsoleHandler(enableCustomParameters: false,),emailReportHandler], customParameters: customParams,explicitExceptionHandlersMap: explicitMap,explicitExceptionReportModesMap: explicitReportModesMap,);
    
      CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [ConsoleHandler(enableCustomParameters: false,),emailReportHandler],customParameters: customParams,explicitExceptionHandlersMap: explicitMap,explicitExceptionReportModesMap: explicitReportModesMap,);
    
      catcher = Catcher(new MediaQuery(
          data: new MediaQueryData.fromWindow(window),
          child: new Directionality(
              textDirection: TextDirection.ltr,
              child: MaterialApp(
                  debugShowCheckedModeBanner: true,
                  builder: (BuildContext context, Widget widget) {
                    Catcher.addDefaultErrorWidget(
                        showStacktrace: true,
                        customTitle: 'An unexpected error occurred forcing the application to stop.',
                        customDescription: " Please help us fix this by sending us error data.\n\nApplication has been able to get error state. See details below");
                    return widget;
                  },
                  navigatorKey: Catcher.navigatorKey,
                  title: Texts.TITLE,
                  home: _defaultHome,
                  theme: ThemeData(
                      primarySwatch: CompanyColors.black,
                      accentColor: Palette.appColor,
                      textTheme: TextTheme(
                          body1: TextStyle(
                              fontWeight: FontWeight.normal,
                              fontSize: 18.0,
                              color: Colors.black))),
                  routes: <String, WidgetBuilder>{
                    '/login': (context) => new LoginPage(),
                    '/home': (context) => new HomePage(),
                  }))),
          debugConfig: debugOptions,
          releaseConfig: releaseOptions,
          enableLogger: true); 
    }
    

    Whenever a crash occurred, it shows this in Run console Couldn't use report mode because you didn't provide navigator key. Add navigator key to use this report mode.

    Same in iOS and Android side.

    Kindly let me know how to solve this issue.

    help wanted 
    opened by praveenb 8
  • Email Handler - Email Sign-in Attempt Blocked by Google.

    Email Handler - Email Sign-in Attempt Blocked by Google.

    Hi Jakub,

    I make use of EmailHandler to automatically send emails when errors occur. I set up a Gmail account (linked to my main account), as you suggest, and use its address and password in the app as the sender of the emails. All works fine as far as Catcher is concerned...has been very useful in my testing/debugging.

    However, a friend of mine is now testing the app some 9000kms from me. When she hit a bug and the error was caught by Catcher, the sending of the email failed because Google detected it as a suspicious login to the email account and blocked it. Obviously, this is going to be a big problem when the app goes live. I am using Firebase as a backend and have no plans to set up my own server so HTTP handler is a no-go.

    I see Catcher as a very important component of my live app and really hope there is a solution. Do you have any advice on how to overcome this issue?

    question 
    opened by GrahamDi 8
  • LocalizationOptions settings are being ignored

    LocalizationOptions settings are being ignored

    The Catcher class is called from the main() function of a Flutter app. The main() function of a Flutter app has no BuildContext which causes the Catcher class to fail to initialize the Catcher private _localizationOptions map to use the custom localization values passed in the debug and release option params. All Catcher dialogs then fail to use the custom localization text.

    My debugging research has found that the Catcher private function named _setupLocalization() is checking for a valid BuildContext (_isContextValid()) in order to populate the private _localizationOptions map. However, because a Flutter main() function has no context at startup, the Catcher private function _setupLocalization() never uses the custom LocalizationOptions defined in either the debugConfig or the releaseConfig params passed into the Catcher class instance.

    I would love to change this code and create a pull request for you, but unfortunately I do not understand your intent of using a BuildContext during the startup of the app when no BuildContext is available yet.

    I've attached a main.dart file (renamed main.txt due to limitations of GitHub) which is nearly an exact copy of the Catcher example file named localization_example.dart. The only thing I changed was to remove the PL localization options and I modified the EN localization content declaration, all functionality is identical to the Catcher example file.

    Here's my sample file for you to test (my custom localization content is not displayed): main.txt

    • Just rename this to main.dart, create a Flutter project, then copy it on top of the default main.dart. Then add the following dependencies to your pubspec.yaml: catcher: ^0.2.7 easy_localization: ^1.3.1
    opened by kabnfever 8
  • choosing exception handler based on particular exception

    choosing exception handler based on particular exception

    Hi,

    Great package! Have you thought about adding a functionality to choose a handler based on the actual exception?

    Let's say I want to catch all APIErorrs and display a toast to a user instead of crashing the app.

    enhancement 
    opened by ayushin 8
  • [BUG] Missing CMakeLists.txt on windows

    [BUG] Missing CMakeLists.txt on windows

    Describe the bug Hi all, after adding Catcher to my project, I get an error message about the source directory not containing the CMakeLists.txt file.

    To Reproduce Steps to reproduce the behavior:

    1. Added catcher as a dep.
    2. Tried to run the project

    Expected behavior The project to run.

    Screenshots image

    Flutter doctor • No issues found!

    Catcher version

    • Version: ^0.7.0

    Smartphone (please complete the following information):

    • Device: Windows (windows-x64)
    • OS: Windows 10
    New issue 
    opened by toheiss-btc 3
  • [FEATURE] Support for acrarium http backend

    [FEATURE] Support for acrarium http backend

    Is your feature request related to a problem? Please describe. No

    Describe the solution you'd like Support for acrarium, the official Acra backend.

    Describe alternatives you've considered No support.

    Additional context Would allow using one backend for everything instead of deploying multiple. Maybe they're mostly compatible in terms of data and supported layout.

    enhancement New issue 
    opened by 0xpr03 0
  • [BUG] Catcher uses fluttertoast which has a conflict with cloud_firestore

    [BUG] Catcher uses fluttertoast which has a conflict with cloud_firestore

    I have removed catcher from my project because of this issue : See https://github.com/firebase/flutterfire/issues/9641

    Catcher version

    • Version: 0.6.9

    Smartphone (please complete the following information):

    • Device: iPhone Simulator
    • OS: iOS 13.5

    Error :

    Can't merge user_target_xcconfig for pod targets: ["FirebaseFirestore", "AutodetectLeveldb", "Base", "WithLeveldb", "fluttertoast"]. Singular build setting EXCLUDED_ARCHS[sdk=iphonesimulator*] has different values.
    
    New issue 
    opened by buzzware 0
  • Use PlatformDispatcher.onError instead of custom zone starting with Flutter 3.3

    Use PlatformDispatcher.onError instead of custom zone starting with Flutter 3.3

    Starting with Flutter 3.3, apps should now use PlatformDispatcher.onError instead of running the app in a custom zone to catch errors. I believe catcher is using a custom zone to catch errors.

    Release notes: https://medium.com/flutter/whats-new-in-flutter-3-3-893c7b9af1ff#:~:text=In%20this%20release%2C%20instead%20of%20using%20a%20custom%20Zone%2C%20you%20should%20catch%20all%20errors%20and%20exceptions%20by%20setting%20the%20PlatformDispatcher.onError%20callback.

    The error handling page was also updated to reflect these changes: https://docs.flutter.dev/testing/errors

    enhancement New issue 
    opened by HosamHasanRamadan 1
  • [BUG] Catcher is not triggered

    [BUG] Catcher is not triggered

    Describe the bug Basic settings and i dont see any dialog.

    To Reproduce

    import 'package:catcher/catcher.dart';
    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await initServices();
    
      CatcherOptions debugOptions =
          CatcherOptions(DialogReportMode(), [ConsoleHandler()]);
    
      /// Release configuration. Same as above, but once user accepts dialog, user will be prompted to send email with crash to support.
      CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
        EmailManualHandler(["[email protected]"])
      ]);
    
      Catcher(
        rootWidget: const MyApp(),
        debugConfig: debugOptions,
        releaseConfig: releaseOptions,
        enableLogger: true,
        ensureInitialized: true,
      );
      //runApp(const MyApp());
    }
    
    Future<void> initServices() async {
      print('starting services ...');
      await Get.putAsync(() => PrefsService().init());
      print('All services started...');
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        String initialPath = "/welcome";
        PrefsService storage = Get.find();
    
        return MaterialApp(
          /// STEP 3. Add navigator key from Catcher. It will be used to navigate user to report page or to show dialog.
          navigatorKey: Catcher.navigatorKey,
          home: Scaffold(
              appBar: AppBar(
                title: const Text('Plugin example app'),
              ),
              body: ChildWidget()),
        );
      }
    }
    class ChildWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
                child: TextButton(
                    child: Text("Generate error"),
                    onPressed: () => generateError()));
      }
    
      generateError() async {
        throw "Test exception";
      }
    }
    
    

    Expected behavior see error dialog, to test it

    Flutter doctor

    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel stable, 3.0.5, on macOS 12.5 21G72 darwin-arm, locale en-CZ)
    [✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    [✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
    [✓] Chrome - develop for the web
    [✓] Android Studio (version 2021.2)
    [✓] VS Code (version 1.70.2)
    [✓] Connected device (3 available)
    [✓] HTTP Host Availability
    
    • No issues found!
    

    Catcher version

    • Version: 0.6.9

    Smartphone (please complete the following information):

    • Device: [e.g. iPhone6] SIMULATOR iPhone 13 mini
    • OS: [e.g. iOS8.1] iOS 15.5

    Additional context running in vscode by run -> run without debugging | with debugging produces same stuff. Only exception in debug console as if catcher is not even there.

    New issue 
    opened by MichalNemec 1
Owner
Jakub
Android & Flutter developer
Jakub
🌈 Repository for a compass project, basically an App for displaying bank transfers, with API requests, Flag persistence, Infinite Scroll, Error Handling, Unit Tests, Extract Sharing working with SOLID, BLoC and Designer Patterns.

?? Green Bank Aplicação desenvolvida em Flutter com intuito de trabalhar conexão com API, Gerenciamento de estado usando BLoC, Refatoração, Arquitetur

André Guerra Santos 28 Oct 7, 2022
GetX Architecture for large scale project, This project include - pagination, pull to refresh, localization, network call and advance error handling

GetX Architecture for large scale project, This project include - pagination, pull to refresh, localization, network call and advance error handling

Wai Han Ko 5 Nov 29, 2022
Create flutter project with all needed configuration in two minutes (theme, localization, connect to firebase, FCM, local notifications, safe API call, error handling, animation..etc)

Flutter GetX Template Flutter Getx template to make starting project fast and easy . Introduction We all face the same problem when we want to start a

Emad Beltaje 150 Jan 7, 2023
Dart generic app exceptions, mainly aimed at flutter

Micro dart library that expose generic exceptions. The goal of this library is to for the end user to rethrow exceptions of other libraries with the s

cedvdb 2 Dec 31, 2022
This example handles HTTP GET requests by responding with 'Hello, World!'

Hello world example This example handles HTTP GET requests by responding with 'Hello, World!'. // lib/functions.dart import 'package:functions_framewo

TryIt (김동현) 0 May 25, 2022
Ozzie is your testing friend. Ozzie will take an screenshot during integration tests whenever you need. Ozzie will capture performance reports for you.

ozzie.flutter Ozzie is your testing friend. Ozzie will take an screenshot during integration tests whenever you need. Ozzie will capture performance r

Jorge Coca 40 Nov 3, 2022
A tool for digitizing medical history, prescriptions, and reports.

Shealth A tool for digitising medical history, prescriptions and report Landing page Login page Home page Registeration page Installation To render re

Servatom 15 Dec 26, 2022
A tool to help cli package authors make raising issues like bug reports more interactive for their users.

issue A tool to help cli package authors make raising issues like bug reports more interactive for their users. Features Interactive file based prompt

Viren Khatri 3 Oct 18, 2022
A flutter plugin for handling PDF files

advance_pdf_viewer A flutter plugin for handling PDF files. Works on both Android & iOS. Originally forked from (https://github.com/CrossPT/flutter_pl

Abeer Iqbal 0 Dec 3, 2021
A Flutter application with proper navigation and routes handling and API data fetching and posting.

Flutter-Navigation-and-API-Integration A Flutter application with proper navigation and routes handling and API data fetching and posting. ⏮ Preview G

Ehmad Saeed⚡ 7 Oct 5, 2022
A small app to manager simple transactions made in a shop (selling, buying, register handling..etc).

Shop Manager Flutter A small app to manager simple transactions made in a shop (selling, buying, register handling..etc). Screenshot: Features: Detail

Oussama Bonnor 45 Dec 31, 2022
20+ Error State For Android and iOS - Flutter

20+ Error State For Android and iOS - Flutter Watch it on YouTube We design 21 error pages for your app it runs both Android and iOS because it builds

Abu Anwar 544 Jan 6, 2023
A collection of stylish animated dialogs like Normal, Progress, Success, Info, Warning, and Error for flutter.

stylish_dialog A collection of stylish animated dialogs like Normal, Progress, Success, Info, Warning, and Error for flutter. Showcase ⭐ Installing de

Marsad Maqsood 5 Nov 8, 2022
A Flutter Material Button that animates between Progress and Error states

progress_button A Material Flutter Button that supports progress and error visuals Getting Started ProgressButton is designed to be easy to use and cu

Halil Ozercan 132 Sep 21, 2022
🧾 Flutter widget allowing easy cache-based data display in a ListView featuring pull-to-refresh and error banners.

Often, apps just display data fetched from some server. This package introduces the concept of fetchable streams. They are just like normal Streams, b

Marcel Garus 17 Jan 18, 2022
A package help you to make api call and handle error faster, also you can check for internet before call api.

http_solver ##not for production use, only for learning purpose. A package help you to make api call and handle error faster, also you can check for i

Abdelrahman Saed 1 Jun 18, 2020
Response Parser makes it easier to parse data and error response from server.

Response Parser makes it easier to parse data and error response from server. Getting started Do you want to write this pretty functions... Future<Eit

Qyre AB 4 Nov 5, 2022
An intuitive Token Parser that includes grammar definition, tokenization, parsing, syntax error and debugging. Implementation based on Lexical Analysis for Dart.

Token Parser An intuitive Token Parser that includes syntax/grammar definition, tokenization and parsing. Implementation based on Lexical Analysis. Re

JUST A SNIPER ツ 2 Dec 15, 2022