Android程序崩溃异常收集框架

来源:互联网 发布:java编写信息管理系统 编辑:程序博客网 时间:2024/05/16 10:28

最近在写Android程序崩溃异常处理,完成之后,稍加封装与大家分享。

我的思路是这样的,在程序崩溃之后,将异常信息保存到一个日志文件中,然后对该文件进行处理,比如发送到邮箱,或发送到服务器。

所以,第一步是先定义一个接口,用于在保存好日志之后的回调。代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)CrashListener.java              Project: crash 
  3.  * Date:2014-5-27 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import java.io.File;  
  24.   
  25. /** 
  26.  * @author Geek_Soledad <a target="_blank" href= 
  27.  *         "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" 
  28.  *         style="text-decoration:none;"><img src= 
  29.  *         "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" 
  30.  *         /></a> 
  31.  */  
  32. public interface CrashListener {  
  33.     /** 
  34.      * 保存异常的日志。 
  35.      *  
  36.      * @param file 
  37.      */  
  38.     public void afterSaveCrash(File file);  
  39. }  

接下来是用于处理崩溃异常的类,它要实现UncaughtExceptionHandler接口。实现它之后,将它设为默认的线程异常的处理者,这样程序崩溃之后,就会调用它了。但是在调用它之前,还需要先获取保存之前默认的handler,用于在我们收集了异常之后对程序进行处理,比如默认的弹出“程序已停止运行”的对话框(当然你也可以自己实现一个),终止程序,打印LOG。

我的实现如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)CrashHandler.java               Project: crash 
  3.  * Date:2014-5-26 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import java.io.File;  
  24. import java.lang.Thread.UncaughtExceptionHandler;  
  25. import java.util.concurrent.ExecutorService;  
  26. import java.util.concurrent.Executors;  
  27. import java.util.concurrent.Future;  
  28.   
  29. /** 
  30.  * @author Geek_Soledad <a target="_blank" href= 
  31.  *         "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" 
  32.  *         style="text-decoration:none;"><img src= 
  33.  *         "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" 
  34.  *         /></a> 
  35.  */  
  36. public class CrashHandler implements UncaughtExceptionHandler {  
  37.     private static final CrashHandler sHandler = new CrashHandler();  
  38.     private static final UncaughtExceptionHandler sDefaultHandler = Thread  
  39.             .getDefaultUncaughtExceptionHandler();  
  40.     private static final ExecutorService THREAD_POOL = Executors.newSingleThreadExecutor();  
  41.     private Future<?> future;  
  42.     private CrashListener mListener;  
  43.     private File mLogFile;  
  44.   
  45.     public static CrashHandler getInstance() {  
  46.         return sHandler;  
  47.     }  
  48.   
  49.     @Override  
  50.     public void uncaughtException(Thread thread, Throwable ex) {  
  51.         CrashLogUtil.writeLog(mLogFile, "CrashHandler", ex.getMessage(), ex);  
  52.         future = THREAD_POOL.submit(new Runnable() {  
  53.             public void run() {  
  54.                 if (mListener != null) {  
  55.                     mListener.afterSaveCrash(mLogFile);  
  56.                 }  
  57.             };  
  58.         });  
  59.         if (!future.isDone()) {  
  60.             try {  
  61.                 future.get();  
  62.             } catch (Exception e) {  
  63.                 e.printStackTrace();  
  64.             }  
  65.         }  
  66.         sDefaultHandler.uncaughtException(thread, ex);  
  67.     }  
  68.   
  69.     public void init(File logFile, CrashListener listener) {  
  70.         mLogFile = logFile;  
  71.         mListener = listener;  
  72.     }  
  73.   
  74. }  

