如何从我的Android应用程序中获得崩溃数据(至少堆栈跟踪)?至少在我自己的设备上工作时可以通过电缆检索,但理想的情况是,从我的应用程序在野外运行的任何实例中都可以,这样我就可以改进它,使它更可靠。


当前回答

我是Bugsnag的创始人之一,我们正是为此目的而设计的。Bugsnag自动捕获Android应用程序中未处理的异常,并将它们发送到我们的仪表板,在那里您可以优先修复并深入诊断信息。

以下是在选择或构建崩溃报告系统时需要考虑的一些重要事项,以及一些代码片段:

自动检测未处理的异常(示例代码) 收集诊断数据,如内存使用情况、设备信息等(示例代码) 根据根本原因有效地将崩溃组合在一起 允许您跟踪用户在每次崩溃前采取的操作,以帮助重现(示例代码)

如果你想在Android上看到一些关于崩溃处理/报告的最佳实践,你可以查看Bugsnag的崩溃报告库的完整源代码,它是完全开源的,可以自由地把它拆开,并在你自己的应用程序中使用!

其他回答

您也可以尝试[BugSense]原因:垃圾邮件重定向到另一个url。BugSense收集并分析所有崩溃报告,并为您提供有意义的可视化报告。它是免费的,而且只需要一行代码就可以进行集成。

声明:我是联合创始人

谷歌Play开发者控制台实际上为你提供了那些已经崩溃和发送报告的应用程序的堆栈跟踪,它也有一个非常好的图表来帮助你查看信息,参见下面的例子:

您还可以为它使用整个(简单的)服务,而不仅仅是库。我们公司刚刚为此发布了一项服务:http://apphance.com。

It has a simple .jar library (for Android) that you add and integrate in 5 minutes and then the library gathers not only crash information but also logs from running application, as well as it lets your testers report problems straight from device - including the whole context (device rotation, whether it is connected to a wifi or not and more). You can look at the logs using a very nice and useful web panel, where you can track sessions with your application, crashes, logs, statistics and more. The service is in closed beta test phase now, but you can request access and we give it to you very quickly.

声明:我是Polidea的CTO,也是这项服务的共同创建者。

感谢资源在Stackoverflow中帮助我找到这个答案。

你可以直接在电子邮件中找到远程Android崩溃报告。记住你必须把你的电子邮件放在CustomExceptionHandler类中。

public static String sendErrorLogsTo = "tushar.pandey@virtualxcellence.com" ;

步骤:

1)在onCreate你的活动使用这段代码。

    if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
        Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
    }   

第二)使用(rrainn)的CustomExceptionHandler类的重写版本,根据我的phpscript。

package com.vxmobilecomm.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
import android.util.Log;

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;
    public static String sendErrorLogsTo = "tushar.pandey@virtualxcellence.com" ;

    Activity activity;

    public CustomExceptionHandler(Activity activity) {
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
        this.activity = activity;
    }

    public void uncaughtException(Thread t, Throwable e) {

        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        e.printStackTrace(printWriter);
        String stacktrace = result.toString();
        printWriter.close();
        String filename = "error" + System.nanoTime() + ".stacktrace";

        Log.e("Hi", "url != null");
        sendToServer(stacktrace, filename);

        StackTraceElement[] arr = e.getStackTrace();
        String report = e.toString() + "\n\n";
        report += "--------- Stack trace ---------\n\n";
        for (int i = 0; i < arr.length; i++) {
            report += "    " + arr[i].toString() + "\n";
        }
        report += "-------------------------------\n\n";

        report += "--------- Cause ---------\n\n";
        Throwable cause = e.getCause();
        if (cause != null) {
            report += cause.toString() + "\n\n";
            arr = cause.getStackTrace();
            for (int i = 0; i < arr.length; i++) {
                report += "    " + arr[i].toString() + "\n";
            }
        }
        report += "-------------------------------\n\n";

        defaultUEH.uncaughtException(t, e);
    }

    private void sendToServer(String stacktrace, String filename) {
        AsyncTaskClass async = new AsyncTaskClass(stacktrace, filename,
                getAppLable(activity));
        async.execute("");
    }

    public String getAppLable(Context pContext) {
        PackageManager lPackageManager = pContext.getPackageManager();
        ApplicationInfo lApplicationInfo = null;
        try {
            lApplicationInfo = lPackageManager.getApplicationInfo(
                    pContext.getApplicationInfo().packageName, 0);
        } catch (final NameNotFoundException e) {
        }
        return (String) (lApplicationInfo != null ? lPackageManager
                .getApplicationLabel(lApplicationInfo) : "Unknown");
    }

    public class AsyncTaskClass extends AsyncTask<String, String, InputStream> {
        InputStream is = null;
        String stacktrace;
        final String filename;
        String applicationName;

        AsyncTaskClass(final String stacktrace, final String filename,
                String applicationName) {
            this.applicationName = applicationName;
            this.stacktrace = stacktrace;
            this.filename = filename;
        }

        @Override
        protected InputStream doInBackground(String... params) 
        { 
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(
                    "http://suo-yang.com/books/sendErrorLog/sendErrorLogs.php?");

            Log.i("Error", stacktrace);

            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
                        6);

                nameValuePairs.add(new BasicNameValuePair("data", stacktrace));
                nameValuePairs.add(new BasicNameValuePair("to",sendErrorLogsTo));
                nameValuePairs.add(new BasicNameValuePair("subject",applicationName));

                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

                HttpResponse response = httpclient.execute(httppost);

                HttpEntity entity1 = response.getEntity();

                BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(
                        entity1);

                is = bufHttpEntity.getContent();

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return is;
        }

        @Override
        protected void onPostExecute(InputStream result) {
            super.onPostExecute(result);

            Log.e("Stream Data", getStringFromInputStream(is));
        }
    }

    // convert InputStream to String
    private static String getStringFromInputStream(InputStream is) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();

    }
}

好吧,我看了rrainn和Soonil提供的样本,我找到了一个解决方案 这不会破坏错误处理。

我修改了CustomExceptionHandler,以便它从我们关联的新线程中存储原始的UncaughtExceptionHandler。在新的“uncaughtException”的末尾- 方法,我只是使用存储的UncaughtExceptionHandler调用旧函数。

在DefaultExceptionHandler类中,你需要这样的东西:

public class DefaultExceptionHandler implements UncaughtExceptionHandler{
  private UncaughtExceptionHandler mDefaultExceptionHandler;

  //constructor
  public DefaultExceptionHandler(UncaughtExceptionHandler pDefaultExceptionHandler)
  {
       mDefaultExceptionHandler= pDefaultExceptionHandler;
  }
  public void uncaughtException(Thread t, Throwable e) {       
        //do some action like writing to file or upload somewhere         

        //call original handler  
        mStandardEH.uncaughtException(t, e);        

        // cleanup, don't know if really required
        t.getThreadGroup().destroy();
  }
}

在http://code.google.com/p/android-remote-stacktrace上对代码进行了修改 你有一个很好的工作基地,登录到你的web服务器或 sd卡。