|
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