获取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);
}
}
最后权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
完成
参考于:https://blog.csdn.net/urmytch/article/details/53642945
获取Android崩溃crash信息并写入日志发送邮件的更多相关文章
- 获取 Android APP 版本信息工具类(转载)
获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...
- 常用获取Android崩溃日志和IOS崩溃日志的几种方法
一:前言 在日常测试app时,经常会遇到崩溃问题,测试快速抓取到崩溃日志可以有效方便开发进行定位,快速解决问题所在测试做到测试分析,定位是非常重要的,这也是判断一个测试能力指标的一大维度. 二:And ...
- android 之 Crash信息的持久化处理
需求: 持久化运行时异常的信息 1.CrashHandler.java import android.content.Context; import android.content.pm.Packag ...
- 使用CrashHandler来获取应用的crash信息
源码地址https://github.com/king1039/android-art-res/tree/master/Chapter_13/CrashTest/src/com/ryg/crashte ...
- Windows Phone & Windows App应用程序崩溃crash信息抓取方法
最近有用户反馈,应用有崩溃的情况,可是本地调试却无法重现问题,理所当然的,我想到了微软的开发者仪表盘,可以查看一段时间内的carsh记录,不过仪表盘生成carsh记录不是实时的,而且生成的报告查看非常 ...
- 获取android手机联系人信息
package com.yarin.android.Examples_04_04; import android.app.Activity; import android.database.Curso ...
- 获取Android系统应用信息
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- java--何时处理Exception(哪一个层级),包装的基础类处理任务尽可能简洁,写入日志,检查null等运行时异常
1. 运行时异常和受检异常 2. 提前预防运行时异常.最常发生的是NPE,而检查NPE是程序员的基本职责.其他的,如除0等运行时异常的检查,需要程序员仔细检查,每个函数都得检查(除非可以确定不会有空指 ...
- (转)获取android手机内部存储空间和外部存储空间的参数 && 如何决定一个apk的安装位置
转:http://blog.csdn.net/zhandoushi1982/article/details/8560233 获取android文件系统的信息,需要Environment类和StatFs ...
随机推荐
- 201871010136—赵艳强《面向对象程序设计(java)》第十三周学习总结
201871010136—赵艳强<面向对象程序设计(java)>第十三周学习总结 博文正文开头格式:(2分) 项目 内容 <面向对象程序设计(java)> https:// ...
- Oracle告Google输了
Oracle告Google输了 boxi • 2016-05-27 • 大公司 Google表示,陪审团的认定代表了Android生态体系.Java开发社区以及依靠开放免费编程语言开发创新消费者产品的 ...
- Python 包:
分享一波油藏描述方面的Python开源包 前一阵去捷克参加了数学地质年会(IAMG2018),听完汇报,发现在数学地质领域用python的越来越多了,他们的很多成果都是用python做出来的.不管喜不 ...
- oracle sql语言模糊查询
'^' 匹配输入字符串的开始位置,在方括号表达式中使用,此时它表示不接受该字符集合.'$' 匹配输入字符串的结尾位置.如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n ...
- Large Margin Softmax Loss for Speaker Verification
[INTERSPEECH 2019接收] 链接:https://arxiv.org/pdf/1904.03479.pdf 这篇文章在会议的speaker session中.本文主要讨论了说话人验证中的 ...
- 4.Vue双向绑定
1.什么是双向数据绑定 Vue.js 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化.这也算是 Vue.js 的精髓之处了 ...
- vue_02day
目录 vue_02 表单指令: 条件指令: 循环指令: 前端数据库: 分隔符: 过滤器: 计算属性: 监听属性: vue编译不生效,闪烁 冒泡排序: vue_02 表单指令: <form act ...
- [LeetCode] 367. Valid Perfect Square 检验完全平方数
Given a positive integer num, write a function which returns True if num is a perfect square else Fa ...
- dogcom在openwrt上的使用
前提,先配置并运行mentohust(作为802.1x认证) 1,取得编译完成的可执行文件(可先在虚拟机里测试) 2,上传到路由器 3,把dogcom主程序和配置文件放在/etc/storage/do ...
- 通过欧拉计划学习Rust编程(第22~25题)
最近想学习Libra数字货币的MOVE语言,发现它是用Rust编写的,所以先补一下Rust的基础知识.学习了一段时间,发现Rust的学习曲线非常陡峭,不过仍有快速入门的办法. 学习任何一项技能最怕没有 ...