前段时间做过一个反馈应用程序Bug的程序,今天和大家分享下
如果想要获取应用程序的出错信息则比较简单,只需要通过实现 UncaughtExceptionHandler就可以达到目的,那么如何获取Android OS 所有应用程序的出错信息,目前的方式只有通过修改框架层来达到此目的。
(一)首先,我们先来看如何获取应用程序的出错信息:
A) 继承UncaughtExceptionHandler的类
- 1.package org.winplus.getex;
- 2.
- 3.import java.lang.Thread.UncaughtExceptionHandler;
- 4.
- 5.import Android.content.Context;
- 6.import android.os.Looper;
- 7.import android.util.Log;
- 8.import android.widget.Toast;
- 9.
- 10.public class CrashHandler implements UncaughtExceptionHandler {
- 11.
- 12. private final static String TAG = "UncaughtExceptionHandler";
- 13. private Thread.UncaughtExceptionHandler mDefaultHandler;
- 14. private static CrashHandler mInstance;
- 15. private Context mContext;
- 16. private CrashHandler() {
- 17. }
- 18.
- 19. /** 获取CrashHandler实例 ,单例模式 */
- 20. public static CrashHandler getInstance() {
- 21. if (mInstance == null)
- 22. mInstance = new CrashHandler();
- 23. return mInstance;
- 24. }
- 25.
- 26. @Override
- 27. public void uncaughtException(Thread thread, Throwable throwable) {
- 28. if (!handleException(throwable) && mDefaultHandler != null) {
- 29. // 如果用户没有处理则让系统默认的异常处理器来处理
- 30. mDefaultHandler.uncaughtException(thread, throwable);
- 31. } else {
- 32. // Sleep一会后结束程序
- 33. // 来让线程停止一会是为了显示Toast信息给用户,然后Kill程序
- 34. try {
- 35. Thread.sleep(3000);
- 36. } catch (InterruptedException e) {
- 37. Log.e(TAG, "Error : ", e);
- 38. }
- 39. android.os.Process.killProcess(android.os.Process.myPid());
- 40. System.exit(10);
- 41. }
- 42. }
- 43.
- 44. private boolean handleException(Throwable ex) {
- 45. if (ex == null) {
- 46. return true;
- 47. }
- 48. final String msg = ex.getLocalizedMessage();
- 49. // 使用Toast来显示异常信息
- 50. new Thread() {
- 51. @Override
- 52. public void run() {
- 53. // Toast 显示需要出现在一个线程的消息队列中
- 54. Looper.prepare();
- 55. Toast.makeText(mContext, "Exception:" + msg, Toast.LENGTH_LONG).show();
- 56. Looper.loop();
- 57. }
- 58. }.start();
- 59. return true;
- 60. }
- 61.
- 62. public void init(Context context) {
- 63. mContext = context;
- 64. mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- 65. Thread.setDefaultUncaughtExceptionHandler(this);
- 66. }
- 67.
- 68.
- 69.}
B) 初始化并启动获取异常的线程类:CrashApplication
- 1.import Android.app.Application;
- 2.
- 3.public class CrashApplication extends Application {
- 4.
- 5. @Override
- 6. public void onCreate() {
- 7. super.onCreate();
- 8.
- 9. CrashHandler crashHandler = CrashHandler.getInstance();
- 10. // 注册crashHandler
- 11. crashHandler.init(getApplicationContext());
- 12. }
- 13.}
C) 记得修改Manifest.xml文件~~~
D) 写一个用于测试的Activity
- 1.public class GetExceptionActivity extends Activity {
- 2. @Override
- 3. public void onCreate(Bundle savedInstanceState) {
- 4. super.onCreate(savedInstanceState);
- 5. setContentView(R.layout.main);
- 6.
- 7. int i = 1/0;//除数不能为0 这里会抛出异常
- 8. }
- 9.}
(二)获取AndroidOS应用程序所有出错信息的思路
获取应用程序异常的方法我们介绍过了,网上也有很多例子。下面来进入这边文章的重点,说是重点,其实也不难。我们的目的是通过修改最少的代码来获取系统中所有应用程序出错的信息:修改框架层ActivityManagerService类(如果不是特殊的要求,非常不建议修改框架层,当然我们在这里要修改的东西不会影响到什么)
|
系统出错时一般会弹出一个Dialog,这个Dialog是由frameworks\base\services\java\com\Android\server\am\ActivityManagerService.java弹出的,具体的Dialog是frameworks\base\services\java\com\android\server\am\AppErrorDialog.java,所以在这里我们只需要将这个AppErrorDialog改掉,或者在AppErrorDialog中添加一个按钮用于来反馈出错信息的功能,简单的说就是在AppErrorDialog中添加一个按钮,这个按钮通过Intent打开相应的应用程序,并将错误信息发送到应用程序的Activity。
这里主要给出一个思路吧。
三)发送邮件
最后,如何发送邮件呢?Android有几种发送邮件的方式,一种是直接调用系统的邮件,第二种是通过Java Mail的方式发送邮件,第一种并不是我们所需要的,要通过javaMail发送邮件,但Android如何通过JavaMail的方式发送邮件呢?很好,以及有哥们帮我们做了,请看这个:http://code.google.com/p/javamail-android/,只需要下载下面3个Jar包即可:additionnal.jar mail.jar activation.jar
- 1.public class MailTool {
- 2.
- 3. public static void sendMail(String subject, String content) throws MessagingException {
- 4. Properties props = new Properties();
- 5. props.put("mail.smtp.host", "mail.sina.cn");// 存储发送邮件服务器的信息
- 6. props.put("mail.smtp.auth", "true");// 同时通过验证
- 7.
- 8. // 基本的邮件会话
- 9. Session session = Session.getInstance(props);
- 10. session.setDebug(true);// 设置调试标志
- 11. // 构造信息体
- 12. MimeMessage message = new MimeMessage(session);
- 13.
- 14. // 发件地址
- 15. Address fromAddress = null;
- 16. fromAddress = new InternetAddress("[email protected]");
- 17.
- 18. message.setFrom(fromAddress);
- 19.
- 20. // 收件地址
- 21. Address toAddress = new InternetAddress("[email protected]");
- 22. message.addRecipient(Message.RecipientType.TO, toAddress);
- 23.
- 24. // 解析邮件内容
- 25. message.setSubject(subject);// 设置信件的标题
- 26. message.setText(content);// 设置信件内容
- 27. message.saveChanges(); // implicit with send()//存储信息
- 28.
- 29. // send e-mail message
- 30. Transport transport = null;
- 31. transport = session.getTransport("smtp");
- 32. transport.connect("mail.sina.cn", "[email protected]", "winplus.org");
- 33.
- 34. transport.sendMessage(message, message.getAllRecipients());
- 35. transport.close();
- 36. }
- 37.
- 38.}
发送邮件时一定要注意属性值得设置,不同的邮件服务器有不同的设置,要想实现发送gmail,yahoo等邮箱的发送接收,需要正确的设置,当时就纠结了很久!至于怎么设置,可以先在foxmail中进行设置,看属性就好了。
比如说需要发送接收gmail的邮件,要进行一下设置
- Properties props = new Properties();
- 2. props.setProperty("mail.transport.protocol", "smtp");
- 3. props.setProperty("mail.host", "smtp.gmail.com");
- 4. props.put("mail.smtp.auth", "true");
- 5. props.put("mail.smtp.port", "465");
- 6. props.put("mail.smtp.socketFactory.port", "465");
- 7. props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
- 8. props.put("mail.smtp.socketFactory.fallback", "false");
- 9. props.setProperty("mail.smtp.quitwait", "false");