获取Android崩溃crash信息并写入日志发送邮件

Posted changyiqiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取Android崩溃crash信息并写入日志发送邮件相关的知识,希望对你有一定的参考价值。

一、实现Thread.UncaughtExceptionHandler
UnChecked异常发生时,由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是我们所说的Crash。Java API提供了一个全局异常捕获处理器,android应用在Java层捕获Crash依赖的就是Thread.UncaughtExceptionHandler处理器接口,通常我们只需实现这个接口,并重写其中的uncaughtException方法,在该方法中可以读取Crash的堆栈信息

public class CrashManager implements Thread.UncaughtExceptionHandler 


    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private Map<String, String> infos;
    private MyApplication application;
    private static SimpleDateFormat logfile = new SimpleDateFormat("yyyy-MM-dd");// 日志文件格式


    public CrashManager(MyApplication application)
        //获取系统默认的UncaughtExceptionHandler
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        this.application = application;
    

    private boolean handleException(final Throwable exc)
        if (exc == null) 
            return false;
        
        new Thread(new Runnable() 
            @Override
            public void run() 
                Looper.prepare();//准备
                Log.i("Urmytch","崩溃正在写入日志");
                flushBufferedUrlsAndReturn();
                //处理崩溃
                collectDeviceAndUserInfo(application);
                writeCrash(exc);
                Looper.loop();
            
        ).start();
        return true;
    

    /**
     * 把未存盘的url和返回数据写入日志文件
     */
    private void flushBufferedUrlsAndReturn()
        //TODO 可以在请求网络时把url和返回xml或json数据缓存在队列中,崩溃时先写入以便查明原因
    

    /**
     * 采集设备和用户信息
     * @param context 上下文
     */
    private void collectDeviceAndUserInfo(Context context)
        PackageManager pm = context.getPackageManager();
        infos = new HashMap<String, String>();
        try 
            PackageInfo pi = pm.getPackageInfo(context.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);
                infos.put("crashTime",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            
         catch (PackageManager.NameNotFoundException e) 
            Log.e("Urmytch",e.getMessage());
        
        Field[] fields = Build.class.getDeclaredFields();
        try 
            for (Field field : fields) 
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
            
         catch (IllegalAccessException e) 
            Log.e("Urmytch",e.getMessage());
        
    

    /**
     * 采集崩溃原因
     * @param exc 异常
     */

    private void writeCrash(Throwable exc)
        StringBuffer sb = new StringBuffer();
        sb.append("------------------crash----------------------");
        sb.append("\r\n");
        for (Map.Entry<String,String> entry : infos.entrySet()) 
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key+"="+value+"\r\n");
        
        Writer writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        exc.printStackTrace(pw);
        Throwable excCause = exc.getCause();
        while (excCause != null) 
            excCause.printStackTrace(pw);
            excCause = excCause.getCause();
        
        pw.close();
        String result = writer.toString();
        sb.append(result);
        sb.append("\r\n");
        sb.append("-------------------end-----------------------");
        sb.append("\r\n");
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
        
            String sdcardPath = Environment.getExternalStorageDirectory().getPath();
            Log.i("路径:",""+Environment.getExternalStorageDirectory().getPath());
            //String filePath = sdcardPath + "//Urmytch/crash/";
            String filePath = sdcardPath + "//kantu/crash/";
            writeLog(sb.toString(), filePath);


        
    
    /**
     *
     * @param log 文件内容
     * @param name 文件路径
     * @return 返回写入的文件路径
     * 写入Log信息的方法,写入到SD卡里面
     */
    private String writeLog(String log, String name)
    
        Date nowtime = new Date();
        String needWriteFiel = logfile.format(nowtime);
        //String filename = name + "mycrash"+ ".log";
        String filename = name + "mycrash"+ needWriteFiel+".txt";
        File file =new File(filename);
        if(!file.getParentFile().exists())
            Log.i("Urmytch","新建文件");
            file.getParentFile().mkdirs();
        
        if (file != null && file.exists() && file.length() + log.length() >= 64 * 1024) 
            //控制日志文件大小
            file.delete();
        
        try
        
            file.createNewFile();
            FileWriter fw=new FileWriter(file,true);
            BufferedWriter bw = new BufferedWriter(fw);
            //写入相关Log到文件
            bw.write(log);
            bw.newLine();
            bw.close();
            fw.close();
            //发送邮件
            SendMailUtil.send(file,"changyiqiang123@126.com");
            return filename;
        
        catch(IOException e)
        
            Log.w("Urmytch",e.getMessage());
            return null;
        


    
    @Override
    public void uncaughtException(Thread thread, Throwable exc) 
        if(!handleException(exc) && mDefaultHandler != null)
            //如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, exc);
            Log.i("打印:","1111");
        else
            Log.i("打印:","222");

            try
                Thread.sleep(2000);
            catch (InterruptedException e)
                Log.w("Urmytch",e.getMessage());
            
            Intent intent = new Intent(application.getApplicationContext(), LoginActivity.class);
            PendingIntent restartIntent = PendingIntent.getActivity(application.getApplicationContext(), 0, intent, 0);
            //退出程序
            AlarmManager mgr = (AlarmManager)application.getSystemService(Context.ALARM_SERVICE);
            //1秒后重启应用
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);
            android.os.Process.killProcess(android.os.Process.myPid());
        


        ////这里可以上传异常信息到服务器,便于开发人员分析日志从而解决Bug
        //        uploadExceptionToServer();
    


    /**
     * 将错误信息上传至服务器
     */
    private void uploadExceptionToServer() 
        File file = new File(Environment.getExternalStorageDirectory()+File.separator+"test.txt");
        OutputStream os = null;
        try 
            os = new FileOutputStream(file);
            String str = "hello world";
            byte[] data = str.getBytes();
            os.write(data);
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        finally
            try 
                if (os != null)os.close();
             catch (IOException e) 
            
        
        SendMailUtil.send(file,"changyiqiang123@126.com");
    


  

二、在Application中注册

public class MyApplication extends Application 
    @Override
    public void onCreate() 
        super.onCreate();
        CrashManager crashHandler = new CrashManager(this);
        Thread.setDefaultUncaughtExceptionHandler(crashHandler);
    

  完成 

参考于:https://blog.csdn.net/urmytch/article/details/53642945

 

以上是关于获取Android崩溃crash信息并写入日志发送邮件的主要内容,如果未能解决你的问题,请参考以下文章

Xcode7.3工具解析App崩溃日志(.crash文件)

android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地

苹果手机crash日志怎么用symbolicatecrash分析

iOS开发——捕获崩溃信息

Android应用崩溃后异常捕获并重启并写入日志

crash日志的分析