[MUSIC PLAYING] ELENA DOTY: Hi, everyone. I'm Elena Doty and I'm here
today with Konstantin Mandrika. We are engineers on the
Firebase Crashlytics team and we wanted to share some
recent work that Crashlytics has done to improve support
for apps built with Flutter. So you're sitting in the office
one day looking for an answer to the perennial question,
how's the weather outside? Instead of looking
out the window, we explored the massive number
of already available weather apps. None of them were really quite
the right amount of perfect, so we decided to build our own. KONSTANTIN MANDRIKA:
Luckily for us, Flutter makes writing natively
compiled multi-platform apps quick and easy. Within hours, we'd released
a beautiful perfect app and could leave the
office now that we knew whether to bring an umbrella. But the next morning, we
were greeted with a flurry of negative reviews. Wrong weather, stock
flows, even a crash or two. What happened? It would have been nice
if we have been notified of these problems in our
app by something other than negative customer reviews. Of course, the earlier an
emerging problem is detected, the quicker can be fixed leading
to fewer unhappy customers. ELENA DOTY: It seems like it's
too late for that, though. At this point, it would be
helpful to at least know the extent of the problems and
to see how many of our users are being impacted by them. Knowing that the app
is unstable is just the beginning of the battle. Somehow, we'll also need to
pinpoint where in our code all these issues
are coming from. Then, figure out
how to fix them. KONSTANTIN MANDRIKA: But as
luck would have it, we both work on a crash
reporter and know exactly what this app needs. For those of you
that aren't familiar, Firebase Crashlytics is a
leading mobile crash reporter that helps you achieve
the full stability potential of your app. And now, the full range
of Crashlytics features is available to apps
built with Flutter. Crashlytics is just one piece
of the Firebase suite of tools. While Crashlytics
will help us ensure the stability of our
app, the rest of Firebase can help it grow and succeed. The first step in getting
our weather app back on track is integrating Crashlytics. Think back to the last time you
discovered a promising new tool only to realize that the setup
process was an astonishing 16 steps. We can sympathize. Not only is this frustrating,
it's also very error prone. This is why we spent a
lot of time simplifying the setup of Firebase
and Crashlytics as much as possible. Getting up and running
should be quick and painless. ELENA DOTY: The setup
process for Flutter apps differs a bit from their native
Android and iOS counterparts. Instead of creating an app
in the Firebase console, then downloading a
Google services file and dropping it into the
appropriate directory in our project, we'll use
the Flutter fire CLI tool so all we need to do is
initialize Firebase directly in our app's Dart code. Before integrating Crashlytics
into our weather app, we need to install the
Flutter Fire CLI tool and run configure. Then, we'll include the
generated Firebase options.dart file in our app, call
firebase.initializeapp and we're good to go. This is not only much
simpler and less error prone. It also allows for greater
runtime flexibility. For example, using different
Firebase app configurations for different environments
or custom builds of the app. Crashlytics supports Dart
only initialization as well. KONSTANTIN MANDRIKA: Once our
app is set up to use Firebase, getting the benefit
of Crashlytics is as easy as adding the
dependency via the Flutter pub add command. This looks simple, right? However, behind the
scenes, this instruments the iOS target to automatically
upload the appropriate symbol files that Crashlytics needs
to translate iOS stack traces into something that
is human readable. On Android, apps that aren't
taking advantage of obfuscation are good to go at
this point as well. If you are using obfuscation,
configuring the project to upload the code mapping files
on every build automatically is straightforward
and just requires adding a few lines to
the corresponding Grandal build files. The Firebase Docs outline
how to do this in detail. ELENA DOTY: With simple
[? in-mapping ?] files automatically taken care of, we
just need to rebuild the app. As Konstantin mentioned,
adding Crashlytics to a Flutter app
configured with Firebase now requires just a single step. At this point, our weather
app is set up correctly. We'll automatically receive
the rare Flutter framework and native Android
and iOS crashes. However, the most
interesting bugs are within the app's
business logic. After all, a never
ending spinner or showing the wrong weather
suggest problems with the code that we wrote not
some systemic OS bug that we just happened to hit. Business logic
errors such as these are often the most impactful
problems within an app and need to be
addressed urgently. KONSTANTIN MANDRIKA:
Such errors are very intuitive on
Android and iOS because they cause
the app to crash. These errors are
considered fatal and are captured automatically
on native platforms. For less impactful
situations, Crashlytics also has an API that lets
the developer log exceptions that are expected and
don't crash the app. Crashlytics Flutter
users were previously limited to using the non-fatal
API for all Flutter bugs, making it hard to
determine their priority. We've addressed this problem
by introducing a new API that allows you to report high
priority issues as fatal in the same manner that a crash
is reported on native Android and iOS apps. Since the Flutter
framework is set up in a way where an on
uncaught exception may not lead to a crash, we wanted
to let you, the developer, determine what is high priority. The new API has two functions. One operates on a Flutter
error details object while the other allows the
developer to specify the error and stack trace. These two functions provide
the maximum flexibility for all error scenarios. ELENA DOTY: Going back
to our weather app, we'll take advantage
of the new API to log all top level,
unhandled exceptions as fatal. FlutterError.onError is
Flutter's uncut exception mechanism that provides
a registered callback function with a
Flutter error details object describing
what the problem is. With this addition, any time
an uncaught exception occurs, it'll be logged to Crashlytics. Our app fetches the weather
via asynchronous HTTP calls. And in order to catch unexpected
errors in these calls, we've made use of
Dart's error zones. We'll go ahead and lock
all exceptions that occur within these zones as fatal. Catching errors in error zones
and with FlutterError.onError casts a wide net. It's often useful to
track specific error prone scenarios as well. In our case, we
want to make sure that the URL our app is
referencing for weather data is valid since it's constructed
using user supplied input. KONSTANTIN MANDRIKA:
While we're here, we'll also log some
non-fatal scenarios that we think are
likely causing issues. Specifically, we
suspect that we may need to ask the
user for permission before querying their
coordinates via our system APIs. A good rule of thumb for
using fatal exceptions and non-fatal exceptions
is to map them to unexpected and
expected events. In the case of our app, anything
that propagates to a top level exception handler is
unexpected and should be recorded as fatal. Most existing try catch blocks
are logged as non-fatal, though we do have some fatals. It's up to you to determine
what works best for your app. Instrumenting our app with
these few Crashlytics API calls provides a large breadth
of error coverage and serves as a good starting
point in our debugging journey. ELENA DOTY: Thinking
back a little bit, notice that we said report
high priority issues instead of record high priority issues. That was intentional. On traditional platforms,
restarting the application after a crash triggers
the sending of a report to Crashlytics. This is necessary for
various technical reasons, especially on iOS
and Android NDK. But since Flutter errors
don't usually lead to a crash, the time between a problem
occurring and an app restart can be long. This motivated us to make
the new fatal API on demand. In other words, as soon as you
log a high priority event using the new API, it'll
be immediately sent to the Crashlytics
backend for processing and it'll show up in
the dashboard almost instantaneously. KONSTANTIN MANDRIKA:
Since high priority events are treated in the exact same
way as standard Android and iOS crashes, we can take
advantage of Crashlytics' early alert system,
Velocity alerts. Velocity alerts can easily
be set up and configured and the Crashlytics console. We can choose to receive
emails about new alerts or integrate with
third party services. We'll stick with
just emails for now and configure alerting to start
when 1% of all user sessions are affected by an issue. This will help notify us
of high impact emerging app problems that are
affecting many customers. Having taken advantage of the
new APIs to record exceptions is fatal. And having set up
velocity alerts to alert us of high
impact emerging problems, we released a new
version of our app. ELENA DOTY: Within minutes,
we got our first alert. It's a nerdy thing to
be excited about, maybe. But this is the first
step towards figuring out what the impactful
problems in our app are. Each velocity alerts
email has a link to the specific issue in
the Crashlytics dashboard that prompted it. That issue is where we'll
start our investigation into just where the problems
in our code are hiding. Looks like our weather app
isn't validating the zip code correctly. From the stack trace, we
can see that an exception is being logged when
we try to validate the URL, one of the scenarios we
chose to log as fatal earlier. Choosing to log this
exception as fatal also means that
users who experience it count against our
crash free users metric. This metric tells us
what percentage of users have not experienced a crash. Because our invalid URL
exception is considered fatal, the crash free users percentage
will decrease accordingly each time a new
user runs into it. Our zip code validation mix up
happens to be a straightforward problem. Unfortunately, not
all issues are going to be this simple to solve. Some end up being extremely
tricky to track down. KONSTANTIN MANDRIKA: Some
are downright frustrating such as when a system or Flutter
framework frame is highlighted and you know it just can't
possibly be the problem. We got your back. We've done quite a bit of work
to revamp our analysis engine. For example, we've
added a number of heuristics that
deprioritized frames that are unlikely to lead to a crash. And as a consequence,
we've improved how crashes are grouped
together providing a more accurate insight
into your app stability and allowing you to triage,
prioritize, and fix issues faster. In our case, better
grouping helped expose the multitude
of distinct problems that the users of our weather
app were running into, giving us a better sense of
just how broken the app is. ELENA DOTY: In service of
all these improvements, we've, of course,
revamped our Docs. Not only the
content of the Docs, but their discoverability. All of the Flutter Docs have
moved into the same place as the Android and iOS Docs. Firebase.google.com/docs. Check them out. We've added many new code
snippets and useful guides to help you build
the best app yet. And in case you
come upon a question that the Docs can't
answer, don't worry. The Firebase support
team is now ramped up to tackle the most
difficult questions. Feel free to reach out. KONSTANTIN MANDRIKA: As Elena
and I found out the hard way, even experienced
developers write bugs. Thankfully, we no longer
have to rely on bad reviews to know if our app is
crashing or on trial and error to figure out where in
the code we messed up. Now that we know how to
make reliable stable apps, the possibilities are endless. Maybe we'll make
a chat app next. So whether you're experienced
with Flutter development or just starting out,
we're excited for you to give Crashlytics a try
within your Flutter app. With the new simplified
onboarding process, getting started is
easier than ever. We've done a lot
of work to ensure that the large range
of Crashlytics features are fully supported in
apps built with Flutter. And we're looking forward
to hearing your feedback. Go to firebase.google.com/docs
to get started and be on the lookout for future
technical blog posts Thanks. [MUSIC PLAYING]