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
50 changes: 29 additions & 21 deletions docs/crashlytics/_customize-crash-reports.md
Expand Up @@ -20,57 +20,62 @@ 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,
to also catch "non-fatal" exceptions, override `FlutterError.onError` with `FirebaseCrashlytics.instance.recordFlutterError`:

```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 Down Expand Up @@ -108,6 +113,9 @@ await FirebaseCrashlytics.instance.recordError(
stackTrace,
reason: 'a non-fatal error'
);

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

You may also wish to log further information about the error which is possible
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