App发生崩溃保存崩溃日志在本地,并发送邮件给开发人员

App在客户手中时不时会出现闪退,崩溃等现象。但蛋疼的时有时候无法重现崩溃原因处理。于是,崩溃保存日志出来了,但保存在用户本地也看不到啊,于是,发邮件又来了。效果如图
App发生崩溃保存崩溃日志在本地,并发送邮件给开发人员_第1张图片
再说个蛋疼的问题,我在公司Android stadio 2.3.3版本UncaughtExceptionHandler不会跳到这个奔溃的提示页面,但我在家里的Android stadio 3.0.1版本有没问题。默默的问问,2.3.3-3.0.1更新了什么。

好了,不哔哔,上代码。
其中主要的是实现UncaughtExceptionHandler这个接口,这个接口有什么用呢?简单点来说,会针对,某段代码做try … catch 没有catch到的代码,发生异常的时候,就会由setDefaultUncaughtExceptionHandler来处理

/**
 * Created by supper on 2017/11/22.
 * UncaughtExceptionHandler做全局的catch
 * 通常来讲,会针对,某段代码做try … catch 没有catch到的代码,发生异常的时候,就会由setDefaultUncaughtExceptionHandler来处理。
 * 当程序崩溃时,由这些代码接管
 * 将报错文件报错到本地,超出日志的大小删除掉旧日志
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {
   
    public static final String TAG = "APP>>CrashHandler";

    //系统默认的UncaughtException处理类
    private static Thread.UncaughtExceptionHandler mDefaultUncaughtException;
    //CarshHandler的单例实例
    private static CrashHandler instance;
    //程序的Context对象
    private Context mContext;
    //用来存储设备信息和异常信息
    private Map infos = new HashMap();

    private String errorLog = "";
    private String errorData = "";

    private String logName = "error";

    private long FileSize = 1024 * 1024 * 10;//1个文件只保存10M的日志,超出重新创建日志文件

    Handler handler = new Handler(Looper.getMainLooper());

    /** 获取CrashHandler实例 ,单例模式 */
    public static CrashHandler getInstance() {
        if(instance == null)
            instance = new CrashHandler();
        return instance;
    }

    //初始化
    public void init(Context context){
        Log.d(TAG, "init: 初始化");
        mContext = context;
        //获取系统默认的UncaughtException处理器
        mDefaultUncaughtException = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        cleanLog(3);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultUncaughtException != null) {
            //以对代码做try … catch处理的代码,继续让系统默认的异常处理器来处理
            mDefaultUncaughtException.uncaughtException(thread, ex);
        } else {
            //uncaughtException无法调出弹窗,只能跳到Activity,询问用户是否发送邮件
            Intent intent = new Intent(mContext, CrashDialog.class);
            intent.putExtra("errorData",errorData);
            intent.putExtra("errorLog",errorLog);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent);
            System.exit(0);
            android.os.Process.killProcess(android.os.Process.myPid());

//            //App重启处理
//            Intent intent = new Intent(mContext, MainActivity.class);
//            PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
//            //退出程序
//            AlarmManager mgr = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
//            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
//                    restartIntent); // 1秒钟后重启应用
//            System.exit(0);
//            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }

    private boolean handleException(Throwable ex){
        if(ex == null){
            return  false;
        }
        //收集设备参数信息
        collectDeviceInfo(mContext);
        try{
            if(FileUtil.hasSdcard()){
  //SD卡可用
                saveCrashInfoFile(ex);
            }
        }catch (Exception e){
            Log.e(TAG,e.getMessage());
        }
        return true;
    }

    private void collectDeviceInfo(Context ctx){
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);
            if(pi != null){
                //获取版本
                String versionName = pi.versionName == null ? "null" : pi.versionName;
                String versionCode = pi.versionCode + "";
                infos.put("versionName", versionName);
                infos.put("versionCode", versionCode);
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "获取版本信息不成功》》" + e);
        }
        //获取手机的配置信息
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);//成员变量为private,故必须进行此操
                infos.put(field.getName(), field.get(null).toString());
                Log.d(TAG, field.getName() + " : " + field.get(null));
            } catch (Exception e) {
                Log.e(TAG, "获取配置信息不成功》》", e);
            }
        }
    }

    /**
     * 保存错误信息到文件中
     * @param ex
     * @return 返回文件名称,便于将文件传送到服务器
     * @throws Exception
     */
    private String saveCrashInfoFile(Throwable ex) throws Exception {
        Log.d(TAG, "saveCrashInfoFile:错误信息" + ex.getMessage());
        errorLog = "";
        errorData = "";
        Log.d(TAG, "saveCrashInfoFile: gg了,保存报错日志到本地");
        StringBuffer sb = new StringBuffer();
        try {
            sb.append("\n\n\n-------------------------------------------我是开始的分割线---------------------------------------------------\n");
            SimpleDateFormat sDateFormat = new SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss");
            errorData = sDateFormat.format(new java.util.Date());
            sb.append(errorData + "\n");
            //Map.Entry 将map里的每一个键值对取出来封装成一个Entry对象在存到一个Set里面
            for (Map.Entry entry : infos.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                sb.append(key + "=" + value + "\n");
            }

            Writer writer = new StringWriter();
            PrintWriter printWriter = new PrintWriter(writer);
            ex.printStackTrace(printWriter);
            Throwable cause = ex.getCause();
            while (cause != null) {
                cause.printStackTrace(printWriter);
                cause = cause.getCause();
            }
            printWriter.flush();
            printWriter.close();
            String result = writer.toString();
            sb.append(result);
            sb.append("-------------------------------------------我是结束的分割线---------------------------------------------------\n\n\n\n");
            final String fileName = getFileName();
            FileUtil.writeFile(fileName,sb.toString(),true);
            e

你可能感兴趣的:(android,异常,邮件,android,app)