# `firebase_crashlytics`

| Package | Kind | Provides the role | Needs | Choose with |
| --- | --- | --- | --- | --- |
| [`smf_firebase_crashlytics`](https://pub.dev/packages/smf_firebase_crashlytics) | infrastructure | Crash reporting | [`firebase_core`](https://doc.saymyframe.com/modules/firebase-core.md) | `-m firebase_crashlytics` |

`firebase_crashlytics` reports errors to [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics) with the [firebase_crashlytics](https://pub.dev/packages/firebase_crashlytics) package: the errors that the app does not handle, and those that its code reports.

## What it adds to the app

The module adds `firebase_crashlytics: ^5.4.0` to the dependencies, and `lib/core/crash_reporting/crashlytics_crash_reporter.dart` with the reporter on `FirebaseCrashlytics.instance`.

Whichever module provides it, the crash reporting role adds `lib/core/crash_reporting/crash_reporter.dart` with:

- the `CrashReporter` interface, where `recordError` and `recordFlutterError` report an error, `log` adds a message to the log sent with the next report, and `setUserId` sets the id of the signed-in user or clears it with `null`;
- `createCrashReporter()`, which returns the reporter of the app, a reporter that forwards every call to the reporters of all the modules that provide crash reporting, each on its own, so an app can report to more than one service and a reporter that fails affects no other;
- `installCrashReporting()`, which reports as fatal the errors of the main isolate that the app does not handle.

In its platform phase, `bootstrap()` initializes Firebase and then calls `installCrashReporting()`.

In the [guide for coding agents](https://doc.saymyframe.com/guides/coding-agents.md) of the app, the crash reporting role describes the reporter under "Crash reporting". The module adds to report through `CrashReporter` and not through `FirebaseCrashlytics.instance`, and says that `tool/configure_firebase.dart` keeps the build phase working for `flutter build ipa`.

## What gets reported and printed

- Flutter still presents an error that it catches, such as one in a build, as it does by default, in every mode. The reporter sends the same report that `recordFlutterError` of Crashlytics sends.
- Any other uncaught error goes to `recordError`, and in debug mode the engine still prints it.
- The reporter itself prints nothing, so an error that the code of the app reports is not printed either. When a call to Crashlytics fails, the reporter of the app prints the failure in debug mode.
- `setUserId(null)` clears the id of the user by setting an empty one, as Crashlytics does.

The handlers cover the main isolate. For errors of other isolates, see [Services and state](https://doc.saymyframe.com/guides/services.md#crash-reporting).

## Getting the reporter

The reporter is created on first use, without waiting. With a module of dependency injection, the role registers it in the container as a lazy singleton, and a feature takes it with `resolve` in its composition file. Without a container, the code of the app calls `createCrashReporter()`.

## Native setup

The module generates nothing in the native projects. `tool/configure_firebase.dart` of [`firebase_core`](https://doc.saymyframe.com/modules/firebase-core.md) has flutterfire add what Crashlytics needs to an app that depends on firebase_crashlytics, such as the build phase that uploads the debug symbols on macOS.

The phase of flutterfire_cli 1.4.1 does not find the upload script when `flutter build ipa` archives the app. flutterfire writes the phase again in each of its runs, so the module adds `tool/firebase_configured/fix_crashlytics_phase.dart`, which that script runs after each flavor. On macOS it points the phase at the upload script where Flutter puts it, and elsewhere it does nothing. The Crashlytics section of the README of the app gives its command, for when you run `flutterfire configure` yourself. See [Firebase](https://doc.saymyframe.com/guides/firebase.md#crashlytics-and-flutter-build-ipa).

The phase looks up the build configuration in `firebase.json`, so on macOS a build of a flavor that is not configured fails there once another flavor is. See [A flavor that is not configured](https://doc.saymyframe.com/guides/firebase.md#a-flavor-that-is-not-configured).

## Choosing it

`smf create` asks which modules provide the crash reporting of the app, and the answer may be none. To choose it without the question, name it in `-m`, and `firebase_core` comes with it:

```bash
smf create my_app -m firebase_crashlytics
```
