Crash Reporting an Android App with Crashlytics and Fabric
This article was updated on January 18, 2017. Specifically: Added coverage of Crashlytics Answers.
The Fabric Library from Twitter provides a suite of tools to complement and enhance your apps. In this tutorial I will focus on the crash reporting features that help pinpoint and track app crashes.
Adding the Fabric Plugin
Create a new project in Android Studio, choosing a minimum API level of 18 and adding a Blank Activity.
Open the Android Studio plugin manager, click Browse Repositories, search for Fabric and install the plugin. Restart Android Studio for the plugin to take effect and a new icon will appear in the upper toolbar.
Clicking the icon will open a panel on the right hand side of the Android Studio window. Click the power button to register or login to the Fabric service, then click Next, Crashlytics and Install.
Fabric will show you the changes it needs to make to your application, check them and click Apply in the bottom right of the screen.
Force A Simple Crash
As this is a sample application you have to force a crash by clicking a button in the app.
Open activity_main.xml and delete the unnecessary ‘Floating Action Bar Button’ code.
Inside the content_main.xml layout add two buttons to represent the report types that Crashlytics supports.
Replace the TextView
with this code:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Simple Crash"
android:onClick="forceCrash"
android:layout_gravity="center" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Extra Info Crash"
android:onClick="showUserDialog"
android:layout_gravity="center"
android:layout_marginTop="30dp" />
</LinearLayout>
Open the MainActivity.java class and delete the ‘Floating Action Button’ code. Before the onCreate()
method, add the following:
private EditText userIdentifierEditText, userEmailEditText, userNameEditText;
private String userIdentifier, userEmail, userName;
These variables will be used in the second crash reporting type that includes custom user information.
The first simple crash throws a RuntimeException
to cause an application crash.
Add the following after the onCreate()
method:
public void forceCrash(View view) {
throw new RuntimeException("This is a simple crash");
}
As the view is called on a button click, the function takes a View
as a parameter and needs to be public
. When clicked, the method forceCrash
throws a RuntimeException
and sends a report to the Fabric Dashboard. The information included in this report will contain the line of code that caused the crash and general device information.
Force a crash that includes user information
The second button simulates a crash that allows a user to input information into a dialog. For example, the users e-mail or social network user names.
Add the function below after forceCrash(View view){}
:
public void logUser(String userIdentifier, String userEmail, String userName) {
// TODO: Use the current user's information
// You can call any combination of these three methods
Crashlytics.setUserIdentifier(userIdentifier);
Crashlytics.setUserEmail(userEmail);
Crashlytics.setUserName(userName);
}
The function requires three parameters of type String
and adds them to the report sent. To get this data from a user you need a custom dialog with three input fields.
Create a custom layout called custom_dialog_layout.xml and add the following code:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/userIdentifier"
android:inputType="number"
android:hint="User Identifier:"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/userEmail"
android:hint="User Email:"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/userName"
android:hint="User Name:"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
Add the following method to MainActivity.java that creates the dialog, gets the information, performs the crash and sends the report:
public void showUserDialog(View view) {
LayoutInflater inflater = getLayoutInflater();
View alertLayout = inflater.inflate(R.layout.custom_dialog_layout, null);
userIdentifierEditText = (EditText) alertLayout.findViewById(R.id.userIdentifier);
userEmailEditText = (EditText) alertLayout.findViewById(R.id.userEmail);
userNameEditText = (EditText) alertLayout.findViewById(R.id.userName);
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Information");
alert.setView(alertLayout);
alert.setCancelable(false);
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
alert.setPositiveButton("Crash & Send", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// code for matching password
userIdentifier = userIdentifierEditText.getText().toString();
userEmail = userEmailEditText.getText().toString();
userName = userNameEditText.getText().toString();
if (!userIdentifier.equals("") && !userEmail.equals("") && !userName.equals("")) {
logUser(userIdentifier, userEmail, userName);
Toast.makeText(getBaseContext(), "Sending extra information...", Toast.LENGTH_SHORT).show();
throw new RuntimeException("This is a crash with extra information");
}
Toast.makeText(getBaseContext(), "Information not send! Please complete all fields...", Toast.LENGTH_SHORT).show();
}
});
AlertDialog dialog = alert.create();
dialog.show();
}
When the second button is clicked, the application shows a dialog that asks for input. Clicking Crash & Send checks if the strings have values, performs the crash and sends the report containing the information.
Crashlytics Dashboard
To see the crash reports, access the Crashlytics dashboard of an individual app.
Below the graph are the crashes corresponding to certain lines of code. To view more detailed information about a crash, click an item on the list.
To view more information about the user who sent the report, click *Viewing latest crash (More details…)_
Answers
Fabric also gives you the simplest tools to keep your application user metrics, events and behavior.
In order to keep the tracks of any Activity or View visited by the user, just add this code inside any method:
//New Answers data
Answers.getInstance().logContentView(new ContentViewEvent()
.putContentName("MainActivity")
.putContentType("View")
.putContentId("1234")
.putCustomAttribute("Custom Number", 20)
.putCustomAttribute("Screen Orientation", "Landscape"));
You can also create custom Answers Events by adding:
Answers.getInstance().logCustom(new CustomEvent("User registered")
.putCustomAttribute("Custom Attribute", "Sample")
.putCustomAttribute("Custom", 350));
But Answers gives more options about the application metrics with many other events like below:
Conclusion
The Crashlytics component of Fabric provides a quick method of adding crash reporting to your apps, helping you identify common problems experienced by users and improve your app.
Please let me know in the comments below if you have any questions or problems.