android - 我的應用程式更新 - 更新google play服務




如何從我的Android應用程序獲取崩潰數據? (20)

我如何從我的Android應用程序獲取崩潰數據(至少是堆棧跟踪)? 至少在通過電纜檢索我自己的設備時,理想情況下是在我的應用程序的任何實例上運行,這樣我可以改進它並使其更加穩定。


Google Play開發者控制台實際上為您提供了已崩潰並已發送報告的應用的堆棧跟踪,它還有一個非常好的圖表可幫助您查看信息,請參閱下面的示例:



使用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關閉發生它的組件的情況下記錄異常,因此我在一段時間後放棄了它。


剛開始使用ACRA https://github.com/ACRA/acra時,使用Google表單作為後端,並且非常容易設置和使用,這是默認設置。

但將報告發送到Google表單將被棄用(然後刪除): https://plus.google.com/118444843928759726538/posts/GTTgsrEQdN6 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 : http://www.bugsense.com/docs/android#acra

NB Bugsense免費賬戶限於每月500份報告


在晚會之後,我支持並相信ACRA是所有人中最好的選擇。 它易於安裝和配置。 我已經創建了一份詳細指南,包含來自各地的輸入信息以使用ACRA獲取崩潰報告,並使用MandrillAp將其郵寄到我的電子郵件地址。

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

鏈接到github上的示例項目: https://github.com/ayushhgoyal/AcraSamplehttps://github.com/ayushhgoyal/AcraSample


好吧,我查看了rrainn和Soonil提供的樣本,並找到了一個不會影響錯誤處理的解決方案。

我修改了CustomExceptionHandler,以便它將原來的UncaughtExceptionHandler從我們關聯新線程的Thread中存儲起來。 在新的“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卡。


如果您的應用正在被其他人下載並在遠程設備上崩潰,則可能需要查看Android錯誤報告庫(在此SO帖子中引用)。 如果它只在您自己的本地設備上,則可以使用LogCat。 即使設備在發生崩潰時未連接到主機,連接設備並發出adb logcat命令也會下載整個logcat歷史記錄(至少在緩衝區中通常是日誌數據的一部分) ,它只是不是無限的)。 這些選項中的任何一個都能回答你的問題? 如果不是,你是否可以試圖澄清你在尋找什麼?


對於備用的崩潰報告/異常跟踪服務,請查看Raygun.io - 它有很多用於處理Android崩潰的良好邏輯,包括將其插入到應用程序時體面的用戶體驗(主要Activity中的兩行代碼以及一些粘貼到AndroidManifest中的XML行)。

當你的應用程序崩潰時,它會自動獲取堆棧跟踪,硬/軟件的環境數據,用戶跟踪信息,你指定的任何自定義數據等。它將它異步發佈到API,所以不會阻塞UI線程並將其緩存如果沒有網絡可用,請將其存儲到磁盤。

免責聲明:我建立了Android提供商:)


您也可以嘗試BugSense 。 BugSense收集和分析所有崩潰報告,並為您提供有意義的可視化報告。 它是免費的,它只有1行代碼才能集成。

免責聲明:我是聯合創始人


您可以嘗試ACRA(Android應用程序崩潰報告)庫:

ACRA是一個使Android應用程序能夠將其崩潰報告自動發佈到GoogleDoc表單的庫。 它的目標是android應用程序開發人員幫助他們在應用程序崩潰或行為錯誤時從其獲取數據。

它很容易安裝在您的應用中,可高度配置,並且不需要您在任何地方託管服務器腳本......報告發送到Google Doc電子表格!


感謝中的資源,幫助我找到答案。

您可以直接在您的電子郵件中找到遠程Android崩潰報告 。 注意你必須把你的電子郵件放入CustomExceptionHandler類中

public static String sendErrorLogsTo = "[email protected]" ;

所需步驟:

1)在你的活動的onCreate使用你的代碼的這一部分。

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

根據我的phpscript,使用這個被覆蓋的版本的CustomExceptionHandler類(rrainn)。

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 = "[email protected]" ;

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

    }
}

我一直在為我的Android和iOS應用使用Crittercism - 在techcrunch上聽說過他們。 到目前為止他們非常開心!



我是我們為此設計的Bugsnag的創始人之一。 Bugsnag會自動捕獲Android應用程序中未處理的異常,並將它們發送到我們的儀表板,您可以在其中優先考慮修補程序並深入診斷信息。

以下是選擇或構建崩潰報告系統時需要考慮的一些重要事項以及一些代碼片段:

  • 自動檢測未處理的異常( 示例代碼
  • 收集診斷數據,如內存使用情況,設備信息等( 示例代碼
  • 根本原因有效地將碰撞組合在一起
  • 允許您跟踪用戶在每次崩潰前採取的操作以幫助重現( 示例代碼

如果您想查看關於Android上崩潰處理/報告的一些最佳實踐,您可以查看Bugsnag完全開源的崩潰報告庫的完整源代碼,隨時將其分開並在您自己的應用程序中使用它!


我發現問題太老了,希望我的回答對於有同樣問題的其他人有幫助。

Crashlytics一個嘗試。 它將深入了解所有設備上的所有崩潰情況,並通過電子郵件向您發送通知。最好的部分是它的完全免費使用..


有一個名為Fabric的工具,這是一個崩潰分析工具,它可以讓您在應用程序部署時和開發過程中獲得崩潰報告。 將此工具添加到您的應用程序也很簡單。當您的應用程序崩潰時,可以從fabric.io儀表板查看該崩潰的報告。 這個報告被自動捕獲,它不會要求用戶許可。 無論他/她想發送錯誤/崩潰報告。 這是完全免費的... https://get.fabric.io/


現在,一天的Firebase崩潰報告非常流行且更易於使用。 請參閱以下鏈接了解更多信息: Firebase崩潰報告

希望它能幫助你。


用它來捕獲異常詳細信息:

String stackTrace = Log.getStackTraceString(exception); 

將其存儲在數據庫中並維護日誌。


這非常殘忍,但可以在任何地方運行logcat,因此快速而骯髒的攻擊是添加到任何catch塊getRuntime().exec("logcat >> /sdcard/logcat.log");


雖然此頁面上的許多答案都很有用,但它們很容易過時。 AppBrain網站匯總的統計數據可以讓您找到當前最流行的崩潰報告解決方案:

Android崩潰報告庫

您可以看到,在張貼這張照片時,Crashlytics在5.24%的應用和12.38%的安裝中使用。





stack-trace