|
2 | 2 |
|
3 | 3 | import android.content.Context;
|
4 | 4 | import android.content.pm.PackageInfo;
|
5 |
| -import android.os.Looper; |
| 5 | +import android.os.Build; |
| 6 | +import android.os.Environment; |
| 7 | + |
| 8 | +import java.io.File; |
| 9 | +import java.io.FileWriter; |
| 10 | +import java.io.IOException; |
| 11 | +import java.io.PrintWriter; |
| 12 | +import java.lang.Thread.UncaughtExceptionHandler; |
6 | 13 |
|
7 | 14 | /**
|
8 | 15 | * <pre>
|
9 | 16 | * author: Blankj
|
10 | 17 | * blog : http://blankj.com
|
11 | 18 | * time : 2016/9/27
|
12 |
| - * desc : |
| 19 | + * desc : 崩溃相关工具类 |
13 | 20 | * </pre>
|
14 | 21 | */
|
15 | 22 | public class CrashUtils implements Thread.UncaughtExceptionHandler {
|
16 | 23 |
|
17 |
| - private Thread.UncaughtExceptionHandler mDefaultHandler; |
18 |
| - private static CrashUtils INSTANCE; |
19 |
| - private Context mContext; |
| 24 | + private UncaughtExceptionHandler mHandler; |
| 25 | + private String mAndroidVersion; |
| 26 | + private String mModel; |
| 27 | + private String mManufacturer; |
| 28 | + public static String sVERSION = "Unknown"; |
| 29 | + private static CrashBuilder sBuilder; |
| 30 | + private boolean isAppend; |
| 31 | + private boolean isSimple; |
20 | 32 |
|
21 | 33 | private CrashUtils() {
|
22 |
| - throw new AssertionError(); |
| 34 | + mHandler = Thread.currentThread().getUncaughtExceptionHandler(); |
| 35 | + Thread.currentThread().setUncaughtExceptionHandler(this); |
| 36 | + mAndroidVersion = Build.VERSION.RELEASE;//安卓系统版本 |
| 37 | + mModel = Build.MODEL;// 设备型号 |
| 38 | + mManufacturer = Build.MANUFACTURER;// 设备厂商 |
23 | 39 | }
|
24 | 40 |
|
25 |
| - public static CrashUtils getInstance() { |
26 |
| - if (INSTANCE == null) |
27 |
| - INSTANCE = new CrashUtils(); |
28 |
| - return INSTANCE; |
| 41 | + /** |
| 42 | + * @param isAppend 是否为日志追加模式 |
| 43 | + */ |
| 44 | + public CrashUtils setAppend(boolean isAppend) { |
| 45 | + this.isAppend = isAppend; |
| 46 | + return this; |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * @param isSimple 是否为简单的日志记录模式 |
| 51 | + */ |
| 52 | + public CrashUtils setSimple(boolean isSimple) { |
| 53 | + this.isSimple = isSimple; |
| 54 | + return this; |
29 | 55 | }
|
30 | 56 |
|
31 |
| - public void init(Context context) { // 在Application中初始化 |
32 |
| - mContext = context; |
33 | 57 |
|
34 |
| - mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器 |
35 |
| - Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器 |
| 58 | + public static CrashUtils init(Context context, String dirName) { |
| 59 | + try { |
| 60 | + PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); |
| 61 | + sVERSION = info.versionName + info.versionCode; |
| 62 | + sBuilder = CrashBuilder.build(context, dirName); |
| 63 | + } catch (Exception e) { |
| 64 | + throw new RuntimeException(e); |
| 65 | + } |
| 66 | + return new CrashUtils(); |
36 | 67 | }
|
| 68 | + |
| 69 | +// public static String formatNumber(int value) { |
| 70 | +// return new DecimalFormat("00").format(value); |
| 71 | +// } |
| 72 | +// |
| 73 | +// public static String getCurrentDate() { |
| 74 | +// Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00")); |
| 75 | +// return calendar.get(Calendar.YEAR) + "-" + formatNumber((calendar.get(Calendar.MONTH) + 1)) + "-" |
| 76 | +// + formatNumber(calendar.get(Calendar.DAY_OF_MONTH)) + " " |
| 77 | +// + formatNumber(calendar.get(Calendar.HOUR_OF_DAY)) + ":" + formatNumber(calendar.get(Calendar |
| 78 | +// .MINUTE)); |
| 79 | +// } |
| 80 | + |
37 | 81 | @Override
|
38 |
| - public void uncaughtException(Thread thread, Throwable ex) { |
39 |
| - if (!handleException(ex) && mDefaultHandler != null) { |
40 |
| - // 如果自定义的没有处理则让系统默认的异常处理器来处理 |
41 |
| - mDefaultHandler.uncaughtException(thread, ex); |
| 82 | + public void uncaughtException(Thread thread, Throwable throwable) { |
| 83 | + if (!isAppend) { |
| 84 | + FileUtils.createFileByDeleteOldFile(sBuilder.getCarsh_log()); |
| 85 | + } else { |
| 86 | + FileUtils.createOrExistsFile(sBuilder.getCarsh_log()); |
| 87 | + } |
| 88 | + File file = new File(sBuilder.getCarsh_log()); |
| 89 | + PrintWriter pw = null; |
| 90 | + try { |
| 91 | + pw = new PrintWriter(new FileWriter(file, true)); |
| 92 | + pw.write("\n*************---------Crash Log Head ------------****************\n\n"); |
| 93 | + pw.write("Happened Time: " + TimeUtils.getCurTimeString() + "\n"); |
| 94 | + pw.write("Android Version: " + mAndroidVersion + "\n"); |
| 95 | + pw.write("Device Model: " + mModel + "\n"); |
| 96 | + pw.write("Device Manufacturer: " + mManufacturer + "\n"); |
| 97 | + pw.write("App Version: v" + sVERSION + "\n\n"); |
| 98 | + pw.write("*************---------Crash Log Head ------------****************\n\n"); |
| 99 | + if (!isSimple) |
| 100 | + throwable.printStackTrace(pw); |
| 101 | + else { |
| 102 | + pw.write(throwable.getLocalizedMessage() + "\n"); |
| 103 | + } |
| 104 | + } catch (IOException e) { |
| 105 | + return; |
| 106 | + } finally { |
| 107 | + FileUtils.closeIO(pw); |
| 108 | + } |
| 109 | + FileUtils.createFileByDeleteOldFile(sBuilder.getCrash_tag()); |
| 110 | + if (mHandler != null) { |
| 111 | + mHandler.uncaughtException(thread, throwable); |
42 | 112 | }
|
43 | 113 | }
|
44 | 114 |
|
45 |
| - /** |
46 |
| - * 自定义错误处理、收集错误信息、发送错误报告 |
47 |
| - * |
48 |
| - * @param ex 异常信息 |
49 |
| - * @return true 如果处理了该异常信息;否则返回false. |
50 |
| - */ |
51 |
| - public boolean handleException(Throwable ex) { |
52 |
| - if (ex == null || mContext == null) |
53 |
| - return false; |
54 |
| - final String crashReport = getCrashReport(mContext, ex); |
55 |
| - new Thread() { |
56 |
| - public void run() { |
57 |
| - Looper.prepare(); |
58 |
| - LogUtils.e("CrashHandler", crashReport); // 打印异常信息,也可保存至文件 方便远程调试 |
59 |
| - Looper.loop(); |
| 115 | + public static class CrashBuilder { |
| 116 | + private String carsh_dir; |
| 117 | + public String getCrash_dir() { |
| 118 | + return carsh_dir; |
| 119 | + } |
| 120 | + public String getCarsh_log() { |
| 121 | + return getCrash_dir() + File.separator + "carshRecord.log"; |
| 122 | + } |
| 123 | + public String getCrash_tag() { |
| 124 | + return getCrash_dir() + File.separator + ".carshed"; |
| 125 | + } |
| 126 | + public CrashBuilder(Context context, String dirName) { |
| 127 | + if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { |
| 128 | + this.carsh_dir = context.getCacheDir().getPath() + File.separator + dirName; |
| 129 | + } else { |
| 130 | + this.carsh_dir = context.getExternalCacheDir().getPath() + File.separator + dirName; |
60 | 131 | }
|
| 132 | + } |
| 133 | + public static CrashBuilder build(Context context, String dirName) { |
| 134 | + return new CrashBuilder(context, dirName); |
| 135 | + } |
61 | 136 |
|
62 |
| - }.start(); |
63 |
| - return true; |
| 137 | + @Override |
| 138 | + public String toString() { |
| 139 | + return "CarshBuilder [dir path: " + getCrash_dir() + "-- log path:" + getCarsh_log() + "-- tag path:" + |
| 140 | + getCrash_tag() + "]"; |
| 141 | + } |
64 | 142 | }
|
65 | 143 |
|
66 | 144 | /**
|
67 |
| - * 获取APP崩溃异常报告 |
68 |
| - * |
69 |
| - * @param ex |
70 |
| - * @return |
| 145 | + * 获取log 日志路径 |
71 | 146 | */
|
72 |
| - private String getCrashReport(Context context, Throwable ex) { |
73 |
| -// PackageInfo pinfo = AppUtils.getPackageInfo(context); |
74 |
| - StringBuffer exceptionStr = new StringBuffer(); |
75 |
| -// exceptionStr.append("Version: " + pinfo.versionName + "(" + pinfo.versionCode + ")\n"); |
76 |
| - exceptionStr.append("Android: " + android.os.Build.VERSION.RELEASE + "(" + android.os.Build.MODEL + ")\n"); |
77 |
| - exceptionStr.append("Exception: " + ex.getMessage() + "\n"); |
78 |
| - StackTraceElement[] elements = ex.getStackTrace(); |
79 |
| - for (int i = 0; i < elements.length; i++) { |
80 |
| - exceptionStr.append(elements[i].toString() + "\n"); |
81 |
| - } |
82 |
| - return exceptionStr.toString(); |
| 147 | + public static String getLogFilePath() { |
| 148 | + if (sBuilder == null) |
| 149 | + return "Unknown"; |
| 150 | + else |
| 151 | + return sBuilder.getCarsh_log(); |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * 获取 LOG 记录的内容 |
| 156 | + */ |
| 157 | + public static String getLogContent() { |
| 158 | + return FileUtils.readFile2String(getLogFilePath(), "UTF-8"); |
83 | 159 | }
|
84 | 160 | }
|
0 commit comments