1.概述

大致的流程就是在用户崩溃的时候,我们获取崩溃信息、应用当前的信息和手机信息,然后把它保存到手机内存卡,再找我就直接找出来看看。后来衍生到上线后某些奇葩机型会有部分问题,所以不得不上传到服务器,后来发现居然可以配合热修复一步一步如此神奇,接下来我们来玩一玩,如何才能把用户的崩溃信息上传到服务器。大家也可以去找腾讯他有现成的:https://bugly.qq.com/v2/index 友盟也有现成的:http://www.umeng.com/ 实现的原理都类似。

2.实现


2.1 拦截闪退信息
  
  如何去收集我们的闪退信息?我们需要认识一下这个类Thread.UncaughtExceptionHandler,一言不和就看源码,这个可以不看,且看我是如何写的。

拦截应用的闪退信息

 1 public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler {
 2
 3     private static final String TAG = "ExceptionCrashHandler";
 4     // 单例设计模式
 5     private static ExceptionCrashHandler mInstance;
 6     // 留下原来的,便于开发的时候调试
 7     private Thread.UncaughtExceptionHandler mDefaultHandler;
 8     // 上下文  获取版本信息和手机信息
 9     private Context mContext;
10
11     public static ExceptionCrashHandler getInstance() {
12         if (mInstance == null) {
13             synchronized (ExceptionCrashHandler.class) {
14                 if (mInstance == null) {
15                     mInstance = new ExceptionCrashHandler();
16                 }
17             }
18         }
19         return mInstance;
20     }
21
22     private ExceptionCrashHandler() {
23
24     }
25
26     public void init(Context context) {
27         /**
28         * 官方解释
29         * Set the handler invoked when this thread abruptly terminates
30         * due to an uncaught exception.
31          **/
32         Thread.currentThread().setUncaughtExceptionHandler(this);
33         // 获取系统默认的UncaughtException处理器
34         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
35         this.mContext = context;
36     }
37
38     @Override
39     public void uncaughtException(Thread t, Throwable ex) {
40         Log.e(TAG, "到拦截闪退信息");
41     }
42
43 }

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

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

