android App异常报错捕获后使用javamail登录QQ邮箱发邮件的功能遇到的问题

网上参照了网上的帖子 两种方式 走了很多弯路 有时候没有针对性的去解决问题 这个缺点要改正其实大致的流程很简单 这里梳理一下:

  一、捕获异常(单例模式注册CrashHandler 并且在handlerExcepiton中发送邮件)

二、设置邮件(1导入三个jar包1.1activation.jar 1.2mail.jar 1.3additionnal.jar )

三、发送邮件(1.密码改为授权码 2.去掉mail.smtp.auth)

四、使用了异常捕获之后 ,直接闪退 ,不弹框提示了,用户体验会好一点

1.gundumw100的博客 http://gundumw100.iteye.com/blog/1182104 来实现了异常捕获,使用的是服务器来接收错误文件的

2.然后又参照了 简书中BRYANB的文章 http://www.jianshu.com/p/ea210ef8b4b0 来实现异常捕获发送邮件的功能

之后发现报错 调试的时候发现报错 到验证密码时候报错 以为是写的有问题 然后去 Windy Wang 的博客 http://www.cnblogs.com/wangsx/archive/2013/08/30/3291036.html 修改了发送邮件的代码 发现还是报错

android App异常报错捕获后使用javamail登录QQ邮箱发邮件的功能遇到的问题

上网搜索后发现这位哥们儿http://www.iteye.com/problems/71677 问题和我的差不多 然后根据下面回答下载了https://code.google.com/archive/p/javamail-android/downloads 这里的三个包并且重新引入之后 还是报错

android App异常报错捕获后使用javamail登录QQ邮箱发邮件的功能遇到的问题

android.os.NetworkOnMainThreadException

然后看到这篇文章http://blog.csdn.net/mad1989/article/details/25964495 说3.0以后不推荐这种方法,开了线程去执行发送邮件还是报错com.sun.mail.smtp.SMTPAddressFailedException:

            到了这一步之后,可以去邮箱设置里面看看开启了了pop3/smtp没有,使用qq邮箱设置了还是报错,我就改换android App异常报错捕获后使用javamail登录QQ邮箱发邮件的功能遇到的问题

网易邮箱了,不论是网易邮箱还是QQ邮箱,邮箱都有个授权码,一定要用授权码来作为密码password = "";// 填写授权码猜到一定还会报错 然后参照了 http://bbs.csdn.net/topics/260074848 这里 去掉了//props.put("mail.smtp.auth", "true"); 把mail.auth=true去掉 然后就可以了

android App异常报错捕获后使用javamail登录QQ邮箱发邮件的功能遇到的问题

如果觉得邮件一直提醒比较烦的话可以发件和收件都为同一个人

源码:

一、发邮件工具类

package com.musicdo.puluo.utils;


import android.util.Log;


import java.util.Properties;


import javax.activation.DataHandler;
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.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;


/**
 * 名 称 :发邮件工具类
 * 描 述 :
 * 创建者:
 * 创建时间:
 * 版 本 :
 * 备 注 :
 */


public class EmailUtil {
    /**
     * 邮件发送程序
     *
     * @param to
     *            接受人
     * @param subject
     *            邮件主题
     * @param content
     *            邮件内容
     * @throws Exception
     * @throws MessagingException
     */
    public static void sendEmail(String to, String subject, String content) throws Exception, MessagingException {
        String host = "smtp.qq.com";
        String address = "[email protected]";
        String from = "AA@qq.com";
        String password = "aa";// 授权码
        if ("".equals(to) || to == null) {
            to = "[email protected]";
        }
        String port = "25";
        SendEmail(host, address, from, password, to, port, subject, content);
    }


