Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(crashlytics): Use PlatformDispatcher.instance.onError for async errors. Update Crashlytics example app to use "flutterfire-e2e-tests" project. #9669

Merged
merged 8 commits into from Oct 26, 2022
53 changes: 31 additions & 22 deletions docs/crashlytics/_customize-crash-reports.md
Expand Up @@ -20,57 +20,63 @@ to disk to be sent along with the next fatal report or when the app restarts.

## Report uncaught exceptions {: #report-uncaught-exceptions}

You can automatically catch all errors that are thrown within the Flutter
You can automatically catch all "fatal" errors that are thrown within the Flutter
framework by overriding `FlutterError.onError` with
`FirebaseCrashlytics.instance.recordFlutterFatalError`:
`FirebaseCrashlytics.instance.recordFlutterFatalError`. Alternatively, if you wish
to catch "non-fatal" exceptions, please use: `FirebaseCrashlytics.instance.recordFlutterError`:

russellwheatley marked this conversation as resolved.
Show resolved Hide resolved

```dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();

await Firebase.initializeApp();

// Pass all uncaught errors from the framework to Crashlytics.
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;
bool weWantFatalErrorRecording = true;
FlutterError.onError = (errorDetails) {
if(weWantFatalErrorRecording){
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
} else {
FirebaseCrashlytics.instance.recordFlutterError(errorDetails);
}
};

runApp(MyApp());
}
```

### Zoned errors {: #zoned-errors}

Not all errors are caught by Flutter. Sometimes, errors are instead caught by
`Zones`. A common case where relying on Flutter to catch errors would not be
enough is when an exception happens inside the `onPressed` handler of a button:
### Asynchronous errors {: #asynchronous-errors}

Asynchronous errors are not caught by the Flutter framework:

```dart
ElevatedButton(
onPressed: () {
onPressed: () async {
throw Error();
}
...
)
```

To catch such errors, you can use `runZonedGuarded`:
To catch such errors, you can use the `PlatformDispatcher.instance.onError` handler:

```dart
void main() async {
runZonedGuarded<Future<void>>(() async {
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// The following lines are the same as previously explained in "Handling uncaught errors"
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;

FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
};
// Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
runApp(MyApp());
}, (error, stack) => FirebaseCrashlytics.instance.recordError(error, stack, fatal: true));

}
```

Note: You must call `WidgetsFlutterBinding.ensureInitialized()` _inside_
`runZonedGuarded`. Error handling wouldn’t work if
`WidgetsFlutterBinding.ensureInitialized()` was called from the outside.

### Errors outside of Flutter {: #errors-outside-flutter}

To catch errors that happen outside of the Flutter context, install an error
Expand All @@ -97,7 +103,7 @@ event is reported or when the app restarts.
Note: {{crashlytics}} only stores the most recent eight recorded non-fatal
exceptions. If your app throws more than eight, older exceptions are lost. This
count is reset each time a fatal exception is thrown, since this causes a report
to be sent to {{crashlytics}}.
to be sent to {{crashlytics}}.

Use the `recordError` method to record non-fatal exceptions in your app's catch
blocks. For example:
Expand All @@ -108,6 +114,9 @@ await FirebaseCrashlytics.instance.recordError(
stackTrace,
reason: 'a non-fatal error'
);

// Or you can use:
await FirebaseCrashlytics.instance.recordFlutterError(errorDetails);
```

Warning: If you want to include a unique value (for example, a user ID or a
Expand Down
26 changes: 14 additions & 12 deletions docs/crashlytics/_get-started.md
Expand Up @@ -66,29 +66,31 @@ void main() async {

await Firebase.initializeApp();

// Pass all uncaught errors from the framework to Crashlytics.
// Pass all uncaught "fatal" errors from the framework to Crashlytics
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;

runApp(MyApp());
}
```

If you're using zones, instrumenting the zone’s error handler will catch errors
that aren't caught by the Flutter framework (for example, in a button’s
`onPressed` handler):
To catch asynchronous errors that aren't handled by the Flutter framework, use
`PlatformDispatcher.instance.onError`:


```dart
void main() async {
runZonedGuarded<Future<void>>(() async {
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();

FlutterError.onError =
FirebaseCrashlytics.instance.recordFlutterFatalError;

FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
};
// Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
runApp(MyApp());
}, (error, stack) =>
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true));

}
```

Expand Down