好几年没写博客了,还是大学生的时候记录过很多学习Android时候遇到的问题以及解决方案。转眼3,4年过去了,前段时间看了看自己以前写的博客,发现水准比较低,所以把以前的博客都给删了,这也间接说明自己成长了许多。本人文采不咋样,所以废话不多说,今天给大家带来一个小工具,一般我们做的App上线后都会去收集客户端崩溃的日志,有很多第三方帮我们做了这个工具,从各种维度进行了分析,但这种一般作为开发者不会去看的,运营专员才会去看。开发讲究的就是立马通知我哪里哪里出问题了,马上修改,好了,那我们就借助java发送邮件的功能在Android中集成一个崩溃信息邮件通知功能吧。
一、准备java发送邮件所需要的jar包
二、建立Android项目
这里只简单介绍几个重要的类
1、自己的Application代码片段
@Override
public void onCreate()
{
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler(getApplicationContext()));
}
2、全局异常类
package com.android.exception2email;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.xml.sax.Attributes;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.sax.Element;
import android.sax.ElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.util.Xml;
/**
* 全局异常处理
* @author hiphonezhu@gmail.com
* @version [2014-6-25]
*/
public final class GlobalExceptionHandler implements
Thread.UncaughtExceptionHandler
{
private static final String SMTP_SINA_COM = "smtp.sina.com";
private static final String LINE_SEPARATOR = System
.getProperty("line.separator");
private Thread.UncaughtExceptionHandler defaultHandler;
private boolean caughtException = false;
private String clientInfo;
private Context appContext;
/**
* 全局错误处理构造函数
*/
public GlobalExceptionHandler(Context appContext)
{
this.appContext = appContext;
this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 收集客户端信息
this.clientInfo = collectClientInfo();
loadEmails();
}
private List<AccountInfo> fromEmailList = new ArrayList<AccountInfo>();
private List<String> toEmailList = new ArrayList<String>();
private AccountInfo mailInfo = null;
/**
* 读取邮件列表信息
*/
private void loadEmails()
{
try
{
InputStream is = appContext.getAssets().open("emails.xml");
RootElement document = new RootElement("addrs");
Element fromList = document.getChild("from-list");
Element itemFrom = fromList.getChild("item");
itemFrom.setElementListener(new ElementListener()
{
@Override
public void end()
{
fromEmailList.add(mailInfo);
}
@Override
public void start(Attributes attributes)
{
mailInfo = new AccountInfo();
}
});
itemFrom.getChild("account").setEndTextElementListener(new EndTextElementListener()
{
@Override
public void end(String body)
{
mailInfo.setAccount(body);
}
});
itemFrom.getChild("password").setEndTextElementListener(new EndTextElementListener()
{
@Override
public void end(String body)
{
mailInfo.setPassword(body);
}
});
Element toList = document.getChild("to-list");
Element itemTo = toList.getChild("item");
itemTo.setEndTextElementListener(new EndTextElementListener()
{
@Override
public void end(String body)
{
toEmailList.add(body);
}
});
Xml.parse(new InputStreamReader(is), document.getContentHandler());
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 返回版本号
* @return
*/
public String getVerName()
{
String verName = "";
try
{
verName = appContext.getPackageManager().getPackageInfo(appContext.getPackageName(),
0).versionName;
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
return verName;
}
/**
* 返回包名
* @return
*/
public String getPackageName()
{
return appContext.getPackageName();
}
/**
* 捕获到异常
*
* @param thread 异常线程
* @param throwable 异常信息
*/
@Override
public void uncaughtException(final Thread thread, final Throwable throwable)
{
if (caughtException)
{
defaultHandler.uncaughtException(thread,
throwable);
return;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
throwable.printStackTrace(ps);
final String errorMsg = new String(baos.toByteArray());
final String mailContent = errorMsg + LINE_SEPARATOR + LINE_SEPARATOR
+ clientInfo;
// 将报错信息发送到指定的邮箱
Thread sendMailThread = new Thread()
{
@Override
public void run()
{
try
{
String subject = getPackageName() + "_v" + getVerName() + " Crash Report";
Properties props = new Properties();
props.put("mail.smtp.host",
SMTP_SINA_COM);
props.put("mail.smtp.auth",
"true");
MailUtil.MailInfo mailInfo = new MailUtil.MailInfo();
int index = (int) (Math.floor(Math
.random() * fromEmailList.size()));
AccountInfo info = fromEmailList.get(index);
mailInfo.setFrom(info.getAccount());
mailInfo.setPassword(info.getPassword());
mailInfo.setSmtpHost(SMTP_SINA_COM);
mailInfo.setNeedAuth(true);
String[] tos = new String[toEmailList.size()];
toEmailList.toArray(tos);
mailInfo.setToList(tos);
mailInfo.setSubject(subject);
mailInfo.setContent(mailContent);
try
{
MailUtil.sendMail(mailInfo);
}
catch (Exception e)
{
e.printStackTrace();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (!handleException() && defaultHandler != null)
{
defaultHandler.uncaughtException(thread, throwable);
}
}
}
};
sendMailThread.start();
}
/**
* 自定义错误处理、收集错误信息 、发送错误报告等操作均在此完成.
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException()
{
try
{
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
return true;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
private String collectClientInfo()
{
StringBuilder systemInfo = new StringBuilder();
systemInfo.append("CLIENT-INFO");
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Id: ");
systemInfo.append(Build.ID);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Display: ");
systemInfo.append(Build.DISPLAY);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Product: ");
systemInfo.append(Build.PRODUCT);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Device: ");
systemInfo.append(Build.DEVICE);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Board: ");
systemInfo.append(Build.BOARD);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("CpuAbility: ");
systemInfo.append(Build.CPU_ABI);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Manufacturer: ");
systemInfo.append(Build.MANUFACTURER);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Brand: ");
systemInfo.append(Build.BRAND);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Model: ");
systemInfo.append(Build.MODEL);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Type: ");
systemInfo.append(Build.TYPE);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Tags: ");
systemInfo.append(Build.TAGS);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("FingerPrint: ");
systemInfo.append(Build.FINGERPRINT);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Version.Incremental: ");
systemInfo.append(Build.VERSION.INCREMENTAL);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Version.Release: ");
systemInfo.append(Build.VERSION.RELEASE);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("SDK: ");
systemInfo.append(Build.VERSION.SDK);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("SDKInt: ");
systemInfo.append(Build.VERSION.SDK_INT);
systemInfo.append(LINE_SEPARATOR);
systemInfo.append("Version.CodeName: ");
systemInfo.append(Build.VERSION.CODENAME);
systemInfo.append(LINE_SEPARATOR);
String clientInfomation = systemInfo.toString();
systemInfo.delete(0, systemInfo.length());
return clientInfomation;
}
}
3、邮件发送辅助类
package com.android.exception2email;
import java.util.Date;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
* 邮件操作封装
* @author hiphonezhu@gmail.com
* @version [2014-6-25]
*/
public abstract class MailUtil
{
/**
* 发送邮件
*
* @param info 邮件信息
* @throws MessagingException MessagingException
*/
public static void sendMail(final MailInfo info) throws MessagingException
{
Properties props = new Properties();
props.put("mail.smtp.host",
info.getSmtpHost());
props.put("mail.smtp.auth",
String.valueOf(info.isNeedAuth()));
Session session = Session.getDefaultInstance(props,
new Authenticator()
{
@Override
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(info.getFrom(),
info.getPassword());
}
});
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(info.getFrom()));
InternetAddress[] address = new InternetAddress[info.getToList().length];
for (int i = 0; i < info.getToList().length; i++)
{
address[i] = new InternetAddress(info.getToList()[i]);
}
msg.setRecipients(Message.RecipientType.TO,
address);
Date current = new Date();
msg.setSubject(info.getSubject());
Multipart mp = new MimeMultipart();
MimeBodyPart mbpContent = new MimeBodyPart();
mbpContent.setText(info.getContent());
mp.addBodyPart(mbpContent);
msg.setContent(mp);
msg.setSentDate(current);
Transport.send(msg,
address);
}
/**
* 邮件信息
*/
public static class MailInfo
{
private String from;
private String password;
private String[] toList;
private String subject;
private String content;
private boolean needAuth;
private String smtpHost;
public String getFrom()
{
return from;
}
public void setFrom(String from)
{
this.from = from;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String[] getToList()
{
return toList;
}
public void setToList(String[] toList)
{
this.toList = toList;
}
public String getSubject()
{
return subject;
}
public void setSubject(String subject)
{
this.subject = subject;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public boolean isNeedAuth()
{
return needAuth;
}
public void setNeedAuth(boolean needAuth)
{
this.needAuth = needAuth;
}
public String getSmtpHost()
{
return smtpHost;
}
public void setSmtpHost(String smtpHost)
{
this.smtpHost = smtpHost;
}
}
}
4、邮件发送者和接受者列表(防止同一个账号发送多次邮件被服务器拒绝,这里我们尽量申请多个Email账号),xml文件可配置,增加灵活性
<?xml version="1.0" encoding="utf-8"?>
<addrs>
<from-list>
<item>
<account>xxx@xxx</account>
<password>xxx</password>
</item>
<item>
<account>xxx@xxx</account>
<password>xxx</password>
</item>
<item>
<account>xxx@xxx</account>
<password>xxx</password>
</item>
<item>
<account>xxx@xxx</account>
<password>xxx</password>
</item>
<item>
<account>xxx@xxx</account>
<password>xxx</password>
</item>
</from-list>
<to-list>
<item>xxx@xxx</item>
</to-list>
</addrs>
我们跑起来看看啊
点击崩溃,我的qq邮箱收到邮件了,信息还是比较全面的
总结:
1、引入这些jar包
2、新建emails.xml文件,内容见上下文
3、Application或其他地方加入代码
Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler(getApplicationContext()));
源码下载地址:http://download.csdn.net/detail/zhf198909/7550295
ps:emails.xml里面发送者账号请改成自己的哦