content: package com.rsen.github.androidutilcode;
  
  import android.content.Context;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.os.Build;
  import android.os.Environment;
  
  import java.io.File;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.lang.Thread.UncaughtExceptionHandler;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  
  /**
   * <pre>
   *     author: Blankj
   *     blog  : http://blankj.com
   *     time  : 2016/9/27
   *     desc  : 崩溃相关工具类
   * </pre>
   */
  public class CrashUtils implements UncaughtExceptionHandler {
  
      private static CrashUtils mInstance = new CrashUtils();
      private        UncaughtExceptionHandler mHandler;
      private        boolean                  mInitialized;
      private static String                   crashDir;
      private        String                   versionName;
      private        int                      versionCode;
  
      private CrashUtils() {
      }
  
      /**
       * 获取单例
       * <p>在Application中初始化{@code CrashUtils.getInstance().init(this);}</p>
       *
       * @return 单例
       */
      public static CrashUtils getInstance() {
          return mInstance;
      }
  
      /**
       * 初始化
       *
       * @param context 上下文
       * @return {@code true}: 成功<br>{@code false}: 失败
       */
      public boolean init(Context context) {
          if (mInitialized) return true;
          if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
              crashDir = context.getExternalCacheDir().getPath() + File.separator + "crash" + File.separator;
          } else {
              crashDir = context.getCacheDir().getPath() + File.separator + "crash" + File.separator;
          }
          try {
              PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
              versionName = pi.versionName;
              versionCode = pi.versionCode;
          } catch (PackageManager.NameNotFoundException e) {
              e.printStackTrace();
              return false;
          }
          mHandler = Thread.getDefaultUncaughtExceptionHandler();
          Thread.setDefaultUncaughtExceptionHandler(this);
          return mInitialized = true;
      }
  
      @Override
      public void uncaughtException(Thread thread, Throwable throwable) {
          String now = new SimpleDateFormat("yy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
          String fullPath = crashDir + now + ".txt";
          if (!FileUtils.createOrExistsFile(fullPath)) return;
          PrintWriter pw = null;
          try {
              pw = new PrintWriter(new FileWriter(fullPath, false));
              pw.write(getCrashHead());
              throwable.printStackTrace(pw);
              Throwable cause = throwable.getCause();
              while (cause != null) {
                  cause.printStackTrace(pw);
                  cause = cause.getCause();
              }
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
              CloseUtils.closeIO(pw);
          }
          if (mHandler != null) {
              mHandler.uncaughtException(thread, throwable);
          }
      }
  
      /**
       * 获取崩溃头
       *
       * @return 崩溃头
       */
      private String getCrashHead() {
          return "\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";
      }
  }
  