Android热修复之 - 收集崩溃信息上传服务器
1.概述
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热修复之 - 收集崩溃信息上传服务器相关推荐
- Android实时监听短信并上传服务器
短信监听 Android监听手机短信的方法有两种,分别为: 1.接受系统的短信广播:当手机收到新消息时,会发送一条广播,通过该广播就可以获取短信内容: 2.监听短信数据库:利用观察者模式监听短信数据库 ...
- 网页信息上传服务器,Unity 连接网页服务器 获取数据上传数据
usingLitJson;usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usin ...
- 信息上传服务器加速cpu处理,英特尔发布全新第二代至强可扩展处理器携手浪潮加速新型应用发展...
原标题:英特尔发布全新第二代至强可扩展处理器携手浪潮加速新型应用发展 近日,英特尔发布了提供更高性能.更好的性价比选择的 全新第二代英特尔®至强可扩展处理器,通过增加核心数量.提高缓存或提升处理器频率 ...
- 信息上传服务器加速cpu处理,业界首款PCIe 4.0服务器处理器为数据中心加速
曾经,在服务器CPU市场Intel一家独大,但过去两年,AMD凭借空前成功的"Zen"核心,以代号为Naples的EPYC(霄龙)处理器强势杀入,从最大的云环境到AI应用领域,再到 ...
- Android热修复之 阿里开源的热补丁
1.概述 上一期讲到Android热修复之 - 收集崩溃信息上传至服务器,我们获取到用户手中上线的崩溃信息上传到服务器后该怎么办?如果直接发布版本要用户去下载肯定不乐意.这一期我们来看一下怎么去打 ...
- 破解微信数据库 并查询数据上传服务器
由于工作需求破解了微信的数据库 并获取想要的信息上传服务器 都是内部手机 网上大神反编译了微信 发现微信的数据库是通过 手机的IMEI(唯一识别码) + UIN 大写的IMEI + UIN 进行MD5 ...
- Android热修复技术选型参考
背景 热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷. 热修复技术对比 1.公司角度 大致可以分为阿里系和腾讯系和其他,如下: 阿里系 Dexposed ...
- 微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录
2019独角兽企业重金招聘Python工程师标准>>> 微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录 来源:微信技术团队的公众号WeMobileDev 热 ...
- android热补丁作用,Android热修复之 - 阿里开源的热补丁
这里就有一个概念那就AndFix.apatch补丁用来修复方法,接下来我们看看到底是怎么实现的. 1.2 生成apatch包 假如我们收到了用户上传的崩溃信息,我们改完需要修复的Bug,这个时候就会有 ...
最新文章
- 2021年大数据Spark(十八):Spark Core的RDD Checkpoint
- pureftpd + pureftp-user-manager 构建磁盘配额,速率限制,web管理ftpserver
- 'eval' is null or not an object
- 如何打赢一场唯快不破的比赛,看看他们的绝招
- 数据集标注工具_如何提高数据标注质量,提供精细化标注数据集?丨曼孚科技...
- Oracle “TNS-12535: TNS: 操作超时“故障的解除。
- 基于安卓手机的辅助驾驶APP开发
- 任正非:不向美国人民学习他们的伟大,就永远战胜不了美国
- azure 使用_如何使用JavaScript在Azure上开始使用SignalR
- cookie——登录注册极简版
- 5G 消息绝地求生:盘活短信 VS 击垮微信?
- 【GNN】一文读懂图卷积GCN
- symantec病毒服务器的部署及配置
- python修改app定位_APP自动化中三大定位工具
- ESD笔记(三)_常用ESD保护电路优缺点
- 鸿蒙和小米哪个值得入手,鸿蒙系统能够吸引小米的优势是什么
- Python量化交易平台开发教程系列7-顶层GUI界面开发(1)
- latex 分布符号_LaTeX最全的数学符号大全(更新中…… )
- 科普:蓝绿部署、金丝雀发布(灰度发布)、A/B测试
- RocketMQ-Retry
热门文章
- linux下ioctl遇到的坑
- 【荐】中国最有潜力的十位企业家(IT行业占大半)
- ORACLE常见问题一千问[501至600](不怕学不成、就怕心不诚!)
- 剪刀、石头、布机器人比赛
- 吴恩达 coursera AI 专项二第三课总结+作业答案
- mySQL(关系型数据库管理系统)编辑
- 心电图多少为正常范围_研究:心跳超过70次/分,至少减寿3年!正常心率范围是多少?...
- USTC English Club Note20171023
- 学长毕业日记 :本科毕业论文写成博士论文的神操作20170401
- 赋值运算符函数严谨性的几点思考