Firebase Crashlytics has a long history of helping Android and Apple developers ship crash-free, stable app experiences. Today, developers have a number of ways to build apps, and we are continuing to see an ever-evolving development landscape. In particular, we've seen amazing growth of apps built using Flutter, a framework that makes it a breeze to build high quality apps across a number of platforms. In recent months, the Crashlytics team has completely rethought the experience for Flutter developers and apps from the ground up. In particular, adding more helpful crash reporting APIs, revamping our analysis engine for Flutter crashes, and simplifying onboarding and plugin configuration.

New Crash Reporting APIs

There are cases when an uncaught exception within Flutter does not crash the app. Although the app is still up and running, it may be in a state that leads to a poor customer experience. What if the customer cannot advance to the next screen, or the application controls are displayed in a horizontal orientation while the phone is physically in a vertical orientation? Bad experiences often lead to customers closing the app in the best case and leaving a negative review in the worst case.

Traditional Android and iOS crashes - cases where the application shuts down - have always been reported automatically by the Crashlytics SDKs. For Flutter’s notion of uncaught exceptions, Crashlytics offered a non-fatal API. However, reporting all exceptions as a non-fatal dilutes the priority of issues. After all, unanticipated events are usually more important than expected ones.

The latest Crashlytics Flutter plugin introduces two new fatals APIs; a convenience API that plugs directly into FlutterError.onError, and a more generic API that allows you to specify the error and stack trace.

recordFlutterFatalError(FlutterErrorDetails flutterErrorDetails);
recordError(dynamic exception, StackTrace? stack,
      {dynamic reason,
      Iterable<DiagnosticsNode> information = const [],
      bool? printDetails,
      bool fatal = true}) async;

Both APIs report exceptions as fatal events to Crashlytics providing a way to distinguish between the priority of issues in the same intuitive way as is done on native Android and iOS apps.

Since Flutter error mechanisms are different from traditional platforms, it is worth thinking about where it makes sense to report issues as fatal and non-fatal. For example, any installable error handler is appropriate for fatal reporting - the most common being Zone and Isolate handlers. Aside from clarifying the priority of problematic events within a Flutter application, there are several important differences between fatal and non-fatal events: their timeliness of reporting, effect on the crash-free user calculation, and alerting.

Timeliness of Reporting

As mentioned previously, on Android and iOS, an unexpected error crashes the app. In many cases, especially for iOS and Android NDK apps, an error invokes the signal handler. The POSIX standard has restrictions on what can be done within a signal handler - unfortunately, making network calls to send a report does not make the cut, requiring an application restart. Since Flutter apps do not typically crash, relying on an application restart to send the report is not reliable, especially when the app mostly continues to function.

Instead of waiting for the user to quit and reopen the app, the new fatals API is on-demand. On-demand means that the report is sent to Crashlytics as soon as it is logged, providing you with a real-time view into the issues within your Flutter app and eliminating cases where your users don’t relaunch the apps for a long time, or at all!

The on-demand nature of the new fatals API makes the already real-time Crashlytics system even more timely. This is especially important when launching a new version of your app or flipping a feature flag.

Crash-free Users

The Crash Free Users (CFU) metric is oftentimes the guiding star that developers monitor to determine the health of their app. The latest Crashlytics Flutter SDK makes this metric more accurate because it provides an idiomatic API for capturing and delivering fatal events that more closely aligns with the Flutter application lifecycle.

Crash-free statistics
Crash-free statistics

Velocity Alerts

The speedy nature of the on-demand fatals API brings with it a more timely notification system. Velocity Alerts is Crashlytics’ early warning system, notifying developers of spiking issues within their app as soon as they occur. Velocity Alerts are particularly useful when rolling out a new version of your app or turning on a feature. Emerging issues are new issues that are affecting a disproportionate number of sessions. In the case of feature flags, a Velocity Alert on a related issue is a great signal to turn off the new feature and investigate further.

Velocity Alert
Velocity Alert

Smarter Grouping of Crashes

Collecting and submitting crash reports is just the start of the battle. Once a crash is received by Crashlytics, it’s run through our analysis pipeline which groups related crashes together into issues.

For Android, iOS, and Unity crashes, the analyzer uses a large number of heuristics to determine how to group individual reports into issues effectively. The better the heuristics, the fewer discrete root causes are grouped into a single issue, providing a more accurate view of the issues within the app, leading to a quicker triage time and reducing time-to-resolution.

For Flutter apps, additional heuristics are needed to correctly classify and differentiate Flutter framework frames from frames within the application code. The Crashlytics grouping algorithm has now been updated with a large number of Flutter-specific heuristics, resulting in a much smaller probability of issues containing more than a single, discrete root cause. Better heuristics also produce a more accurate highlighted frame of interest within the console, pinpointing where in the code the investigation should start!

Simple Onboarding

Getting started with a new tool shouldn’t be rocket science. Complicated and lengthy steps provide ample opportunity to make mistakes. With the latest Crashlytics Flutter plugin, many of the manual steps necessary to get up and running have been automated. In particular, you no longer need to modify your Android and iOS generated projects to upload the appropriate symbol and mapping files. Now, configuring Crashlytics is just three steps.

These improvements, coupled with the project configuration option within the Firebase CLI, allows you to think about your Flutter application as a single entity instead of many platform-specific projects. This not only reduces frustration and speeds up the onboarding process, but also reduces the opportunity for error.

Improved Documentation

All the new features that the latest Crashlytics Flutter plugin offers would not be complete without comprehensive, easy to find docs. The docs have moved to firebase.google.com/docs and have been completely updated to reflect the latest improvements.

As the Flutter community grows, we’re making sure that Crashlytics offers best-in-class crash reporting for Flutter-based apps. We’re excited about these updates and can’t wait to hear what you think! This is also just the start - we’re continuing to work on Crashlytics features to help Flutter apps monitor app health, so stay tuned for more to come.