Android 一行代码搞定将错误日志放入到sd卡中且不需要任何权限,适配到android7.0

Android 一行代码搞定将错误日志放入到sd卡中且不需要任何权限,适配到android7.0

之前所有的项目都有一个将崩溃日志写入到sd卡的工具类,然后每次项目新建都从老项目copy过来,后来慢慢发现这样也挺累的。就吧工具类封装到了一个lib库里面,后来android6.0出了权限需要动态申请,然后又把日志写入到getExternalFilesDir()里面去。后来把他上传到jcenter里面去了,更方便了,就分享给大家。

github地址:https://github.com/dreamlivemeng/Clog

Clog

这是一个将android 崩溃日志写入到sd卡得工具类。
This is a tool that write the Android crash log to the sd card.
最低版本android2.2(8),已经适配到android7.0。

目前对应Clog版本0.0.1.

导入方法

  • Android Studio

     compile 'com.dreamlive.cn.clog:ClogLibrary:0.0.1'
    

使用方法1

强烈建议*

使用方法1,因为不需要权限。

在application的oncreate()配置

  //android6.0也不需要动态sd权限,
  //将错误日志写入到sd卡,默认为Android/data/包名/files/logs下面放这个目录下主要是为了不需要权限
  CollectLog clog = CollectLog.getInstance();
  clog.init(this);
  \[object Object\]
  //一行代码就是CollectLog.getInstance().init(this);

使用方法2

自定义日志存放路径 在application的oncreate()配置

   //自定义日志存放路径,
   //这儿示例就只传了sd根目录下的dreamlivemeng(/storage/emulated/0/dreamlivemeng),把错误日志写到这个目录下
  CollectLog clog = CollectLog.getInstance();
  clog.init(this, Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dreamlivemeng");

混淆

#Clog
-dontwarn com.dreamlive.cn.**
-keep classcom.dreamlive.cn.**{*;}

使用方法说完了,来说说具体是怎么实现的。

主要用到了一个类UncaughtExceptionHandler。

//初始化,2个init是因为一个是将日志存到默认路径下,另外一个是自定义保存路径。

   /**
     * initialization
     *
     * @param context context
     */
    public void init(Context context) {
        mContext = context;
        //Gets the system's default UncaughtException handler
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //Set the CrashHandler as the default handler for the program
        Thread.setDefaultUncaughtExceptionHandler(this);
    }
    /**
     * initialization ,Can custom the path
     *
     * @param context context
     * @param path    custom the path
     */
    public void init(Context context, String path) {
        init(context);
        filePath = path;
    }

//收集设备基本信息

   /**
     * Collect device parameter information
     *
     * @param ctx context
     */
    public 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 (NameNotFoundException e) {
//            Log.e(TAG, "an error occured when collect package info", e);
        }
        Field\[\] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
//                Log.d(TAG, field.getName() + " : " + field.get(null));
            } catch (Exception e) {
//                Log.e(TAG, "an error occured when collect crash info", e);
            }
        }
    }

//收集错误日志

   
    /**
     * Gets the string of the caught exception
     *
     * @param tr throwable
     * @return the string of the caught exception
     */
    public static String getStackTraceString(Throwable tr) {
        try {
            if (tr == null) {
                return "";
            }
            Throwable t = tr;
            while (t != null) {
                if (t instanceof UnknownHostException) {
                    return "";
                }
                t = t.getCause();
            }
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            tr.printStackTrace(pw);
            return sw.toString();
        } catch (Exception e) {
            return "";
        }
    }

//将错误日志和设备信息写入到sd卡

  
    /**
     * Save the error message to a file
     *
     * @param ex Throwable
     * @return Returns the name of the file to facilitate transfer of the file to the server
     */
    private String saveCrashInfo2File(Throwable ex) {
        StringBuffer sb = new StringBuffer();
        for (Map.Entryentry : infos.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append("\[" + key + ", " + value + "\]n");
        }
        sb.append("n" + getStackTraceString(ex));
        try {
            String time = formatter.format(new Date());
            String fileName = "CRS_" + time + ".txt";
            File sdDir = null;
            sdDir = mContext.getExternalFilesDir("logs").getAbsoluteFile();
            File file = null;
            if (!TextUtils.isEmpty(filePath)) {
                File files = new File(filePath);
                if (!files.exists()) {
                    //Create a directory
                    files.mkdirs();
                }
                file = new File(filePath + File.separator + fileName);
            } else {
                file = new File(sdDir + File.separator + fileName);
            }
            if (file == null) {
                file = new File(sdDir + File.separator + fileName);
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(sb.toString().getBytes());
            fos.close();
            return fileName;
        } catch (Exception e) {
        }
        return null;
    }

最后厚脸求star和fork,如有错误可以直接提issues。

github地址:https://github.com/dreamlivemeng/Clog