获取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 ...
随机推荐
- 17-numpy笔记-莫烦pandas-5
代码 import pandas as pd import numpy as np left=pd.DataFrame({'key':['K0','K1','K2','K3'], 'A':['A0', ...
- USACO Apple Delivery
洛谷 P3003 [USACO10DEC]苹果交货Apple Delivery 洛谷传送门 JDOJ 2717: USACO 2010 Dec Silver 1.Apple Delivery JDOJ ...
- Gym101002E:K-Inversions
\(Gym101002E:K-Inversions\) 题意描述: 题目连接链接 给定一个长度为\(N\)只包含\(AB\)的字符串,某个\(A\)的位置为\(j\),某个\(B\)的位置为\(i\) ...
- requests--超时设置,代理设置,身份认证
超时设置 你可以告诉 requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应.基本上所有的接口都应该使用这一参数.如果不使用,你的程序可能会永远失去响应 import requ ...
- Java 函数式编程(Lambda表达式)与Stream API
1 函数式编程 函数式编程(Functional Programming)是编程范式的一种.最常见的编程范式是命令式编程(Impera Programming),比如面向过程.面向对象编程都属于命令式 ...
- uniApp配置文件几个注意点
虽然有文档,但是偶尔还是会又找不到的,写下来遇到过的问题,随时补充.好记性不如烂笔头. 1.打包完安装之后,app 有时候会弹出一个提示框.如下: 修改配置项,设置 ignoreVersion 为 t ...
- multiply two numbers using + opertor
public class Solution { public static void main(String[] args) { , y = ; ; ; i <= y; i++) res = i ...
- Python __name__的使用
__name__是什么 * __开头代表是系统变量; * __name__ 是标识模块名字的系统变量. 当前模块是主模块时, 模块名就是"__main__"; 当模块是被调用(im ...
- Hanlp分词插件docker集群安装
背景:我是用docker-compose的方式装的es集群,正常情况es镜像没有插件,如果在docker里面用命令安装了那么重启以后又没了,所以采用挂载离线安装的方式 版本: es7.2 1下载Han ...
- windbg排查线上线程数爆炸问题
1.早上发现有个job的线程数一直居高不下 2.于是dump一个文件拉到本地,查到都在执行 StartInner方法 3.查询代码,此方法是个静态类开启线程的地方,理论上没有任何问题 4.思索了半天, ...