美文网首页
将捕获的异常信息上传至服务器

将捕获的异常信息上传至服务器

作者: 刘境鑫 | 来源:发表于2017-06-04 18:34 被阅读0次

一、概述

当一个产品上线后,要想知道用户使用时是否出现了bug,总不能让用户来反馈一些信息,要想让用户有更好的体验,我们通常的做法就是去捕获用户操作app所产生的异常信息,然后将所捕获的信息上传到服务器,再进行修复。

二、实现思路

1、构建异常捕获类

如何捕获异常信息?首先了解一个类Thread.UncaughtExceptionHandler,这个类是捕获异常的一个类,重写uncaughtException方法(捕获异常的方法)。具体源码:

public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "ExceptionCrashHandler";
    // 单例设计模式
    private static ExceptionCrashHandler mInstance;
    // 留下原来的,便于开发的时候调试
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    // 上下文  获取版本信息和手机信息
    private Context mContext;

    public static ExceptionCrashHandler getInstance() {
        if (mInstance == null) {
            synchronized (ExceptionCrashHandler.class) {//防止多并发产生错误
                if (mInstance == null) {
                    mInstance = new ExceptionCrashHandler();
                }
            }
        }
        return mInstance;
    }

    private ExceptionCrashHandler() {

    }

    public void init(Context context) {
        /**
        * 官方解释
        * Set the handler invoked when this thread abruptly terminates
        * due to an uncaught exception.
         **/
        Thread.currentThread().setUncaughtExceptionHandler(this);
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        this.mContext = context;
    }

    @Override
    public void uncaughtException(Thread t, Throwable ex) {
        Log.e(TAG, "到拦截闪退信息");
    }

}
在Application的onCreate()中配置一下,然后在任何一个地方写一个异常试一试:


public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ExceptionCrashHandler.getInstance().init(this);
    }
}