    /**
     * 邮件发送程序
     *
     * @param host
     *            邮件服务器 如:smtp.qq.com
     * @param address
     *            发送邮件的地址 如:[email protected]
     * @param from
     *            来自: [email protected]
     * @param password
     *            您的邮箱密码
     * @param to
     *            接收人
     * @param port
     *            端口(QQ:25)
     * @param subject
     *            邮件主题
     * @param content
     *            邮件内容
     * @throws Exception
     */
    public static void SendEmail(String host, final String address, String from, final String password, String to, String port, String subject, String content) throws Exception {
        Multipart multiPart;
        String finalString = "";
        ByteArrayDataSource  ds = null;
        Properties props = System.getProperties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.user", address);
        props.put("mail.smtp.password", password);
        props.put("mail.smtp.port", port);
//        props.put("mail.smtp.auth", "true");
        Log.i("Check", "done pops");
        Session session = Session.getDefaultInstance(props, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {//此处必须做验证,才能发送邮件
                return new javax.mail.PasswordAuthentication(address,
                        password);
            }
        });
        DataHandler handler = new DataHandler(new ByteArrayDataSource(finalString.getBytes(), "text/plain"));
        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        message.setDataHandler(handler);
        Log.i("Check", "done sessions");
        multiPart = new MimeMultipart();
        InternetAddress toAddress;
        toAddress = new InternetAddress(to);
        message.addRecipient(Message.RecipientType.TO, toAddress);
        Log.i("Check", "added recipient");
        message.setSubject(subject);
        message.setContent(multiPart);
        message.setText(content);
        Log.i("check", "transport");
        Transport transport = session.getTransport("smtp");
        Log.i("check", "connecting");
        transport.connect(host, address, password);
        Log.i("check", "wana send");
        transport.sendMessage(message, message.getAllRecipients());
        transport.close();
        Log.i("check", "sent");
    }


}

二、异常处理类

package com.musicdo.puluo.utils;


import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.os.StrictMode;
import android.text.format.Time;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;


import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Properties;
import java.util.TreeSet;


/**
 * 名 称 :
 * 描 述 :
 * 创建者: 
 * 创建时间:
 * 版 本 :
 * 备 注 :
 */


