Getting Readable Crash Reports in Firebase Crashlytics from your Flutter Application

Table Of Contents

  • Introduction
  • Android
  • iOS
  • Conclusion

Introduction

Many of us have deployed mobile applications to pre-production/production environments and got an email from Firebase saying “Heads up! We detected a new fatal issue in !” if you integrated Firebase crashlytics.

You wonder what it could be about, and head over to the firebase console under the crashlytics section to find out nothing makes sense, everything looks like a hexadecimal fest.

In this article, we’ll look at steps to take for both Android & iOS applications built with Flutter to ensure our crash reports are readable for every app version we release.

Before we get into it, Flutter is an open-source cross-platform development kit that supports but is not limited to Android and iOS and will generate binaries for these platforms when instructed to.

These binaries may be in .aab or .apk format for Android and in .ipa for iOS.

It’s safe to say that if you stumbled upon this article, you already understand what obfuscation means

In any case, obfuscation is a means by which during the compilation of an application, the resulting symbols or tokens that you as the developer understand and can make meaning of in the first instance, are obscured. i.e. functions, classes, and variable names will be rendered meaning less, thus making it extremely hard to reverse-engineer. This is a security measure that production-grade applications go through.

This is why stack traces or error messages on the crashlytics dashboards are a bunch of gibberish without the steps we will go into detail on.

If Firebase crashlytics was set up properly, you probably don’t need to read this article. But for some wired reason, I’ve set up a couple of Flutter applications with Firebase crashlytics following all the steps in the official documentation and I still get the warning for missing dSYM files for iOS even though there are build steps that are meant to take care of this. If you are in the same situation, then read on.

Before we proceed, I assume that you’ve already integrated Firebase crashlytics with your Flutter application for Android and iOS. If you’ve not done that, See Integrating Firebase Crashlytics with your Fluter Application

Android

When developing Android applications using Flutter and you want obfuscation enabled, you’d pass the --obfuscate flag and the --split-debug-info argument. The --split-debug-info flag is the most important argument for what we want to achieve as this tells the flutter binary where to output the debug symbols files.

We’ll upload these files to Firebase using the Firebase CLI tool.

Here’s a full flutter build command that obfuscates the resulting application and outputs the debug symbols to a specified path

flutter build apk --target-platform android-arm,android-arm64,android-x64 --release --obfuscate --split-debug-info=build/app/outputs/symbols --verbose

So we’ve told Flutter to output debug symbols to the path build/app/outputs/symbols. Note that the path will be created if it doesn’t exist.

The next step is to use the Firebase CLI tool. If you don’t have it installed, use the below command to do so

curl -sL https://firebase.tools | bash

And then use the below to log in to your Firebase account

firebase login

To upload the debug symbols, you then use the command below while pointing to the folder containing the debug symbols

firebase crashlytics:symbols:upload --app=FIREBASE_APP_ID build/app/outputs/symbols

You can obtain FIREBASE_APP_ID from your ‘Project Settings’ page in the Firebase console as shown below

Firebase Project Settings - App ID

If running the firebase crashlytics:symbols:upload command in a CI environment like GitHub Actions, set an environment variable GOOGLE_APPLICATION_CREDENTIALS to point to the location of your service account .json key file.

Below is a typical re-usable and manually dispatchable GitHub Actions workflow that downloads the symbols folder as a zipped artifact, extracts it, and uploads it to Firebase. the workflow is expected to be re-used by an actual job in a workflow consisting of other jobs.

name: upload-flutter-debug-symbols-to-firebase on: workflow_dispatch: inputs: flutter-debug-symbols-artifact-name: description: AAB Artifact Name. required: true type: string workflow_call: inputs: flutter-debug-symbols-artifact-name: description: AAB Artifact Name. required: true type: string secrets: FIREBASE_APP_ID: description: Firebase App ID required: true FIREBASE_SERVICE_ACCOUNT_JSON_CONTENT: description: Firebase Service Account Key Content required: true jobs: upload-debug-symbols: name: Upload Flutter Debug Symbols to Firebase runs-on: ubuntu-latest steps: - name: Install Firebase Tools run: curl -sL https://firebase.tools | bash - name: Download Flutter Debug Symbols uses: actions/download-artifact@v2 with: name: ${{ inputs.flutter-debug-symbols-artifact-name }} - name: Extract Flutter Debug Symbols run: unzip -q ./symbols.zip -d symbols - name: Prepare Google Service Account Credential run: echo '${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_CONTENT }}' >> firebase-service-account.json - name: Upload Flutter Debug Symbols to Firebase env: GOOGLE_APPLICATION_CREDENTIALS: firebase-service-account.json run: firebase crashlytics:symbols:upload --app=${{ secrets.FIREBASE_APP_ID }} ./symbols

iOS

Running the flutterfire configure command after integrating your Flutter project with Firebase crashlytics will attempt to add a run script to your project’s Xcode workspace that finds and uploads the necessary dSYM symbol files to Crashlytics. Without these files, you’ll see a “Missing dSYM” alert in the Crashlytics dashboard and exceptions will be held by the backend until the missing files are uploaded – firebase.google.com.

If you did not use flutterfire configure or did and you still get the “Missing dSYM” alert from Firebase, you will need to follow through on the steps from the highlighted text downwards

Sometimes, the steps in the official documentation (previous link) don’t help and sometimes cause the build process to fail depending on the complexity of your application, especially when you use the --split-debug-info argument and the optional --obfuscate flag.

There’s also the question of build schemes or flavors, concerning which Firebase credentials will be used while executing the script.

If you’ve followed through with the links above and still not getting readable crash reports from the Firebase console, two things are certain at this point.

  • You have an upload script present at ios/Pods/FirebaseCrashlytics/upload-symbols
    After a successful build process, + dSYMs are being generated at build/ios/archive/Runner.xcarchive/dSYMs.

To upload your dSYM files, the command should be somewhat like this

ios/Pods/FirebaseCrashlytics/upload-symbols -gsp <Absolute-Path-To-Flutter-Project-Root>/ios/Runner/GoogleService-Info.plist -p ios <Absolute-Path-To-Flutter-Project-Root>/build/ios/archive/Runner.xcarchive/dSYMs

The concept is the same in workflow or flavored or multi-build scheme Flutter iOS apps

Conclusion

Crash reports are essential for improving and maintaining the stability of any application as they help you identify issues before they become a major disaster. Hopefully, this article will help you achieve stability in your Flutter apps.


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top