【问题标题】:How do I obtain crash-data from my Android application?如何从我的 Android 应用程序中获取崩溃数据?
【发布时间】:2010-10-10 17:34:33
【问题描述】:

如何从我的 Android 应用程序中获取崩溃数据(至少是堆栈跟踪)?至少在通过电缆检索我自己的设备上工作时,但最好是从我在野外运行的应用程序的任何实例中进行,以便我可以改进它并使其更加可靠。

【问题讨论】:

  • 我看到这会将报告发送到远程服务器。它也可以将异常记录到本地文件吗?
  • Android 应用程序崩溃报告code.google.com/p/acra
  • 这个看起来比较健壮,如果重试后报告上传失败,可以记录文件还是sqlite db?
  • 您尝试过 Firebase Crashlytics 吗?

标签: android crash stack-trace


【解决方案1】:

你可以试试ACRA (Application Crash Report for Android) 库:

ACRA 是一个库,可让 Android 应用程序自动将其崩溃报告发布到 GoogleDoc 表单。它面向 android 应用程序开发人员,以帮助他们在应用程序崩溃或出现错误行为时从应用程序中获取数据。

它很容易安装在您的应用中,高度可配置,并且不需要您在任何地方托管服务器脚本...报告会发送到 Google Doc 电子表格!

【讨论】:

  • 这很容易设置和使用。建议在上市前使用,甚至可能在之后使用。
  • 开始使用它,它比我之前在 Flurry 中的错误报告或我开始使用的自制的要好得多。到目前为止,我对“acra”很感兴趣。
  • acra 的一大优势是可以使用 Google API 轻松分析和可视化数据,有关如何执行此操作的示例,请参阅 jberkel.github.com/sms-backup-plus/acra-analysis
  • 对我来说似乎很不稳定。 ACRA 本身崩溃并发送了关于自身的崩溃报告,而不是相关的应用程序崩溃。 -1
  • 不再支持 Google Docs 作为后端
【解决方案2】:

出于示例应用程序和调试目的,我使用了一个简单的解决方案,该解决方案允许我将堆栈跟踪写入设备的 sd 卡和/或将其上传到服务器。这个解决方案受到 Project android-remote-stacktrace 的启发(特别是保存到设备和上传到服务器部分),我认为它解决了 Soonil 提到的问题。它不是最佳的,但它可以工作,如果你想在生产应用程序中使用它,你可以改进它。如果您决定将堆栈跟踪上传到服务器,您可以使用 php 脚本 (index.php) 来查看它们。如果您有兴趣,可以在下面找到所有源代码 - 一个用于您的应用程序的 java 类和两个用于托管已上传堆栈跟踪的服务器的可选 php 脚本。

在上下文中(例如主 Activity),调用

if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
    Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(
            "/sdcard/<desired_local_path>", "http://<desired_url>/upload.php"));
}

