Tuesday, February 24, 2015

Android Obtain Crash Data of Application Remotely

Recently in one my project we distributed APKs to some people to test applications and we got a complain that APP is crashing. While on our side app was not crashing and it was working fine. We were not sure what could be possible reason of crash.  As they were running app from APK we sent in mail so there is no way they can report to Play Store. So we added our own solution to get stack trace on server from the app. In this blog I am going o explain how to do this.

First we added custom exception handler class. Here is that class. 

package com.myapp.app;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.util.Log;

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;
    private String url;
    public CustomExceptionHandler(String url) {
        this.url = url;
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }

    public void uncaughtException(Thread t, Throwable e) {
        Calendar c = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timestamp = df.format(c.getTime());
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        String stacktrace = result.toString();
        printWriter.close();
        String time = timestamp + ".stacktrace";
        if (url != null) {
            sendToServer(stacktrace, time);
        }

        defaultUEH.uncaughtException(t, e);
    }

    private void sendToServer(String stacktrace, String time) {
        Log.v("stacktrace","stacktrace");
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        List nvps = new ArrayList();
        nvps.add(new BasicNameValuePair("time", time));
        nvps.add(new BasicNameValuePair("stacktrace", stacktrace));
        try {
            httpPost.setEntity(
                    new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
            httpClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

As you can see in above class we have added Class with name CustomExceptionHandler which implements UncaughtExceptionHandler. The constructor is expecting server URL. This is your custom server URL where you want to log stack trace. As you can see in above code we have uncaughtException function which is logging stack trace to server by calling function sendToServer with HTTP POST request. Now We have to add this class as exception handler. This you can do in onCreate of your activity.

Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(
     null, "http://yourloggingurl));

As you can see in above code we are setting default exception handler for thread and passing the URL, you have to replace your own URL instead of yourloggingurl. That's it and your app will send complete stack trace on crash to server. Here is the PHP code on server to get data and write a file if you need.

<?php
    $time = $_POST['time'];
    $stacktrace = $_POST['stacktrace'] ;
    file_put_contents($filename, $stacktrace . "\n", FILE_APPEND);
?>

As yo can see in above codes you are getting stack trace and writing to a file. Make sure you have write permission on directory.


No comments:

Post a Comment