这个类很简单,就是在发生未能捕获的异常之后,保存LOG到文件,然后 调用前面定义的接口,对日志文件进行处理。其中CrashLogUtil是我实现的保存LOG到文件的类。代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)LogUtil.java            Project: crash 
  3.  * Date:2014-5-27 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import java.io.BufferedWriter;  
  24. import java.io.Closeable;  
  25. import java.io.File;  
  26. import java.io.FileWriter;  
  27. import java.io.IOException;  
  28. import java.io.PrintWriter;  
  29. import java.text.SimpleDateFormat;  
  30. import java.util.Calendar;  
  31. import java.util.Locale;  
  32.   
  33. /** 
  34.  * @author Geek_Soledad <a target="_blank" href= 
  35.  *         "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" 
  36.  *         style="text-decoration:none;"><img src= 
  37.  *         "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" 
  38.  *         /></a> 
  39.  */  
  40. public class CrashLogUtil {  
  41.     private static final SimpleDateFormat timeFormat = new SimpleDateFormat("MM-dd HH:mm:ss.SSS",  
  42.             Locale.getDefault());  
  43.   
  44.     /** 
  45.      * 将日志写入文件。 
  46.      *  
  47.      * @param tag 
  48.      * @param message 
  49.      * @param tr 
  50.      */  
  51.     public static synchronized void writeLog(File logFile, String tag, String message, Throwable tr) {  
  52.         logFile.getParentFile().mkdirs();  
  53.         if (!logFile.exists()) {  
  54.             try {  
  55.                 logFile.createNewFile();  
  56.             } catch (IOException e) {  
  57.                 e.printStackTrace();  
  58.             }  
  59.         }  
  60.         String time = timeFormat.format(Calendar.getInstance().getTime());  
  61.         synchronized (logFile) {  
  62.             FileWriter fileWriter = null;  
  63.             BufferedWriter bufdWriter = null;  
  64.             PrintWriter printWriter = null;  
  65.             try {  
  66.                 fileWriter = new FileWriter(logFile, true);  
  67.                 bufdWriter = new BufferedWriter(fileWriter);  
  68.                 printWriter = new PrintWriter(fileWriter);  
  69.                 bufdWriter.append(time).append(" ").append("E").append('/').append(tag).append(" ")  
  70.                         .append(message).append('\n');  
  71.                 bufdWriter.flush();  
  72.                 tr.printStackTrace(printWriter);  
  73.                 printWriter.flush();  
  74.                 fileWriter.flush();  
  75.             } catch (IOException e) {  
  76.                 closeQuietly(fileWriter);  
  77.                 closeQuietly(bufdWriter);  
  78.                 closeQuietly(printWriter);  
  79.             }  
  80.         }  
  81.     }  
  82.   
  83.     public static void closeQuietly(Closeable closeable) {  
  84.         if (closeable != null) {  
  85.             try {  
  86.                 closeable.close();  
  87.             } catch (IOException ioe) {  
  88.                 // ignore  
  89.             }  
  90.         }  
  91.     }  
  92. }  