CustomExceptionHandler

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;

    private String localPath;

    private String url;

    /* 
     * if any of the parameters is null, the respective functionality 
     * will not be used 
     */
    public CustomExceptionHandler(String localPath, String url) {
        this.localPath = localPath;
        this.url = url;
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }

    public void uncaughtException(Thread t, Throwable e) {
        String timestamp = TimestampFormatter.getInstance().getTimestamp();
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        e.printStackTrace(printWriter);
        String stacktrace = result.toString();
        printWriter.close();
        String filename = timestamp + ".stacktrace";

        if (localPath != null) {
            writeToFile(stacktrace, filename);
        }
        if (url != null) {
            sendToServer(stacktrace, filename);
        }

        defaultUEH.uncaughtException(t, e);
    }

    private void writeToFile(String stacktrace, String filename) {
        try {
            BufferedWriter bos = new BufferedWriter(new FileWriter(
                    localPath + "/" + filename));
            bos.write(stacktrace);
            bos.flush();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

upload.php

<?php
    $filename = isset($_POST['filename']) ? $_POST['filename'] : "";
    $message = isset($_POST['stacktrace']) ? $_POST['stacktrace'] : "";
    if (!ereg('^[-a-zA-Z0-9_. ]+$', $filename) || $message == ""){
        die("This script is used to log debug data. Please send the "
                . "logging message and a filename as POST variables.");
    }
    file_put_contents($filename, $message . "\n", FILE_APPEND);
?>

index.php

<?php
    $myDirectory = opendir(".");
    while($entryName = readdir($myDirectory)) {
        $dirArray[] = $entryName;
    }
    closedir($myDirectory);
    $indexCount = count($dirArray);
    sort($dirArray);
    print("<TABLE border=1 cellpadding=5 cellspacing=0 \n");
    print("<TR><TH>Filename</TH><TH>Filetype</th><th>Filesize</TH></TR>\n");
    for($index=0; $index < $indexCount; $index++) {
        if ((substr("$dirArray[$index]", 0, 1) != ".") 
                && (strrpos("$dirArray[$index]", ".stacktrace") != false)){ 
            print("<TR><TD>");
            print("<a href=\"$dirArray[$index]\">$dirArray[$index]</a>");
            print("</TD><TD>");
            print(filetype($dirArray[$index]));
            print("</TD><TD>");
            print(filesize($dirArray[$index]));
            print("</TD></TR>\n");
        }
    }
    print("</TABLE>\n");
?>

【讨论】:

  • 我认为这会在某些州/国家引起法律问题
  • 注意:如果您的目标是 Honeycomb 或更高版本,HttpPost httpPost = new HttpPost(url); 现在必须在异步任务(或处理程序...单独的线程)中
  • @Joset,什么样的法律问题,为什么?
  • @varevarao 法律问题(可能),因为您在未经用户同意的情况下使用此代码的发送到服务器功能发送敏感设备信息。
  • defaultExceptionHandler 似乎在 Activity 重新创建中持续存在。如果尚未设置自定义处理程序,我将答案更新为仅设置默认值。没有它,每个处理程序都会持有并调用前一个处理程序,一直到原始处理程序。这会导致重复记录问题以及内存泄漏问题。
【解决方案3】:

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

免责声明:我是联合创始人

【讨论】:

  • 我试过 BugSense,它很棒。简单清新的用户界面,也很快。没有愚蠢的功能膨胀。很容易看到最频繁的崩溃,也可以深入了解堆栈跟踪。
  • 我们最近所做的不仅仅是崩溃报告,但这里不适合谈论新功能等。
  • 试过了。尽管堆栈跟踪不太完整,但错误仍然有效,实时崩溃数据没有通过。调试模式不起作用。不过,我从 Application 类中走下初始化一次的路线(这对大多数情况来说是有意义的)。 BugSense 有一个令人惊叹的仪表板,令人遗憾的是,由于某种原因崩溃报告不起作用并且符号不在免费层中。我花了 5 分钟来安装 GetSentry,它使用这个通用客户端在 Android 上开箱即用:github.com/joshdholtz/Sentry-Android
  • BugSense 简单且易于集成。但它太贵了。我们可以使用 Flurry 分析和 Parse 实现相同的错误感知功能。它们都是免费且易于集成的。
【解决方案4】:

在 Android 2.2 中,现在可以从 Android Market 应用程序自动获取崩溃报告:

Android 的新错误报告功能 市场应用程序使开发人员能够 接收来自的崩溃和冻结报告 他们的用户。报告将 当他们登录到他们的 发布商帐户。

http://developer.android.com/sdk/android-2.2-highlights.html

【讨论】:

  • 我认为它不仅仅是 2.2,而只是 google 提供的一个新的市场功能。几天前我收到了一份崩溃报告,不应该有使用我的应用程序的 froyo 设备。
  • @Janusz 你确定吗? Nexus One 已经发布了 Froyo,这还不包括运行 Froyo 一段时间的 Google 员工。
  • 至少手机上的版本肯定有更新,哪怕只是另一个版本,但不然怎么办?
  • 我不知道报告之前是否已发送给谷歌。该报告有些奇怪,因为谷歌显示了一个用于发送视频的 UI,这必须是操作系统的变化,而不仅仅是市场。但它说:平台 1 每周报告报告,机器人不应该在 froyo 上。
  • “报告”按钮代码在 AOSP 中已有一段时间了,几个月前,Romain Guy(含糊地)在这里回答了一个关于它的问题。
【解决方案5】:

可以使用Thread.setDefaultUncaughtExceptionHandler() 处理这些异常,但这似乎与 Android 处理异常的方法有冲突。我尝试使用这种性质的处理程序:

private class ExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread thread, Throwable ex){
        Log.e(Constants.TAG, "uncaught_exception_handler: uncaught exception in thread " + thread.getName(), ex);

        //hack to rethrow unchecked exceptions
        if(ex instanceof RuntimeException)
            throw (RuntimeException)ex;
        if(ex instanceof Error)
            throw (Error)ex;

        //this should really never happen
        Log.e(Constants.TAG, "uncaught_exception handler: unable to rethrow checked exception");
    }
}

