如何从Android应用程序获取崩溃数据(至少是堆栈跟踪)?至少在使用电缆检索我自己的设备上工作时,但理想情况下,该应用程序可以在野外运行的任何应用程序实例中运行,以便我可以对其进行改进并使其更牢固。
如何从Android应用程序获取崩溃数据(至少是堆栈跟踪)?至少在使用电缆检索我自己的设备上工作时,但理想情况下,该应用程序可以在野外运行的任何应用程序实例中运行,以便我可以对其进行改进并使其更牢固。
Answers:
您可以尝试ACRA(Android应用程序崩溃报告)库:
ACRA是一个使Android应用程序能够将其崩溃报告自动发布到GoogleDoc表单的库。它面向android应用程序开发人员,以帮助他们在崩溃或行为异常时从其应用程序获取数据。
它易于安装在您的应用程序中,可高度配置,并且不需要您在任何地方托管服务器脚本...报告将发送到Google Doc电子表格!
出于示例应用程序和调试目的,我使用一个简单的解决方案,该解决方案使我可以将stacktrace写入设备的sd卡和/或将其上传到服务器。该解决方案的灵感来自Project android-remote-stacktrace(特别是保存到设备和上载到服务器的部件),我认为它解决了Soonil提到的问题。它不是最佳选择,但是它可以工作,如果您想在生产应用程序中使用它,则可以对其进行改进。如果决定将堆栈跟踪上载到服务器,则可以使用php脚本(index.php
)查看它们。如果您有兴趣,可以在下面找到所有源代码-一个Java类用于您的应用程序,两个可选php脚本,用于托管上传的stacktrace的服务器。
在上下文(例如主活动)中,调用
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");
?>
HttpPost httpPost = new HttpPost(url);
如果要定位蜂窝或更高版本,则现在必须处于异步任务(或处理程序...单独的线程)中
您也可以尝试[BugSense] 原因:垃圾邮件重定向到另一个URL。BugSense收集并分析了所有崩溃报告,并为您提供有意义的可视化报告。它是免费的,并且只有1行代码可以集成。
免责声明:我是联合创始人
在Android 2.2中,现在可以自动从Android Market应用程序获取崩溃报告:
Android Market应用程序的新错误报告功能使开发人员能够接收崩溃并冻结其用户的报告。当他们登录其发布者帐户时,这些报告将可用。
http://developer.android.com/sdk/android-2.2-highlights.html
可以使用来处理这些异常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关闭发生了该事件的组件,因此一段时间后我放弃了。
Constants.TAG
Android框架的一部分吗?第一次看到它。似乎找不到它。
我发现这个问题太旧了,希望我的回答对其他有同样问题的人有所帮助...
给Crashlytics一试。它将深入了解具有应用程序的所有设备上的所有崩溃,并通过电子邮件向您发送通知。而最好的部分是它完全免费使用。
好的,我查看了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卡。
Google Play开发者控制台实际上为您提供了已崩溃并发送报告的那些应用程序的堆栈跟踪,它还具有非常好的图表来帮助您查看信息,请参见以下示例:
我一直在为Android和iOS应用程序使用Crittercism-在techcrunch上听说过它们。到目前为止对他们还很满意!
我在这里制作了自己的版本:http : //androidblogger.blogspot.com/2009/12/how-to-improve-your-application-crash.html
这基本上是同一件事,但是我使用的是邮件而不是http连接来发送报告,更重要的是,我在报告中添加了一些信息,例如应用程序版本,操作系统版本,电话型号或可用内存。 。
使用它来捕获异常详细信息:
String stackTrace = Log.getStackTraceString(exception);
将此存储在数据库中并维护日志。
您还可以为其使用整个(简单)服务,而不仅仅是库。我们公司刚刚为此发布了一项服务:http : //apphance.com。
它具有一个简单的.jar库(适用于Android),您可以在5分钟内添加并集成该库,然后该库不仅收集崩溃信息,还收集正在运行的应用程序的日志,还可以让测试人员直接从设备报告问题-包括整个上下文(设备旋转,无论是否连接到wifi等)。您可以使用非常漂亮且有用的Web面板查看日志,您可以在其中跟踪与应用程序的会话,崩溃,日志,统计信息等。该服务目前处于封闭Beta测试阶段,但是您可以请求访问权限,我们会很快将其提供给您。
免责声明:我是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));
}
2)根据我的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();
}
}
如今,Firebase崩溃报告非常流行并且更易于使用。请参考以下链接以获取更多信息: Firebase崩溃报告
希望对您有帮助。
这非常残酷,但是可以在任何地方运行logcat,因此要在任何catch块中添加快速而肮脏的hack。 getRuntime().exec("logcat >> /sdcard/logcat.log");
有一个称为架构的工具,这是一个崩溃分析工具,当您实时部署应用程序时以及在开发过程中,它将使您能够获取崩溃报告。将这个工具添加到您的应用程序也很简单。当您的应用程序崩溃时,可以从fabric.io仪表板查看崩溃报告。该报告被自动捕获。它不会征求用户的许可。他/她是否要发送错误/崩溃报告。这是完全免费的... https://get.fabric.io/
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()));
}
有一个名为Sherlock的 android库。它为您提供崩溃的完整报告以及设备和应用程序信息。每当发生崩溃时,它都会在通知栏中显示一个通知,并在单击该通知时会打开崩溃详细信息。您还可以通过电子邮件或其他共享选项与其他人共享崩溃详细信息。
安装
android {
dataBinding {
enabled = true
}
}
compile('com.github.ajitsing:sherlock:1.0.0@aar') {
transitive = true
}
演示版
尽管此页面上的许多答案很有用,但很容易使它们过时。AppBrain网站汇总了统计信息,可让您找到当前最受欢迎的崩溃报告解决方案:
您可以看到,在发布此图片时,Crashlytics在5.24%的应用程序和12.38%的安装程序中使用。
我们在公司内部使用我们自己的系统,它为我们提供了很好的服务。这是一个Android库,用于将崩溃报告发送到服务器以及接收报告并进行一些分析的服务器。服务器按异常名称,堆栈跟踪,消息将异常分组。它有助于确定需要解决的最关键的问题。我们的服务现在处于公开测试阶段,因此每个人都可以尝试。您可以在http://watchcat.co上创建帐户,也可以使用演示访问http://watchcat.co/reports/index.php?demo看看它的工作方式。
我找到了另一个很棒的Web应用程序来跟踪错误报告。
配置步骤少。
Mint.initAndStartSession(YourActivity.this, "api_key");
android { ... repositories { maven { url "https://mint.splunk.com/gradle/"} } ... } dependencies { ... compile "com.splunk.mint:mint:4.4.0" ... }
Mint.initAndStartSession(YourActivity.this,“ api_key”);
而已。登录并转到应用程序仪表板,您将获得所有错误报告。
希望它可以帮助某人。
有关备用崩溃报告/异常跟踪服务的信息,请查看Raygun.io-它具有许多处理Android崩溃的好方法,包括将其插入应用程序时的体面用户体验(主Activity中有两行代码,粘贴到AndroidManifest中的XML行)。
当您的应用崩溃时,它将自动获取堆栈跟踪,硬件/软件的环境数据,用户跟踪信息,您指定的任何自定义数据等。它异步地将其发布到API,因此不会阻塞UI线程,并对其进行缓存如果没有可用的网络磁盘
免责声明:我建立了Android提供程序:)
刚开始使用ACRA https://github.com/ACRA/acra(使用Google Forms作为后端),并且设置和使用起来非常容易,这是默认设置。
但不建议将报告发送到Google表单(然后删除): https : //plus.google.com/118444843928759726538/posts/GTTgsrEQdN6 https://github.com/ACRA/acra/wiki/Notice-on-Google -表单电子表格用法
无论如何,都可以定义自己的发件人 https://github.com/ACRA/acra/wiki/AdvancedUsage#wiki-Implementing_your_own_sender, 您可以尝试发送电子邮件给发件人。
只需花费很少的精力,就可以将报告发送到Bugsense:http : //www.bugsense.com/docs/android#acra
注意:无错误的免费帐户每月最多只能报告500次
晚会晚了,我支持并相信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
Flurry Analytics可为您提供崩溃信息,硬件模型,Android版本和实时应用使用情况统计信息。在新的SDK中,它们似乎提供了更详细的崩溃信息http://www.flurry.com/flurry-crash-analytics.html。
Google更改了您实际获得的崩溃报告数量。以前,您只有手动报告的错误报告。
自从上次开发者大会和Android Vitals推出以来,您还获得了允许共享诊断数据的用户崩溃报告。
您会看到从用户选择自动共享使用情况和诊断数据的Android设备收集的所有崩溃。提供前两个月的数据。