public class CrashMailHandler implements Thread.UncaughtExceptionHandler {
    private final static String TAG = "UncaughtExceptionHandler";
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private static CrashMailHandler mInstance;
    private Context mContext;
    /** 使用Properties来保存设备的信息和错误堆栈信息*/
    private Properties mDeviceCrashInfo = new Properties();
    private static final String VERSION_NAME = "versionName";
    private static final String VERSION_CODE = "versionCode";
    private static final String STACK_TRACE = "STACK_TRACE";
    /** 在Release状态下关闭以提示程序性能
    * */
    public static final boolean DEBUG = false;
    /** 错误报告文件的扩展名 */
    private static final String CRASH_REPORTER_EXTENSION = ".cr";
    private CrashMailHandler() {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads().detectDiskWrites().detectNetwork()
                .penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
                .penaltyLog().penaltyDeath().build());
    }


    /** 获取CrashHandler实例 ,单例模式 */
    public static CrashMailHandler getInstance() {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads().detectDiskWrites().detectNetwork()
                .penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
                .penaltyLog().penaltyDeath().build());
        if (mInstance == null)
            mInstance = new CrashMailHandler();
        return mInstance;
    }


    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if (!handleException(throwable) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, throwable);
        } else {
            // Sleep一会后结束程序
            // 来让线程停止一会是为了显示Toast信息给用户,然后Kill程序
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                Log.e(TAG, "Error : ", e);
            }
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(10);
        }
    }


    private boolean handleException(final Throwable ex) {
        if (ex == null) {
            return true;
        }
        final String msg = ex.getLocalizedMessage();
        new Thread() {
            @Override
            public void run() {
                try {

//此处发送邮件
                    EmailUtil.sendEmail(null,"邮件标题",“邮件内容”+msg );
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
        // 使用Toast来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast toast = Toast.makeText(mContext, "程序出错,即将退出:\r\n" + msg,
                        Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
//              MsgPrompt.showMsg(mContext, "程序出错啦", msg+"\n点确认退出");
                Looper.loop();


            }
        }.start();


        //创建消息
//        collectCrashDeviceInfo(mContext);
        //保存错误报告文件
//        saveCrashInfoToFile(ex);
        //发送锗误报告到服务器,暂时没有用到,以后可以加上 //
//        sendCrashReportsToServer(mContext);
        return true;
    }


    /**
     * 把错误报告发送给服务器,包含新产生的和以前没发送的.
     * @param ctx
     */
    private void sendCrashReportsToServer(Context ctx) {
        String[] crFiles = getCrashReportFiles(ctx);
        if (crFiles != null && crFiles.length > 0) {
            TreeSet<String> sortedFiles = new TreeSet<String>();
            sortedFiles.addAll(Arrays.asList(crFiles));
            for (String fileName : sortedFiles) {
                File cr = new File(ctx.getFilesDir(), fileName);
                postReport(cr);
                cr.delete();// 删除已发送的报告
            }
        }
    }
    private void postReport(File file) {
        // TODO 发送错误报告到服务器
//        1.简单发送没有附件和抄送
        /*Intent data=new Intent(Intent.ACTION_SENDTO);
        data.setData(Uri.parse("mailto:[email protected]"));
        data.putExtra(Intent.EXTRA_SUBJECT, "这是标题");
        data.putExtra(Intent.EXTRA_TEXT, "这是内容");
        mContext.startActivity(data);*/


//        2.多个附件 可抄送 发送邮件
       /* Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        String[] tos = { "[email protected]" };
        String[] ccs = { "[email protected]" };
        intent.putExtra(Intent.EXTRA_EMAIL, tos);
        intent.putExtra(Intent.EXTRA_CC, ccs);
        intent.putExtra(Intent.EXTRA_TEXT, "body");
        intent.putExtra(Intent.EXTRA_SUBJECT, "subject");


        ArrayList<Uri> imageUris = new ArrayList<Uri>();
        imageUris.add(Uri.parse("file:///mnt/sdcard/a.jpg"));
        imageUris.add(Uri.parse("file:///mnt/sdcard/b.jpg"));
        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
        intent.setType("image*//*");
        intent.setType("message/rfc882");
        Intent.createChooser(intent, "Choose Email Client");
        mContext.startActivity(intent);*/
    }


    /**
     * 获取错误报告文件名
     * @param ctx
     * @return
     */
    private String[] getCrashReportFiles(Context ctx) {
        File filesDir = ctx.getFilesDir();
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(CRASH_REPORTER_EXTENSION);
            }
        };
        return filesDir.list(filter);
    }


    public void init(Context context) {
        mContext = context;
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }


    public void collectCrashDeviceInfo(Context ctx) {
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
                    PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                mDeviceCrashInfo.put(VERSION_NAME,
                        pi.versionName == null ? "not set" : pi.versionName);
                mDeviceCrashInfo.put(VERSION_CODE, ""+pi.versionCode);
            }
        }catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Error while collect package info", e);
        }
        //使用反射来收集设备信息.在Build类中包含各种设备信息,
        //例如: 系统版本号,设备生产商 等帮助调试程序的有用信息
        //具体信息请参考后面的截图
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                mDeviceCrashInfo.put(field.getName(), ""+field.get(null));
                if (DEBUG) {
                    Log.d(TAG, field.getName() + " : " + field.get(null));
                }
            } catch (Exception e) {
                Log.e(TAG, "Error while collect crash info", e);
            }}}
    /**
     * 保存错误信息到文件中
     * @param ex
     * @return
     */
    private String saveCrashInfoToFile(Throwable ex) {
        Writer info = new StringWriter();
        PrintWriter printWriter = new PrintWriter(info);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        String result = info.toString();
        printWriter.close();
        mDeviceCrashInfo.put("EXEPTION", ex.getLocalizedMessage());
        mDeviceCrashInfo.put(STACK_TRACE, result);
        try {


            //long timestamp = System.currentTimeMillis();
            Time t = new Time("GMT+8");
            t.setToNow(); // 取得系统时间
            int date = t.year * 10000 + t.month * 100 + t.monthDay;
            int time = t.hour * 10000 + t.minute * 100 + t.second;
            String fileName = "crash-" + date + "-" + time + CRASH_REPORTER_EXTENSION;
            FileOutputStream trace = mContext.openFileOutput(fileName,
                    Context.MODE_PRIVATE);
            mDeviceCrashInfo.store(trace, "");
            trace.flush();
            trace.close();
            return fileName;
        } catch (Exception e) {
            Log.e(TAG, "an error occured while writing report file...", e);
        }
        return null;
    }
}