ZOFTINO.COM android and web dev tutorials

Fireabase Crashlytics Android Crash Reporting

In order to make your android application run without issues on user devices, you need to consider android version, device manufacturers, and features of device while developing your app. Even after through testing and taking care of all the possible failure scenarios, one unhandled scenario may cause your app to crash leading to diminished user experience.

Since android apps run on user devices, there is no way of knowing about your app crashes and scenarios causing the crashes. This is where Firebase crashlytics comes into picture. If you add this tool to your app, the tool will capture the crashes on user devices and make the information about crashes available for you to view on Firebase console so that you can fix the root causes if any which are causing your app to crash.

Adding Crashlytics to Android App

To start capturing crash details of an android app, all that needs to be done is to add crashlytics SDK to the app and it will automatically captures app crash information. Below are the steps to add crashlytics SDK to android app.

First you need to add Firebase SDK to your project and then you need to add Crashlytics libraries to the project. To add Firebase SDK, login to firebase console, create Firebase project and add it to android project, then download the google-services.json file and save it in app directory of your project. You can find step by step instructions to do the setup at adding Firebase SDK to android project and using firebase analytics in android.

After Firebase SDK is added to your project, you need to add crashlytics SDK to project by adding below libraries.

Project level build.gradle file changes.

 buildscript {    
    repositories {
	. . . .
        maven {
            url 'https://maven.fabric.io/public'
        }
    }
    dependencies {
	. . . .
        classpath 'io.fabric.tools:gradle:1.24.4'
    }
}

allprojects {
    repositories {
	. . . .
        maven {
            url 'https://maven.google.com/'
        }
    }
}
. . . . 

App level build.gradle file change

 . . . .
apply plugin: 'io.fabric'

. . . .

dependencies {

    compile('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') {
        transitive = true
    }
    compile 'com.google.firebase:firebase-core:11.8.0'
    . . . .
}

. . . . 

That is it, after this setup, your app’s crash reports will be captured for viewing on firebase console.

Firebase Crashlytics Reports

You can view crash data in firebase console. There are filters to view crash only reports. On the main crashlytics report screen, you can find event trends, crash free stats and issues.

Firebase crashlytics reports in firebase console

On clicking an issue in issues section, detailed report page will be displayed showing stacktrace, android version, device information, device configuration when the issue occure, etc.

Firebase crashlytics detailed report in firebase console

Enabling Firebase Crashlytics for Selected Users

As mentioned before, once crashlytics libraries have been added to the project, it will automatically captures crash information. If you don’t want this behavior and want to enable this for select users, you need to follow below steps.

First, disable auto capture by adding below meta data tag to android manifest file.

<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" /> 

Then in one of the main activities, add below code to enable crashlytics based on the user settings.

 if(user.isIssueCaptureEnabled){
 Fabric.with(this, new Crashlytics());
} 

Custom Information in Crashlytics Crash Report

You can add extra information to crash report which will help in understanding the context in which a particular crash occurred. Extra information can be in the form of a message or key and value pairs or user identification information. You can add messages to crash report by using Crashlytics.log. To add key value pairs, use one of the key-value methods such as setString, setBool, setInt, etc. on Crashlytics. To add user identification information, use setUserName, setUserEmail or setUserIdentifier methods on Crashlytics as shown below.

 //crashlytics message
Crashlytics.log("After adding or updating notes");
Crashlytics.log(2, TAG, "After adding or updating notes");
//crashlytics key and value paris
if(editNotesFile != null){
    Crashlytics.setString("updating notes", editNotesFile);
}else{
    Crashlytics.setString("adding notes", notesNameET.getText().toString());
} 
//adding user identity to crash report
Crashlytics.setUserIdentifier(user.getDisplayName());
 

You can even log handled exceptions which will help you in analyzing the application flow.

try {
    notesBytes = notes.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
    Log.e(TAG, "Error encoding file", e);
    Crashlytics.logException(e);
} 

Below screen shows key and value in the carshlytic report

Firebase crashlytics reports custom logs and keys

Sending Crash Notification Using Crashlytics Triggered Cloud Functions

You can write Firebase cloud functions which can send crash notifications to support team device or do something with crash information when there is an instance of an issue.

To write a cloud function that handles crashlytics events, you need to use functions.crashlytics.issue object. There are three crashlytics events which can be handled using cloud functions, occurrence of new crash issue (onNewDetected), reoccurrence of closed issue (onRegressed) and multiple occurrences of an issue (onVelocityAlert).

From the event object passed to the event handlers, you can get issueId, appInfo, issueTitle, velocityAlert, crashPercentage, crashes, etc. Below example cloud function shows how to handle velocity alert and send notification to support team device via firebase cloud messaging.

 'use strict';

const functions = require('firebase-functions');


const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.postOnIssueCreate = functions.crashlytics.issue().onVelocityAlert(event => {
  //support device firebase token, get it from db
  const appSupportDeviceToken = 'dXYNWKwoHsshhhhyyyyn';

  const data = event.data;

  const issueId = data.issueId;
  const issueTitle = data.issueTitle;
  const appName = data.appInfo.appName;
  const crashPercentage = data.velocityAlert.crashPercentage;
  const crashes = data.velocityAlert.crashes;

  const message = ` Multiple occurance of (${issueId}) ` +
      `in ${appName} app - ${issueTitle} - crash percentage ${crashPercentage} and ${crashes}`;

  const payload = {
      notification: {
        title: 'App Crash Velocity Alert',
        body: `${message}`
      }
  };

  //send notification
  return admin.messaging().sendToDevice(appSupportDeviceToken, payload).then(response => {
      response.results.forEach((result, index) => {
        const error = result.error;
          if (error) {
           console.error('Failed to send velocity alert');
          }
      });
   });
});