在日志保存之后,我们还需要生成一个报告,并发送给服务器。报告的方法,可以是发送到邮箱,或者http请求发送给服务器。所以这里写了一个抽象类,实现了生成标题和内容,设置日志路径等。代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)AbstractReportHandler.java              Project: crash 
  3.  * Date:2014-5-27 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import java.io.File;  
  24.   
  25. import android.content.Context;  
  26. import android.content.pm.ApplicationInfo;  
  27. import android.content.pm.PackageInfo;  
  28. import android.content.pm.PackageManager;  
  29. import android.os.Build;  
  30.   
  31. /** 
  32.  * @author Geek_Soledad <a target="_blank" href= 
  33.  *         "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" 
  34.  *         style="text-decoration:none;"><img src= 
  35.  *         "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" 
  36.  *         /></a> 
  37.  */  
  38. public abstract class AbstractCrashReportHandler implements CrashListener {  
  39.     private Context mContext;  
  40.   
  41.     public AbstractCrashReportHandler(Context context) {  
  42.         mContext = context;  
  43.         CrashHandler handler = CrashHandler.getInstance();  
  44.         handler.init(getLogDir(context), this);  
  45.         Thread.setDefaultUncaughtExceptionHandler(handler);  
  46.     }  
  47.   
  48.     protected File getLogDir(Context context) {  
  49.         return new File(context.getFilesDir(), "crash.log");  
  50.     }  
  51.   
  52.     protected abstract void sendReport(String title, String body, File file);  
  53.   
  54.     @Override  
  55.     public void afterSaveCrash(File file) {  
  56.         sendReport(buildTitle(mContext), buildBody(mContext), file);  
  57.     }  
  58.   
  59.     public String buildTitle(Context context) {  
  60.         return "Crash Log: "  
  61.                 + context.getPackageManager().getApplicationLabel(context.getApplicationInfo());  
  62.     }  
  63.   
  64.     public String buildBody(Context context) {  
  65.         StringBuilder sb = new StringBuilder();  
  66.   
  67.         sb.append("APPLICATION INFORMATION").append('\n');  
  68.         PackageManager pm = context.getPackageManager();  
  69.         ApplicationInfo ai = context.getApplicationInfo();  
  70.         sb.append("Application : ").append(pm.getApplicationLabel(ai)).append('\n');  
  71.   
  72.         try {  
  73.             PackageInfo pi = pm.getPackageInfo(ai.packageName, 0);  
  74.             sb.append("Version Code: ").append(pi.versionCode).append('\n');  
  75.             sb.append("Version Name: ").append(pi.versionName).append('\n');  
  76.         } catch (PackageManager.NameNotFoundException e) {  
  77.             e.printStackTrace();  
  78.         }  
  79.   
  80.         sb.append('\n').append("DEVICE INFORMATION").append('\n');  
  81.         sb.append("Board: ").append(Build.BOARD).append('\n');  
  82.         sb.append("BOOTLOADER: ").append(Build.BOOTLOADER).append('\n');  
  83.         sb.append("BRAND: ").append(Build.BRAND).append('\n');  
  84.         sb.append("CPU_ABI: ").append(Build.CPU_ABI).append('\n');  
  85.         sb.append("CPU_ABI2: ").append(Build.CPU_ABI2).append('\n');  
  86.         sb.append("DEVICE: ").append(Build.DEVICE).append('\n');  
  87.         sb.append("DISPLAY: ").append(Build.DISPLAY).append('\n');  
  88.         sb.append("FINGERPRINT: ").append(Build.FINGERPRINT).append('\n');  
  89.         sb.append("HARDWARE: ").append(Build.HARDWARE).append('\n');  
  90.         sb.append("HOST: ").append(Build.HOST).append('\n');  
  91.         sb.append("ID: ").append(Build.ID).append('\n');  
  92.         sb.append("MANUFACTURER: ").append(Build.MANUFACTURER).append('\n');  
  93.         sb.append("PRODUCT: ").append(Build.PRODUCT).append('\n');  
  94.         sb.append("TAGS: ").append(Build.TAGS).append('\n');  
  95.         sb.append("TYPE: ").append(Build.TYPE).append('\n');  
  96.         sb.append("USER: ").append(Build.USER).append('\n');  
  97.   
  98.         return sb.toString();  
  99.     }  
  100. }  

这样一个框架就算基本完成了。

当然,下面我还给出了报告的一种实现,发送邮件。

如何发送邮箱,网上已有不少资料,这里不再简而言之。

首先需要用到三个jar包: activation.jar, additionnal.jar, mail.jar。