2.2 收集闪退信息

  这样每次崩溃的时候都会进入uncaughtException(),这个时候我们只需要收集信息写入本地文件就好了,收集的信息肯定需要包含好几个部分:当前崩溃信息,当前应用的版本信息,当前手机的信息,有的时候我们还需要其他部分,这里大概就只收集这三部分。为什么收集收集手机信息呢?因为有的时候是由于某些特定手机引起的Bug,若怪罪下来的话我们要甩锅给他。

  1  @Override
  2     public void uncaughtException(Thread t, Throwable ex) {
  3         Log.e(TAG, "捕捉到了异常");
  4         // 1. 获取信息
  5         // 1.1 崩溃信息
  6         // 1.2 手机信息
  7         // 1.3 版本信息
  8         // 2.写入文件
  9         String crashFileName = saveInfoToSD(ex);
 10
 11         Log.e(TAG, "fileName --> " + crashFileName);
 12
 13         // 3. 缓存崩溃日志文件
 14         cacheCrashFile(crashFileName);
 15         // 系统默认处理
 16         mDefaultHandler.uncaughtException(t, ex);
 17     }
 18
 19     /**
 20      * 缓存崩溃日志文件
 21      *
 22      * @param fileName
 23      */
 24     private void cacheCrashFile(String fileName) {
 25         SharedPreferences sp = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE);
 26         sp.edit().putString("CRASH_FILE_NAME", fileName).commit();
 27     }
 28
 29
 30     /**
 31      * 获取崩溃文件名称
 32      *
 33      * @return
 34      */
 35     public File getCrashFile() {
 36         String crashFileName = mContext.getSharedPreferences("crash",
 37                 Context.MODE_PRIVATE).getString("CRASH_FILE_NAME", "");
 38         return new File(crashFileName);
 39     }
 40
 41     /**
 42      * 保存获取的 软件信息,设备信息和出错信息保存在SDcard中
 43      *
 44      * @param ex
 45      * @return
 46      */
 47     private String saveInfoToSD(Throwable ex) {
 48         String fileName = null;
 49         StringBuffer sb = new StringBuffer();
 50
 51         for (Map.Entry<String, String> entry : obtainSimpleInfo(mContext)
 52                 .entrySet()) {
 53             String key = entry.getKey();
 54             String value = entry.getValue();
 55             sb.append(key).append(" = ").append(value).append("\n");
 56         }
 57
 58         sb.append(obtainExceptionInfo(ex));
 59
 60         if (Environment.getExternalStorageState().equals(
 61                 Environment.MEDIA_MOUNTED)) {
 62             File dir = new File(mContext.getFilesDir() + File.separator + "crash"
 63                     + File.separator);
 64
 65             // 先删除之前的异常信息
 66             if (dir.exists()) {
 67                 deleteDir(dir);
 68             }
 69
 70             // 再从新创建文件夹
 71             if (!dir.exists()) {
 72                 dir.mkdir();
 73             }
 74             try {
 75                 fileName = dir.toString()
 76                         + File.separator
 77                         + getAssignTime("yyyy_MM_dd_HH_mm") + ".txt";
 78                 FileOutputStream fos = new FileOutputStream(fileName);
 79                 fos.write(sb.toString().getBytes());
 80                 fos.flush();
 81                 fos.close();
 82             } catch (Exception e) {
 83                 e.printStackTrace();
 84             }
 85         }
 86         return fileName;
 87     }
 88
 89     /**
 90     * 返回当前日期根据格式
 91     **/
 92     private String getAssignTime(String dateFormatStr) {
 93         DateFormat dataFormat = new SimpleDateFormat(dateFormatStr);
 94         long currentTime = System.currentTimeMillis();
 95         return dataFormat.format(currentTime);
 96     }
 97
 98
 99     /**
100      * 获取一些简单的信息,软件版本,手机版本,型号等信息存放在HashMap中
101      *
102      * @return
103      */
104     private HashMap<String, String> obtainSimpleInfo(Context context) {
105         HashMap<String, String> map = new HashMap<>();
106         PackageManager mPackageManager = context.getPackageManager();
107         PackageInfo mPackageInfo = null;
108         try {
109             mPackageInfo = mPackageManager.getPackageInfo(
110                     context.getPackageName(), PackageManager.GET_ACTIVITIES);
111         } catch (PackageManager.NameNotFoundException e) {
112             e.printStackTrace();
113         }
114         map.put("versionName", mPackageInfo.versionName);
115         map.put("versionCode", "" + mPackageInfo.versionCode);
116         map.put("MODEL", "" + Build.MODEL);
117         map.put("SDK_INT", "" + Build.VERSION.SDK_INT);
118         map.put("PRODUCT", "" + Build.PRODUCT);
119         map.put("MOBLE_INFO", getMobileInfo());
120         return map;
121     }
122
123
124     /**
125      * Cell phone information
126      *
127      * @return
128      */
129     public static String getMobileInfo() {
130         StringBuffer sb = new StringBuffer();
131         try {
132             Field[] fields = Build.class.getDeclaredFields();
133             for (Field field : fields) {
134                 field.setAccessible(true);
135                 String name = field.getName();
136                 String value = field.get(null).toString();
137                 sb.append(name + "=" + value);
138                 sb.append("\n");
139             }
140         } catch (Exception e) {
141             e.printStackTrace();
142         }
143         return sb.toString();
144     }
145
146
147     /**
148      * 获取系统未捕捉的错误信息
149      *
150      * @param throwable
151      * @return
152      */
153     private String obtainExceptionInfo(Throwable throwable) {
154         StringWriter stringWriter = new StringWriter();
155         PrintWriter printWriter = new PrintWriter(stringWriter);
156         throwable.printStackTrace(printWriter);
157         printWriter.close();
158         return stringWriter.toString();
159     }
160
161
162     /**
163      * 递归删除目录下的所有文件及子目录下所有文件
164      *
165      * @param dir 将要删除的文件目录
166      * @return boolean Returns "true" if all deletions were successful. If a
167      * deletion fails, the method stops attempting to delete and returns
168      * "false".
169      */
170     private boolean deleteDir(File dir) {
171         if (dir.isDirectory()) {
172             String[] children = dir.list();
173             // 递归删除目录中的子目录下
174             for (int i = 0; i < children.length; i++) {
175                 boolean success = deleteDir(new File(dir, children[i]));
176                 if (!success) {
177                     return false;
178                 }
179             }
180         }
181         // 目录此时为空,可以删除
182         return true;
183     }

保存的路径最好不要在用户的外部存储卡中,因为6.0的时候如果访问外部存储卡需要动态的申请权限,那这个时候信息是获取到了但是GG。都蹦了还拖着我不放,还需要申请权限,纳尼???

2.2 上传闪退信息

每次启动应用的时候就获取上次闪退的信息日志,然后上传到服务器。

public class MainActivity extends BaseActivity {@Overrideprotected void initData() {// 获取上次的崩溃信息File crashFile = ExceptionCrashHandler.getInstance().getCrashFile();// 上传到服务器,后面再说.......
    }@Overrideprotected void initView() {}@Overrideprotected void setContentView() {setContentView(R.layout.activity_main);}@Overrideprotected void initTitle() {}
}

http://www.cnblogs.com/ganchuanpu/p/8196771.html

