package com.yidianling.common.tools; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import androidx.annotation.NonNull; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.Thread.UncaughtExceptionHandler; import java.text.Format; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by vondear on 2016/12/21. */ public class RxCrashTool { private static final String FILE_SEP = System.getProperty("file.separator"); //---------------------------------------------------------------------------------------------- private static final Format FORMAT = new SimpleDateFormat("MM-dd HH-mm-ss", Locale.getDefault()); private static final String CRASH_HEAD; private static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER; private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER; private static Context mContext; private static String mCrashDirPath; private static String dir; private static String versionName; private static int versionCode; private static ExecutorService sExecutor; static { CRASH_HEAD = "\n************* Crash Log Head ****************" + "\nDevice Manufacturer: " + Build.MANUFACTURER +// 设备厂商 "\nDevice Model : " + Build.MODEL +// 设备型号 "\nAndroid Version : " + Build.VERSION.RELEASE +// 系统版本 "\nAndroid SDK : " + Build.VERSION.SDK_INT +// SDK版本 "\nApp VersionName : " + versionName + "\nApp VersionCode : " + versionCode + "\n************* Crash Log Head ****************\n\n"; DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); UNCAUGHT_EXCEPTION_HANDLER = new UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread t, final Throwable e) { if (e == null) { android.os.Process.killProcess(android.os.Process.myPid()); System.exit(0); return; } Date now = new Date(System.currentTimeMillis()); String fileName = FORMAT.format(now) + ".txt"; final String fullPath = (dir == null ? mCrashDirPath : dir) + fileName; if (!createOrExistsFile(fullPath)) { return; } if (sExecutor == null) { sExecutor = Executors.newSingleThreadExecutor(); } sExecutor.execute(new Runnable() { @Override public void run() { PrintWriter pw = null; try { pw = new PrintWriter(new FileWriter(fullPath, false)); pw.write(CRASH_HEAD); e.printStackTrace(pw); Throwable cause = e.getCause(); while (cause != null) { cause.printStackTrace(pw); cause = cause.getCause(); } } catch (IOException e) { e.printStackTrace(); } finally { if (pw != null) { pw.close(); } } } }); if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) { DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, e); } } }; } /** * 初始化 * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p> */ public static void init(Context context) { mContext = context; try { PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); if (pi != null) { versionName = pi.versionName; versionCode = pi.versionCode; } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } init(""); } /** * 初始化 * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p> * * @param crashDir 崩溃文件存储目录 */ public static void init(@NonNull final File crashDir) { init(crashDir.getAbsolutePath()); } /** * 初始化 * <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p> * * @param crashDir 崩溃文件存储目录 */ public static void init(final String crashDir) { if (isSpace(crashDir)) { dir = null; } else { dir = crashDir.endsWith(FILE_SEP) ? crashDir : crashDir + FILE_SEP; } try { PackageManager packageManager = mContext.getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo(mContext.getPackageName(), 0); int labelRes = packageInfo.applicationInfo.labelRes; String name = mContext.getResources().getString(labelRes); mCrashDirPath = RxFileTool.getRootPath() + File.separator + name + File.separator + "crash" + File.separator; } catch (Exception e) { mCrashDirPath = mContext.getCacheDir().getPath() + File.separator + "crash" + File.separator; /* if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { mCrashDirPath = mContext.getExternalCacheDir().getPath() + File.separator + "crash" + File.separator; } else { mCrashDirPath = mContext.getCacheDir().getPath() + File.separator + "crash" + File.separator; }*/ } Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER); } private static boolean createOrExistsFile(final String filePath) { File file = new File(filePath); if (file.exists()) { return file.isFile(); } if (!createOrExistsDir(file.getParentFile())) { return false; } try { return file.createNewFile(); } catch (IOException e) { e.printStackTrace(); return false; } } private static boolean createOrExistsDir(final File file) { return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); } private static boolean isSpace(final String s) { if (s == null) { return true; } for (int i = 0, len = s.length(); i < len; ++i) { if (!Character.isWhitespace(s.charAt(i))) { return false; } } return true; } }