但是,即使重新抛出异常,我也无法获得所需的行为,即记录异常同时仍然允许 Android 关闭它发生的组件,所以我在一段时间后放弃了它。

【讨论】:

  • 为什么只重新抛出未经检查的异常?在我看来,您应该重新抛出所有异常。
  • 看起来有人用你的方法成功了:jyro.blogspot.com/2009/09/crash-report-for-android-app.html
  • 诀窍是获取上一个默认的 UncaughtExceptionHandler 并在完成报告异常后处理该对象的异常。
  • Constants.TAG 是 Android 框架的一部分吗?第一次见。好像没找到。
  • @HarounHajem 我们需要自己定义。
【解决方案6】:

我看到这个问题太老了,希望我的回答对其他有同样问题的人有所帮助......

试试Crashlytics。它将深入了解拥有您的应用程序的所有设备上的所有崩溃情况,并通过电子邮件向您发送通知。最好的部分是它完全免费使用..

【讨论】:

    【解决方案7】:

    好的,我查看了 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的代码进行了修改 您有一个良好的工作基础,可以将现场登录到您的网络服务器或 sd卡。

    【讨论】:

      【解决方案8】:

      Google Play 开发者控制台实际上为您提供了来自那些已崩溃并已发送报告的应用程序的堆栈跟踪,它还有一个非常好的图表可以帮助您查看信息,请参见下面的示例:

      【讨论】:

      • 如果您的应用不在 Play 商店中,您是如何让用户发送报告的,或者它是如何工作的,您可以出于测试目的这样做吗?
      • 你知道有没有开源的 Android 项目公开他们的崩溃报告?
      • 请注意,这只会显示用户选择报告的崩溃、ANR
      • 确实如此,无论如何,当您拥有庞大的用户群时,您有很多可能报告所有崩溃,而且此处报告的崩溃和 ANR 将是最重要的,因为人们会报告它们更多次,这样您就可以按优先级过滤和修复它们(更多报告 = 更重要的错误)同时(没有报告 = 不是那个严重的错误)。
      【解决方案9】:

      我一直在为我的 Android 和 iOS 应用程序使用 Crittercism - 在 techcrunch 上听说过它们。到目前为止对他们很满意!

      【讨论】:

      • 仅供参考:来自 NDK 方面的崩溃报告不是基本计划的一部分,属于“扩展崩溃报告”。见:crittercism.com/pricing
      • 我刚刚在 Twitter 的 Fabric.io Crashlytics 上测试了 NDK 报告......非常棒(在使用的第一天),当我发布将映射放入他们的系统时,它需要一个额外的步骤,所以堆栈跟踪看起来不错,但它确定了我用来测试的 NDK 错误(在整个 c++ 中战略性地调用了“abort();”,它提供了一个堆栈跟踪用于测试。
      【解决方案10】:

      我在这里制作了自己的版本: http://androidblogger.blogspot.com/2009/12/how-to-improve-your-application-crash.html

      基本上是一样的,但是我使用邮件而不是 http 连接来发送报告,更重要的是,我添加了一些信息,例如应用程序版本、操作系统版本、手机型号或可用内存到我的报告...

      【讨论】:

        【解决方案11】:

        使用它来捕获异常详细信息:

        String stackTrace = Log.getStackTraceString(exception); 
        

        将其存储在数据库中并维护日志。

        【讨论】:

        • 如何访问那个数据库,你能给我举个例子吗?如果可以,请。谢谢你的建议
        【解决方案12】:

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

        它有一个简单的 .jar 库(适用于 Android),您可以在 5 分钟内添加并集成该库,然后该库不仅会收集崩溃信息,还会收集正在运行的应用程序的日志,并让您的测试人员直接从设备报告问题- 包括整个上下文(设备旋转,是否连接到 wifi 等等)。您可以使用一个非常漂亮且有用的 Web 面板查看日志,您可以在其中跟踪与您的应用程序的会话、崩溃、日志、统计信息等。 该服务目前处于封闭 Beta 测试阶段,但您可以申请访问权限,我们会很快将其提供给您。

        免责声明:我是 Polidea 的 CTO,也是该服务的共同创建者。

        【讨论】:

          【解决方案13】:

          现在,Firebase 崩溃报告非常流行且更易于使用。 请参阅以下链接以获取更多信息: Firebase Crash Reporting

          希望对你有帮助。

          【讨论】:

            【解决方案14】:

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

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

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

            所需步骤:

            1st) 在您的活动的 onCreate 中使用您的代码的这一部分。

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

            2nd) 根据我的 phpscript,使用 (rrainn) 的 CustomExceptionHandler 类的这个覆盖版本。

            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();
            
                }
            }
            

            【讨论】:

              【解决方案15】:

              Google Firebase 是 Google 最新(2016 年)为您提供手机崩溃/错误数据的方式。 将其包含在您的 build.gradle 文件中:

              compile 'com.google.firebase:firebase-crash:9.0.0'
              

              致命崩溃会自动记录,无需用户输入,您还可以记录非致命崩溃或其他类似事件:

              try
              {
              
              }
              catch(Exception ex)
              {
                  FirebaseCrash.report(new Exception(ex.toString()));
              }
              

              【讨论】:

                【解决方案16】:

                有一个名为Sherlock 的android 库。它为您提供完整的崩溃报告以及设备和应用程序信息。 每当发生崩溃时,它会在通知栏中显示一条通知,单击通知时,它会打开崩溃详细信息。您还可以通过电子邮件或其他共享选项与他人共享崩溃详细信息。

                安装

                android {
                    dataBinding {
                      enabled = true
                    }
                }
                
                compile('com.github.ajitsing:sherlock:1.0.0@aar') {
                    transitive = true
                }
                

                演示

                【讨论】:

                  【解决方案17】:

                  这很粗暴,但是可以在任何地方运行 logcat,所以一个快速而肮脏的 hack 是添加到任何 catch 块 getRuntime().exec("logcat &gt;&gt; /sdcard/logcat.log");

                  【讨论】:

                  • 这将给出所有应用程序的日志输出。按应用标记名过滤可能没问题,但不要认为这将是一个好方法,因为条目可能是累积的。不过,在每次写入后清除 logcat 输出可能会解决该问题。
                  【解决方案18】:

                  有一个名为fabric的工具,这是一个崩溃分析工具,它可以让您在应用程序实时部署和开发期间获得崩溃报告。 将此工具添加到您的应用程序也很简单。 当您的应用程序崩溃时,可以从您的 fabric.io 仪表板查看崩溃报告。 thw 报告被自动捕获。它不会请求用户许可。他/她是否要发送错误/崩溃报告。 这是完全免费的... https://get.fabric.io/

                  【讨论】:

                    【解决方案19】:

                    虽然此页面上的许多答案都很有用,但它们很容易过时。 AppBrain 网站汇总了统计数据,可让您找到当前最流行的崩溃报告解决方案:

                    Android crash reporting libraries

                    您可以看到,在发布这张图片时,5.24% 的应用和 12.38% 的安装使用了 Crashlytics。

                    【讨论】:

                      【解决方案20】:

                      我们在公司内部使用我们自己开发的系统,它为我们提供了很好的服务。这是一个将崩溃报告发送到服务器和接收报告并进行一些分析的服务器的 android 库。服务器按异常名称、堆栈跟踪、消息对异常进行分组。它有助于识别需要修复的最关键问题。 我们的服务现在处于公开测试阶段,因此每个人都可以尝试。您可以在http://watchcat.co 创建帐户,或者您可以使用演示访问http://watchcat.co/reports/index.php?demo 看看它是如何工作的。

                      【讨论】:

                        【解决方案21】:

                        如果您想立即得到答案,可以使用logcat

                        $adb shell logcat -f /sdcard/logoutput.txt *:E

                        如果您的日志中现在有太多垃圾,请先尝试清除它。

                        $adb shell logcat -c

                        然后尝试运行您的应用程序,然后再次运行 logcat。

                        【讨论】:

                        • 这是否仍然需要您将设备连接到 PC(例如使用电缆)?
                        【解决方案22】:

                        我发现了另一个很棒的网络应用程序来跟踪错误报告。

                        https://mint.splunk.com/

                        配置步骤少。

                        1. 使用以上链接登录或注册并进行配置。完成创建应用程序后,他们将提供一行进行配置,如下所示。
                        Mint.initAndStartSession(YourActivity.this, "api_key");
                        
                        1. 在应用程序的 build.gradl 中添加以下内容。
                        android {
                        ...
                            repositories {
                                maven { url "https://mint.splunk.com/gradle/"}
                            }
                        ...
                        }
                        
                        dependencies {
                        ...
                            compile "com.splunk.mint:mint:4.4.0"
                        ...
                        }
                        
                        1. 添加我们上面复制的代码并将其添加到每个活动中。

                          Mint.initAndStartSession(YourActivity.this, "api_key");

                        就是这样。您登录并转到您的应用程序仪表板,您将获得所有错误报告。

                        希望对某人有所帮助。

                        【讨论】:

                        • 这个要多少钱?
                        【解决方案23】:

                        有关备用崩溃报告/异常跟踪服务,请查看 Raygun.io - 它有很多很好的逻辑来处理 Android 崩溃,包括将其插入应用时的良好用户体验(主 Activity 中的两行代码并将几行 XML 粘贴到 AndroidManifest 中)。

                        当您的应用崩溃时,它会自动获取堆栈跟踪、硬件/软件的环境数据、用户跟踪信息、您指定的任何自定义数据等。它会将其异步发布到 API,因此不会阻塞 UI 线程,如果没有可用的网络,则将其缓存到磁盘。

                        免责声明:我构建了 Android 提供程序 :)

                        【讨论】:

                          【解决方案24】:

                          刚开始使用 ACRA https://github.com/ACRA/acra,使用 Google 表单作为后端,设置和使用非常简单,这是默认设置。

                          但是向 Google 表单发送报告将被弃用(然后被删除): https://plus.google.com/118444843928759726538/posts/GTTgsrEQdN6 https://github.com/ACRA/acra/wiki/Notice-on-Google-Form-Spreadsheet-usage

                          无论如何,您都可以定义自己的发件人 https://github.com/ACRA/acra/wiki/AdvancedUsage#wiki-Implementing_your_own_sender 例如,您可以尝试向发件人发送电子邮件。

                          只需最少的努力,就可以将报告发送到 bugsense: http://www.bugsense.com/docs/android#acra

                          注意 bugsense 免费帐户限制为每月 500 份报告

                          【讨论】:

                            【解决方案25】:

                            晚会,我支持并相信 ACRA 是所有人中的最佳选择。它易于设置和配置。我创建了一份详细的指南,其中包含来自各地的输入,以使用 ACRA 获取崩溃报告,并使用 MandrillAp 将其邮寄到我的电子邮件地址。

                            发帖链接:https://androidician.wordpress.com/2015/03/29/sending-crash-reports-with-acra-over-email-using-mandrill/

                            github上的示例项目链接:https://github.com/ayushhgoyal/AcraSample

                            【讨论】:

                              【解决方案26】:

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

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

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

                              如果您想了解有关 Android 上的崩溃处理/报告的一些最佳实践,您可以查看 Bugsnag 的 crash reporting library 的完整源代码,它是完全开源的,您可以随意将其拆开并在您自己的应用程序中使用!

                              【讨论】:

                                【解决方案27】:

                                Google 更改了您实际收到的崩溃报告的数量。以前您只能收到手动报告的错误报告。

                                自从上次开发者大会和 Android Vitals 的介绍以来,您还收到了来自已启用共享诊断数据的用户的崩溃报告。

                                您会看到从用户已选择自动共享使用情况和诊断数据的 Android 设备收集的所有崩溃信息。可获取前两个月的数据。

                                View crashes & application not responding (ANR) errors

                                【讨论】:

                                • logcat 说 /data/user/0/com./cache/WebView/Crash Report/.dmp 中有一个输出故障转储文件,但设备不是t 植根,我不知道如何访问这个文件!
                                【解决方案28】:

                                如果您的应用正在被其他人下载并在远程设备上崩溃,您可能需要查看 Android 错误报告库(在 this SO post 中引用)。如果它只是在您自己的本地设备上,您可以使用 LogCat。即使设备在崩溃发生时没有连接到主机,连接设备并发出 adb logcat 命令将下载整个 logcat 历史记录(至少在它被缓冲的范围内,这通常是大量的日志数据,它只是不是无限的)。这些选项中的任何一个都回答了您的问题吗?如果不是,您可以尝试澄清一下您在寻找什么吗?

                                【讨论】:

                                  【解决方案29】:

                                  Flurry analytics 为您提供崩溃信息、硬件型号、Android 版本和实时应用使用统计信息。在新的 SDK 中,他们似乎提供了更详细的崩溃信息http://www.flurry.com/flurry-crash-analytics.html

                                  【讨论】:

                                  • Flurry 仅限于这么多字符,并且不会为您提供行号或类似内容。
                                  【解决方案30】:

                                  您可以直接在 Android Studio 中执行此操作。只需连接您的手机,运行应用程序,让它崩溃,您就可以直接在 Android Studio 中查看堆栈跟踪。

                                  【讨论】:

                                    猜你喜欢
                                    • 2015-09-27
                                    • 1970-01-01
                                    • 2011-04-09
                                    • 1970-01-01
                                    • 2014-12-30
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多