然后 写一个类,继承自Authenticator。代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)Snippet.java            Project: CrashHandler 
  3.  * Date: 2014-5-27 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import android.util.Log;  
  24.   
  25. import java.util.Date;  
  26. import java.util.Properties;  
  27.   
  28. import javax.activation.CommandMap;  
  29. import javax.activation.DataHandler;  
  30. import javax.activation.DataSource;  
  31. import javax.activation.FileDataSource;  
  32. import javax.activation.MailcapCommandMap;  
  33. import javax.mail.Authenticator;  
  34. import javax.mail.BodyPart;  
  35. import javax.mail.MessagingException;  
  36. import javax.mail.Multipart;  
  37. import javax.mail.PasswordAuthentication;  
  38. import javax.mail.Session;  
  39. import javax.mail.Transport;  
  40. import javax.mail.internet.InternetAddress;  
  41. import javax.mail.internet.MimeBodyPart;  
  42. import javax.mail.internet.MimeMessage;  
  43. import javax.mail.internet.MimeMultipart;  
  44.   
  45. /** 
  46.  * Author: msdx (645079761@qq.com) Time: 14-5-27 上午9:07 
  47.  */  
  48. public class LogMail extends Authenticator {  
  49.     private String host;  
  50.     private String port;  
  51.     private String user;  
  52.     private String pass;  
  53.     private String from;  
  54.     private String to;  
  55.     private String subject;  
  56.     private String body;  
  57.   
  58.     private Multipart multipart;  
  59.     private Properties props;  
  60.   
  61.     public LogMail() {  
  62.     }  
  63.   
  64.     public LogMail(String user, String pass, String from, String to, String host, String port,  
  65.             String subject, String body) {  
  66.         this.host = host;  
  67.         this.port = port;  
  68.         this.user = user;  
  69.         this.pass = pass;  
  70.         this.from = from;  
  71.         this.to = to;  
  72.         this.subject = subject;  
  73.         this.body = body;  
  74.     }  
  75.   
  76.     public LogMail setHost(String host) {  
  77.         this.host = host;  
  78.         return this;  
  79.     }  
  80.   
  81.     public LogMail setPort(String port) {  
  82.         this.port = port;  
  83.         return this;  
  84.     }  
  85.   
  86.     public LogMail setUser(String user) {  
  87.         this.user = user;  
  88.         return this;  
  89.     }  
  90.   
  91.     public LogMail setPass(String pass) {  
  92.         this.pass = pass;  
  93.         return this;  
  94.     }  
  95.   
  96.     public LogMail setFrom(String from) {  
  97.         this.from = from;  
  98.         return this;  
  99.     }  
  100.   
  101.     public LogMail setTo(String to) {  
  102.         this.to = to;  
  103.         return this;  
  104.     }  
  105.   
  106.     public LogMail setSubject(String subject) {  
  107.         this.subject = subject;  
  108.         return this;  
  109.     }  
  110.   
  111.     public LogMail setBody(String body) {  
  112.         this.body = body;  
  113.         return this;  
  114.     }  
  115.   
  116.     public void init() {  
  117.         multipart = new MimeMultipart();  
  118.         // There is something wrong with MailCap, javamail can not find a  
  119.         // handler for the multipart/mixed part, so this bit needs to be added.  
  120.         MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();  
  121.         mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");  
  122.         mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");  
  123.         mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");  
  124.         mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");  
  125.         mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");  
  126.         CommandMap.setDefaultCommandMap(mc);  
  127.   
  128.         props = new Properties();  
  129.   
  130.         props.put("mail.smtp.host", host);  
  131.         props.put("mail.smtp.auth""true");  
  132.         props.put("mail.smtp.port", port);  
  133.         props.put("mail.smtp.socketFactory.port", port);  
  134.         props.put("mail.transport.protocol""smtp");  
  135.         props.put("mail.smtp.socketFactory.class""javax.net.ssl.SSLSocketFactory");  
  136.         props.put("mail.smtp.socketFactory.fallback""false");  
  137.     }  
  138.   
  139.     public boolean send() throws MessagingException {  
  140.         if (!user.equals("") && !pass.equals("") && !to.equals("") && !from.equals("")) {  
  141.             Session session = Session.getDefaultInstance(props, this);  
  142.             Log.d("SendUtil", host + "..." + port + ".." + user + "..." + pass);  
  143.   
  144.             MimeMessage msg = new MimeMessage(session);  
  145.   
  146.             msg.setFrom(new InternetAddress(from));  
  147.   
  148.             InternetAddress addressTo = new InternetAddress(to);  
  149.             msg.setRecipient(MimeMessage.RecipientType.TO, addressTo);  
  150.   
  151.             msg.setSubject(subject);  
  152.             msg.setSentDate(new Date());  
  153.   
  154.             // setup message body  
  155.             BodyPart messageBodyPart = new MimeBodyPart();  
  156.             messageBodyPart.setText(body);  
  157.             multipart.addBodyPart(messageBodyPart);  
  158.   
  159.             // Put parts in message  
  160.             msg.setContent(multipart);  
  161.   
  162.             // send email  
  163.             Transport.send(msg);  
  164.   
  165.             return true;  
  166.         } else {  
  167.             return false;  
  168.         }  
  169.     }  
  170.   
  171.     public void addAttachment(String filePath, String fileName) throws Exception {  
  172.         BodyPart messageBodyPart = new MimeBodyPart();  
  173.         DataSource source = new FileDataSource(filePath);  
  174.         messageBodyPart.setDataHandler(new DataHandler(source));  
  175.         messageBodyPart.setFileName(fileName);  
  176.         multipart.addBodyPart(messageBodyPart);  
  177.     }  
  178.   
  179.     @Override  
  180.     public PasswordAuthentication getPasswordAuthentication() {  
  181.         return new PasswordAuthentication(user, pass);  
  182.     }  
  183. }  
