[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]