|
1 | 1 | package com.blankj.utilcode.utils;
|
2 | 2 |
|
| 3 | +import android.annotation.SuppressLint; |
3 | 4 | import android.content.Context;
|
4 | 5 | import android.content.pm.PackageInfo;
|
| 6 | +import android.content.pm.PackageManager; |
5 | 7 | import android.os.Build;
|
6 | 8 | import android.os.Environment;
|
| 9 | +import android.util.Log; |
7 | 10 |
|
8 | 11 | import java.io.File;
|
9 | 12 | import java.io.FileWriter;
|
10 | 13 | import java.io.IOException;
|
11 | 14 | import java.io.PrintWriter;
|
| 15 | +import java.io.StringWriter; |
| 16 | +import java.io.Writer; |
12 | 17 | import java.lang.Thread.UncaughtExceptionHandler;
|
| 18 | +import java.nio.channels.NonWritableChannelException; |
| 19 | + |
| 20 | +import static android.content.ContentValues.TAG; |
13 | 21 |
|
14 | 22 | /**
|
15 | 23 | * <pre>
|
|
21 | 29 | */
|
22 | 30 | public class CrashUtils implements Thread.UncaughtExceptionHandler {
|
23 | 31 |
|
| 32 | + private volatile static CrashUtils mInstance; |
| 33 | + private Context mContext; |
24 | 34 | 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; |
| 35 | + private boolean mInitialized; |
| 36 | + |
| 37 | + private CrashUtils(){ |
32 | 38 |
|
33 |
| - private CrashUtils() { |
34 |
| - mHandler = Thread.currentThread().getUncaughtExceptionHandler(); |
35 |
| - Thread.currentThread().setUncaughtExceptionHandler(this); |
36 |
| - mAndroidVersion = Build.VERSION.RELEASE;//安卓系统版本 |
37 |
| - mModel = Build.MODEL;// 设备型号 |
38 |
| - mManufacturer = Build.MANUFACTURER;// 设备厂商 |
39 | 39 | }
|
40 | 40 |
|
41 | 41 | /**
|
42 |
| - * @param isAppend 是否为日志追加模式 |
| 42 | + * 获取单例 |
| 43 | + * |
| 44 | + * @return 单例 |
43 | 45 | */
|
44 |
| - public CrashUtils setAppend(boolean isAppend) { |
45 |
| - this.isAppend = isAppend; |
46 |
| - return this; |
| 46 | + public static CrashUtils getInstance() { |
| 47 | + synchronized (CrashUtils.class) { |
| 48 | + if (null == mInstance) { |
| 49 | + mInstance = new CrashUtils(); |
| 50 | + } |
| 51 | + } |
| 52 | + return mInstance; |
47 | 53 | }
|
48 | 54 |
|
49 | 55 | /**
|
50 |
| - * @param isSimple 是否为简单的日志记录模式 |
| 56 | + * 初始化 |
| 57 | + * |
| 58 | + * @param context 上下文 |
51 | 59 | */
|
52 |
| - public CrashUtils setSimple(boolean isSimple) { |
53 |
| - this.isSimple = isSimple; |
54 |
| - return this; |
| 60 | + public void init(Context context) { |
| 61 | + if (mInitialized) return; |
| 62 | + mInitialized = true; |
| 63 | + mContext = context; |
| 64 | + mHandler = Thread.getDefaultUncaughtExceptionHandler(); |
| 65 | + Thread.setDefaultUncaughtExceptionHandler(this); |
55 | 66 | }
|
56 | 67 |
|
57 |
| - |
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(); |
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 |
| - |
81 | 68 | @Override
|
82 | 69 | public void uncaughtException(Thread thread, Throwable throwable) {
|
83 |
| - if (!isAppend) { |
84 |
| - FileUtils.createFileByDeleteOldFile(sBuilder.getCarsh_log()); |
| 70 | + String dir; |
| 71 | + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { |
| 72 | + dir = mContext.getExternalCacheDir().getPath(); |
85 | 73 | } else {
|
86 |
| - FileUtils.createOrExistsFile(sBuilder.getCarsh_log()); |
| 74 | + dir = mContext.getCacheDir().getPath(); |
87 | 75 | }
|
88 |
| - File file = new File(sBuilder.getCarsh_log()); |
| 76 | + String fullPath = dir + File.separator + "crash_" + TimeUtils.getCurTimeString() + ".txt"; |
| 77 | + if (!FileUtils.createOrExistsFile(fullPath)) return; |
| 78 | + StringBuilder sb = new StringBuilder(); |
| 79 | + sb.append(getCrashHead()); |
| 80 | + Writer writer = new StringWriter(); |
89 | 81 | PrintWriter pw = null;
|
90 | 82 | 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"); |
| 83 | + pw = new PrintWriter(writer); |
| 84 | + throwable.printStackTrace(pw); |
| 85 | + Throwable cause = throwable.getCause(); |
| 86 | + while (cause != null) { |
| 87 | + cause.printStackTrace(pw); |
| 88 | + cause = cause.getCause(); |
103 | 89 | }
|
104 |
| - } catch (IOException e) { |
105 |
| - return; |
106 | 90 | } finally {
|
107 | 91 | FileUtils.closeIO(pw);
|
108 | 92 | }
|
109 |
| - FileUtils.createFileByDeleteOldFile(sBuilder.getCrash_tag()); |
| 93 | + sb.append(writer.toString()); |
| 94 | + FileUtils.writeFileFromString(fullPath, sb.toString(), false); |
110 | 95 | if (mHandler != null) {
|
111 | 96 | mHandler.uncaughtException(thread, throwable);
|
112 | 97 | }
|
113 | 98 | }
|
114 | 99 |
|
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; |
131 |
| - } |
132 |
| - } |
133 |
| - public static CrashBuilder build(Context context, String dirName) { |
134 |
| - return new CrashBuilder(context, dirName); |
135 |
| - } |
136 |
| - |
137 |
| - @Override |
138 |
| - public String toString() { |
139 |
| - return "CarshBuilder [dir path: " + getCrash_dir() + "-- log path:" + getCarsh_log() + "-- tag path:" + |
140 |
| - getCrash_tag() + "]"; |
141 |
| - } |
142 |
| - } |
143 |
| - |
144 | 100 | /**
|
145 |
| - * 获取log 日志路径 |
| 101 | + * 获取崩溃头 |
| 102 | + * |
| 103 | + * @return 崩溃头 |
146 | 104 | */
|
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"); |
| 105 | + public StringBuilder getCrashHead() { |
| 106 | + StringBuilder sb = new StringBuilder(); |
| 107 | + try { |
| 108 | + PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); |
| 109 | + sb.append("\n************* Crash Log Head ****************"); |
| 110 | + sb.append("\nDevice Manufacturer: ").append(Build.MANUFACTURER);// 设备厂商 |
| 111 | + sb.append("\nDevice Model : ").append(Build.MODEL);// 设备型号 |
| 112 | + sb.append("\nAndroid Version : ").append(Build.VERSION.RELEASE);// 系统版本 |
| 113 | + sb.append("\nAndroid SDK : ").append(Build.VERSION.SDK_INT);// SDK版本 |
| 114 | + sb.append("\nApp VersionName : ").append(pi.versionName); |
| 115 | + sb.append("\nApp VersionCode : ").append(pi.versionCode); |
| 116 | + sb.append("\n************* Crash Log Head ****************\n\n"); |
| 117 | + } catch (PackageManager.NameNotFoundException e) { |
| 118 | + e.printStackTrace(); |
| 119 | + } |
| 120 | + return sb; |
159 | 121 | }
|
160 | 122 | }
|
0 commit comments