然后是发送报告邮件的类了,它继承自前面所写的AbstractCrashReportHandler,实现如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * @(#)CrashEmailReport.java               Project: CrashHandler 
  3.  * Date: 2014-5-27 
  4.  * 
  5.  * Copyright (c) 2014 CFuture09, Institute of Software,  
  6.  * Guangdong Ocean University, Zhanjiang, GuangDong, China. 
  7.  * All rights reserved. 
  8.  * 
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  10.  *  you may not use this file except in compliance with the License. 
  11.  * You may obtain a copy of the License at 
  12.  * 
  13.  *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, 
  17.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  18.  * See the License for the specific language governing permissions and 
  19.  * limitations under the License. 
  20.  */  
  21. package com.githang.android.crash;  
  22.   
  23. import java.io.File;  
  24.   
  25. import android.content.Context;  
  26.   
  27. /** 
  28.  * @author Geek_Soledad <a target="_blank" href= 
  29.  *         "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" 
  30.  *         style="text-decoration:none;"><img src= 
  31.  *         "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" 
  32.  *         /></a> 
  33.  */  
  34. public class CrashEmailReport extends AbstractCrashReportHandler {  
  35.     private String mReceiveEmail;  
  36.   
  37.     public CrashEmailReport(Context context) {  
  38.         super(context);  
  39.     }  
  40.   
  41.     public void setReceiver(String receiveEmail) {  
  42.         mReceiveEmail = receiveEmail;  
  43.     }  
  44.       
  45.     @Override  
  46.     protected void sendReport(String title, String body, File file) {  
  47.         LogMail sender = new LogMail().setUser("irain_log@163.com").setPass("xxxxxxxx")  
  48.                 .setFrom("irain_log@163.com").setTo(mReceiveEmail).setHost("smtp.163.com")  
  49.                 .setPort("465").setSubject(title).setBody(body);  
  50.         sender.init();  
  51.         try {  
  52.             sender.addAttachment(file.getPath(), file.getName());  
  53.             sender.send();  
  54.             file.delete();  
  55.         } catch (Exception e) {  
  56.             e.printStackTrace();  
  57.         }  
  58.     }  
  59. }  

这样,一个完整的程序崩溃异常框架就完成了。对于日志报告,可自己继承AbstractCrashReportHandler来扩展实现。

使用的时候,需要写一个继承自Application的类,在onCreate方法中加上如下代码,即设置接收邮箱。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. new CrashEmailReport(this).setReceiver("log@msdx.pw");  

然后在AndroidManifest.xml中配置这个类。

目前我已经把框架放在了github了,地址如下:https://github.com/msdx/android-crash


使用方法见github上面的README.md。

本项目相关jar包已发布在jcenter,如果你使用gradle构建工具,可以直接添加依赖,具体见项目的README.

0 0
原创粉丝点击