获取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,"[email protected]");
            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,"[email protected]");
    }

}

  

二、在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

原文地址:https://www.cnblogs.com/changyiqiang/p/11224971.html

时间: 2024-09-29 10:37:29

获取Android崩溃crash信息并写入日志发送邮件的相关文章

常用获取Android崩溃日志和IOS崩溃日志的几种方法

一:前言 在日常测试app时,经常会遇到崩溃问题,测试快速抓取到崩溃日志可以有效方便开发进行定位,快速解决问题所在测试做到测试分析,定位是非常重要的,这也是判断一个测试能力指标的一大维度. 二:Android崩溃日志 一.通过adb logcat获取 # 清除日志,新手上路时,日志内容很多,对于能毕现的日志,可以先清除后重新获取 adb logcat -c # 然后再次运行崩溃操作,再抓取日志 # 存储日志到当前目录下的 carsh.log 中 adb logcat -d *:W > crash

获取android所有联系人信息

转自http://blog.csdn.net/sky181772733/article/details/7221431 这个是代码 1 import android.app.Activity; 2 import android.database.Cursor; 3 import android.os.Bundle; 4 import android.provider.ContactsContract; 5 import android.provider.ContactsContract.Data

代码获取Android版本等信息

我手机的关于手机界面: 说明: 其中手机型号.Android版本.软件版本通过系统Build类得到,处理器信息.内核版本通过读取系统文件得到,基带版本信息通过反射得到. 源码: package com.example.shen.phoneinfo; import android.app.Activity; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.L

Windows Phone &amp; Windows App应用程序崩溃crash信息抓取方法

最近有用户反馈,应用有崩溃的情况,可是本地调试却无法重现问题,理所当然的,我想到了微软的开发者仪表盘,可以查看一段时间内的carsh记录,不过仪表盘生成carsh记录不是实时的,而且生成的报告查看非常不便,是否有其他方法抓取应用的崩溃记录呢? 其实目前已经有一些第三方提供了相应的工具插件,如国外的uTest(http://www.utest.com/),mtiks(http://www.mtiks.com/),国内的九幽(http://www.windows.sc)等等,小弟英语比较烂,就只研究

(转)获取android手机内部存储空间和外部存储空间的参数 &amp;&amp; 如何决定一个apk的安装位置

转:http://blog.csdn.net/zhandoushi1982/article/details/8560233 获取android文件系统的信息,需要Environment类和StatFs类的支持. (1)Environment 是一个提供访问环境变量的类,常用的方法有: A,getRootDirectory() ,返回File,获取Android 的根目录. B,getDataDirectory() ,返回File ,获取Android 数据目录. C,getExternalSto

Android崩溃日志获取与解析

在程序界面有一句话很流行,那就是不要重复造轮子.现在市面上有很多的崩溃日志抓取工具,比如腾讯的bugly,不管是eclipse还是Android Studio,集成都是非常简单,他可以抓取到JAVA的崩溃,同样也可以抓取到NDK代码的崩溃. Java的崩溃就没有什么好说的,集成的步骤以及实现的原理太简单,下面我们来看看如何集成NDK崩溃的抓取 首先在c/c++代码的任意位置添加代码const char SO_FILE_VERSION[]  __attribute__ ((section (".b

【Android应用开发】 Android 崩溃日志 本地存储 与 远程保存

示例代码下载 : http://download.csdn.net/detail/han1202012/8638801; 一. 崩溃日志本地存储 1. 保存原理解析 崩溃信息本地保存步骤 : -- 1. 自定义类实现 UncaughtExceptionHandler : public class CrashHandler implements UncaughtExceptionHandler; -- 2. 设置该自定义的 CrashHandler 类为单例模式 : // 单例模式 private

Android Native crash日志分析

在Android应用crash的类型中,native类型crash应该是比较难的一种了,因为大家接触的少,然后相对也要多转几道工序,所有大部分对这个都比较生疏.虽然相关文章也有很多了,但是我在刚开始学的过程中还是遇到一些问题,下面一一记录,以便将来翻阅. 分析native crash 日志需要几个东西: addr2line,objdump,ndk-stack等几个工具 带symbols的so文件 log log native crash的日志都是从一行星号(*** *** *** *** ***

Android怎样捕获应用的crash信息

转载请注明出处:http://blog.csdn.net/fishle123/article/details/50823358 我们的应用不可避免的会发生crash,假设是在调试阶段,我们能够使用Logcat查看异常信息.可是假设应用公布之后呢?假设在用户那边crash了,假设我们能够捕获这些crash信息,那么对我们定位crash原因并修复问题是非常有帮助的. 应用crash就可以能是Java层的异常导致的,也可能是native层导致,以下分别来看一下该怎样处理. 1 Java层的未捕获异常处