2、收集异常信息以及导致异常的设备信息
每次异常都会执行uncaughtException()方法,这个时候我们只需要收集信息写入本地文件就好了,收集的信息肯定需要包含好几个部分:当前崩溃信息,当前应用的版本信息,当前手机的信息,有的时候我们还需要其他部分,这里大概就只收集这三部分。

 @Override
    public void uncaughtException(Thread t, Throwable ex) {
        Log.e(TAG, "捕捉到了异常");
        // 1. 获取信息
        // 1.1 崩溃信息
        // 1.2 手机信息
        // 1.3 版本信息
        // 2.写入文件
        String crashFileName = saveInfoToSD(ex);

        Log.e(TAG, "fileName --> " + crashFileName);

        // 3. 缓存崩溃日志文件
        cacheCrashFile(crashFileName);
        // 系统默认处理
        mDefaultHandler.uncaughtException(t, ex);
    }

    /**
     * 缓存崩溃日志文件
     *
     * @param fileName
     */
    private void cacheCrashFile(String fileName) {
        SharedPreferences sp = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE);
        sp.edit().putString("CRASH_FILE_NAME", fileName).commit();
    }


    /**
     * 获取崩溃文件名称
     *
     * @return
     */
    public File getCrashFile() {
        String crashFileName = mContext.getSharedPreferences("crash",
                Context.MODE_PRIVATE).getString("CRASH_FILE_NAME", "");
        return new File(crashFileName);
    }

    /**
     * 保存获取的 软件信息,设备信息和出错信息保存在SDcard中
     *
     * @param ex
     * @return
     */
    private String saveInfoToSD(Throwable ex) {
        String fileName = null;
        StringBuffer sb = new StringBuffer();

        for (Map.Entry<String, String> entry : obtainSimpleInfo(mContext)
                .entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append(" = ").append(value).append("\n");
        }

        sb.append(obtainExceptionInfo(ex));

        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            File dir = new File(mContext.getFilesDir() + File.separator + "crash"
                    + File.separator);

            // 先删除之前的异常信息
            if (dir.exists()) {
                deleteDir(dir);
            }

            // 再从新创建文件夹
            if (!dir.exists()) {
                dir.mkdir();
            }
            try {
                fileName = dir.toString()
                        + File.separator
                        + getAssignTime("yyyy_MM_dd_HH_mm") + ".txt";
                FileOutputStream fos = new FileOutputStream(fileName);
                fos.write(sb.toString().getBytes());
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return fileName;
    }

    /**
    * 返回当前日期根据格式
    **/
    private String getAssignTime(String dateFormatStr) {
        DateFormat dataFormat = new SimpleDateFormat(dateFormatStr);
        long currentTime = System.currentTimeMillis();
        return dataFormat.format(currentTime);
    }


    /**
     * 获取一些简单的信息,软件版本,手机版本,型号等信息存放在HashMap中
     *
     * @return
     */
    private HashMap<String, String> obtainSimpleInfo(Context context) {
        HashMap<String, String> map = new HashMap<>();
        PackageManager mPackageManager = context.getPackageManager();
        PackageInfo mPackageInfo = null;
        try {
            mPackageInfo = mPackageManager.getPackageInfo(
                    context.getPackageName(), PackageManager.GET_ACTIVITIES);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        map.put("versionName", mPackageInfo.versionName);
        map.put("versionCode", "" + mPackageInfo.versionCode);
        map.put("MODEL", "" + Build.MODEL);
        map.put("SDK_INT", "" + Build.VERSION.SDK_INT);
        map.put("PRODUCT", "" + Build.PRODUCT);
        map.put("MOBLE_INFO", getMobileInfo());
        return map;
    }


    /**
     * Cell phone information
     *
     * @return
     */
    public static String getMobileInfo() {
        StringBuffer sb = new StringBuffer();
        try {
            Field[] fields = Build.class.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                String value = field.get(null).toString();
                sb.append(name + "=" + value);
                sb.append("\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 获取系统未捕捉的错误信息
     *
     * @param throwable
     * @return
     */
    private String obtainExceptionInfo(Throwable throwable) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter printWriter = new PrintWriter(stringWriter);
        throwable.printStackTrace(printWriter);
        printWriter.close();
        return stringWriter.toString();
    }


    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     *
     * @param dir 将要删除的文件目录
     * @return boolean Returns "true" if all deletions were successful. If a
     * deletion fails, the method stops attempting to delete and returns
     * "false".
     */
    private boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            // 递归删除目录中的子目录下
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空,可以删除
        return true;
    }

保存的路径最好不要在用户的外部存储卡中,因为6.0的时候如果访问外部存储卡需要动态的申请权限,那这个时候信息是获取到了但是GG。
3、上传异常信息

public class MainActivity extends BaseActivity {

    @Override
    protected void initData() {
        // 获取上次的崩溃信息
        File crashFile = ExceptionCrashHandler.getInstance().getCrashFile();
        // 上传到服务器
    }

    @Override
    protected void initView() {

    }

    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initTitle() {

    }
}

本文来自http://www.jianshu.com/p/91f494c7adf6

相关文章

  • 将捕获的异常信息上传至服务器

    一、概述 当一个产品上线后,要想知道用户使用时是否出现了bug,总不能让用户来反馈一些信息,要想让用户有更好的体验...

  • 异常捕获上传服务器

    要接入上海分部的自己的性能统计和事件统计的 sdk,在接入之前自己了解下。看到了一套捕获异常的代码。 对于异常分为...

  • iOS开发知识体系之《 Crash闪退日志的捕获》

    如何捕获app闪退的原因?如何将闪退的原因发送到服务器? 一、异常处理:预先设置捕获的异常和未知异常。 预先设置捕...

  • iOS手动捕获异常信息实时查看

    可通过注册NSUncaughtExceptionHandler捕获异常信息,将拿到的NSException细节写入...

  • 前端异常监控window.onerror unhandledre

    关于前端异常监控,我们需要做到捕获JS异常和代码中未捕获的promise异常,然后向服务器上报 捕获JS异常 在了...

  • Spring Boot——全局捕获异常

    1.全局捕获异常:进行全局捕获异常可以去捕获一些运行时候的错误,将这些错误信息处理掉,而不去返回给用户。 2.代码...

  • ERROR ITMS-90475 - iOS

    日常产品功能迭代完成后打包上传至 App Store 期间抛出如下异常信息: 异常信息 ERROR ITMS-90...

  • logging日志使用

    日志的等级 捕获异常信息到日志。这里主要需要进行捕获异常才能记录下完整的异常信息 日志的输出格式 对于日志的输出格...

  • NO.91 Spring中文件的上传与下载

    1.文件上传业务分析 1)将文件上传到服务器,然后存储到服务器的某个位置. 2)将已上传的文件相关信息存储到数据库...

  • python异常处理、模块、私有化

    异常处理 一、系统异常 1.捕捉异常 2.捕获多个异常 3.异常描述信息 4.捕获所有异常 5.try…final...

网友评论

      本文标题:将捕获的异常信息上传至服务器

      本文链接:https://www.haomeiwen.com/subject/tlqbfxtx.html