使用CrashHandler來獲取(收集)應用的crash資訊
阿新 • • 發佈:2019-02-03
import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Environment; import android.util.Log; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Created by zb.yang on 2017/12/22. */ public class ZbCrashHandler implements Thread.UncaughtExceptionHandler { private static final String TAG = "ZbCrashHandler"; private static final String PATH = Environment.getExternalStorageDirectory().getPath()+"/CrashHandler/log"; private static final String FILE_NAME = "crash"; private static final String FILE_NAME_SUFFIX = ".trace"; //系統預設的UncaughtException處理類 private Thread.UncaughtExceptionHandler mDefaultHandler; //CrashHandler例項 private static ZbCrashHandler INSTANCE; //程式的Context物件 private Context mContext; //用來儲存裝置資訊和異常資訊 private Map<String, String> infos = new HashMap<String, String>(); private ZbCrashHandler(){ } /** * 通過靜態類返回單例 */ private static class SingletonHolder { private static final ZbCrashHandler INSTANCE = new ZbCrashHandler(); } public static ZbCrashHandler getINSTANCE(){ return SingletonHolder.INSTANCE; } /** * 初始化 */ public void init(Context context){ mContext = context; //獲取系統預設的UncaughtException處理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); //設定該CrashHandler為程式的預設處理器 Thread.setDefaultUncaughtExceptionHandler(this); } /** * 當UncaughtException發生時會轉入該函式來處理 */ @Override public void uncaughtException(Thread t, Throwable e) { if (!handleException(e) && mDefaultHandler != null) { //如果使用者沒有處理則讓系統預設的異常處理器來處理 mDefaultHandler.uncaughtException(t, e); } else { try { Thread.sleep(3000); } catch (InterruptedException ie) { LogUtils.e(ie.toString()); } //退出程式 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } /** * 自定義錯誤處理,收集錯誤資訊 傳送錯誤報告等操作均在此完成. * * @param ex * @return true:如果處理了該異常資訊;否則返回false. */ private boolean handleException(Throwable ex) { if (ex == null) { return false; } //收集裝置引數資訊 collectDeviceInfo(mContext); //儲存日誌檔案 saveCrashInfo2File(ex); return true; } /** * 收集裝置引數資訊 * * @param ctx */ private void collectDeviceInfo(Context ctx) { try { PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; infos.put("versionName", versionName); infos.put("versionCode", versionCode); } } catch (PackageManager.NameNotFoundException e) { LogUtils.e(TAG,"CrashHandleran.NameNotFoundException---> error occured when collect package info"); } //收集裝置型號資訊 Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); } catch (Exception e) { LogUtils.e(TAG,"CrashHandler.NameNotFoundException---> an error occured when collect crash info"); } } } /** * 儲存錯誤資訊到檔案中 * * @param ex * @return 返回檔名稱, 便於將檔案傳送到伺服器 */ private String saveCrashInfo2File(Throwable ex) { if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { Log.e(TAG,"sdcard unmounted, skip saveCrashInfo2File"); } //呼叫這個方法之前在6.0之後需要動態許可權請求 File dir = new File(PATH); if(!dir.exists()){ dir.mkdirs(); } long current = System.currentTimeMillis(); String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current)); String file_name = PATH+FILE_NAME+time+FILE_NAME_SUFFIX; File file = new File(file_name); try{ PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); pw.println(time); StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : infos.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\n"); } pw.println(sb.toString()); pw.println(); ex.printStackTrace(pw); Throwable cause = ex.getCause(); while (cause != null) { cause.printStackTrace(pw); cause = cause.getCause(); } }catch (Exception e){ Log.e(TAG,"save crash info into file failed"); } return file_name; } public void uploadExceptionToServer(){ // TODO upload Ecxeption Message to Your Web server; } }