Android热修复之 - 收集崩溃信息上传服务器相关推荐

  1. Android实时监听短信并上传服务器

    短信监听 Android监听手机短信的方法有两种,分别为: 1.接受系统的短信广播:当手机收到新消息时,会发送一条广播,通过该广播就可以获取短信内容: 2.监听短信数据库:利用观察者模式监听短信数据库 ...

  2. 网页信息上传服务器,Unity 连接网页服务器 获取数据上传数据

    usingLitJson;usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usin ...

  3. 信息上传服务器加速cpu处理,英特尔发布全新第二代至强可扩展处理器携手浪潮加速新型应用发展...

    原标题:英特尔发布全新第二代至强可扩展处理器携手浪潮加速新型应用发展 近日,英特尔发布了提供更高性能.更好的性价比选择的 全新第二代英特尔®至强可扩展处理器,通过增加核心数量.提高缓存或提升处理器频率 ...

  4. 信息上传服务器加速cpu处理,业界首款PCIe 4.0服务器处理器为数据中心加速

    曾经,在服务器CPU市场Intel一家独大,但过去两年,AMD凭借空前成功的"Zen"核心,以代号为Naples的EPYC(霄龙)处理器强势杀入,从最大的云环境到AI应用领域,再到 ...

  5. Android热修复之 阿里开源的热补丁

    1.概述   上一期讲到Android热修复之 - 收集崩溃信息上传至服务器,我们获取到用户手中上线的崩溃信息上传到服务器后该怎么办?如果直接发布版本要用户去下载肯定不乐意.这一期我们来看一下怎么去打 ...

  6. 破解微信数据库 并查询数据上传服务器

    由于工作需求破解了微信的数据库 并获取想要的信息上传服务器 都是内部手机 网上大神反编译了微信 发现微信的数据库是通过 手机的IMEI(唯一识别码) + UIN 大写的IMEI + UIN 进行MD5 ...

  7. Android热修复技术选型参考

    背景 热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷. 热修复技术对比 1.公司角度 大致可以分为阿里系和腾讯系和其他,如下: 阿里系 Dexposed ...

  8. 微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录

    2019独角兽企业重金招聘Python工程师标准>>> 微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录 来源:微信技术团队的公众号WeMobileDev 热 ...

  9. android热补丁作用,Android热修复之 - 阿里开源的热补丁

    这里就有一个概念那就AndFix.apatch补丁用来修复方法,接下来我们看看到底是怎么实现的. 1.2 生成apatch包 假如我们收到了用户上传的崩溃信息,我们改完需要修复的Bug,这个时候就会有 ...

最新文章

  1. 2021年大数据Spark(十八):Spark Core的RDD Checkpoint
  2. pureftpd + pureftp-user-manager 构建磁盘配额,速率限制,web管理ftpserver
  3. 'eval' is null or not an object
  4. 如何打赢一场唯快不破的比赛,看看他们的绝招
  5. 数据集标注工具_如何提高数据标注质量,提供精细化标注数据集?丨曼孚科技...
  6. Oracle “TNS-12535: TNS: 操作超时“故障的解除。
  7. 基于安卓手机的辅助驾驶APP开发
  8. 任正非:不向美国人民学习他们的伟大,就永远战胜不了美国
  9. azure 使用_如何使用JavaScript在Azure上开始使用SignalR
  10. cookie——登录注册极简版
  11. 5G 消息绝地求生:盘活短信 VS 击垮微信?
  12. 【GNN】一文读懂图卷积GCN
  13. symantec病毒服务器的部署及配置
  14. python修改app定位_APP自动化中三大定位工具
  15. ESD笔记(三)_常用ESD保护电路优缺点
  16. 鸿蒙和小米哪个值得入手,鸿蒙系统能够吸引小米的优势是什么
  17. Python量化交易平台开发教程系列7-顶层GUI界面开发(1)
  18. latex 分布符号_LaTeX最全的数学符号大全(更新中…… )
  19. 科普:蓝绿部署、金丝雀发布(灰度发布)、A/B测试
  20. RocketMQ-Retry

热门文章

  1. linux下ioctl遇到的坑
  2. 【荐】中国最有潜力的十位企业家(IT行业占大半)
  3. ORACLE常见问题一千问[501至600](不怕学不成、就怕心不诚!)
  4. 剪刀、石头、布机器人比赛
  5. 吴恩达 coursera AI 专项二第三课总结+作业答案
  6. mySQL(关系型数据库管理系统)编辑
  7. 心电图多少为正常范围_研究:心跳超过70次/分,至少减寿3年!正常心率范围是多少?...
  8. USTC English Club Note20171023
  9. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170401
  10. 赋值运算符函数严谨性的几点思考