Android 应用中使用ContentObserver自动填写短信验证码

/**稀土掘金,时光不老**/

大家好,最近做项目时,加了一个小功能,手机登录应用或注册时自动填写短信验证码,当然,网上有很多很棒的demo,我也来和大家分享一下,同时也作为一下个人笔记吧。

因为比较简单,就不上效果图了,为什么不用广播(BroadcastReceiver)来接收系统收到短信时候的广播。可是这个广播是有序广播,就是当别的程序先获取到了这个广播再传递给你,当然它也可以干掉这个广播,让你接收不到,这样你的程序肯定是接收不到这个广播的了。网上有很多这样的例子,什么提高广播接收器的优先级又是1000又是10000的。这里提到了把intent-filter中的android:priority的值设置为1000,但是在实时中你设置1000一样是接受不到广播的,除非你把手机中的其他接受了这个广播的短信卸载,比如360 GO短信,飞信神马的。他们的优先级总是要比你的高。你可以继续BAIDU,有的人会设置它为10000 9999等等,你会发现设置为10000的时候偶尔可以接收到,仅仅是偶尔。那肿么办呢。

大家可以看看这个广播的基本介绍:http://wenku.baidu.com/view/226f9dd5b14e852458fb57ba.html

好了,来说说几个核心点吧

 1. 使用ContentObserver(使用的观察者模式)监听手机短信动态数据库,当收到短信数据库变化了的时候    去取得最新的那条短信即可。或者你想别的什么操作也可以。

    2. 可指定一个号码,只读取与它有关短信,避免提取来源错误 。

     3.  可过滤掉与我们不需要的短信

        4. 利用正则表达式,可匹配各种类型验证码。

哈哈 ,激动人心的时刻来了,看代码--------------

  1. 在你的Activity中进行注册监听短信数据库,c为Activity的对象
  2. 注册代码为getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, c);  
  3. 关于各种类型的uri请参考http://www.2cto.com/kf/201203/123797.html博客。

这是获取短信验证码的工具类

public class SmsReciverUtil extends ContentObserver {
    private Activity c;
    private int codelength;
    private Handler handler;

    public SmsReciverUtil(Handler handler, Activity c, int codelength) {
        super(handler);
        this.c = c;
        this.codelength = codelength;//截取验证码的长度
        this.handler = handler;
    }

    // 收到短信一般来说都是执行了两次onchange方法.第一次一般都是raw的这个.这个时候虽然收到了短信.但是短信还没有写入 到收件箱里面
    // 然后才是另外一个,后面的数字是该短信在收件箱中的位置
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        if (uri.toString().equals("content://sms/raw")) {
            return;
        }
        String code = getsmsCode(c, codelength);
        if (!TextUtils.isEmpty(code)) {
            // 利用handler将得到的验证码发送给主界面
            Message msg = Message.obtain();
            msg.what =0;
            msg.obj = code;
            handler.sendMessage(msg);
        }
    }

    public String getsmsCode(Activity c, int codelength) {
        ContentResolver contentresolver = c.getContentResolver();
        // 设置一个uri来查看收件箱中短信内容
        Uri uri = Uri.parse("content://sms/inbox");
        //需要查询的字段 address 号码,read 0未读 1已读,body短信内容
        String[] projection = new String[]{"_id", "address", "read", "body"};
        //需要查询未读短信
//        String selection = "address=? and read=?";  //注意这里填写的号码如何是公司里固定的号码可以是 (xxxxxxx)但是测试使用的号码时看有没有(+86xxxxxxx)别 写错了,代码没问题,好好检查O(∩_∩)O哈哈~,当然你可以不写需要查询的号码,查询收件箱数据库中的短信
//        String [] selections = new String[]{"这里填写需要查询的号码","0"};
        // 按短信id倒序排序,如果按date排序的话,修改手机时间后,读取的短信就不准了
        String sortOrder = "_id desc";
        // 读取收件箱中指定号码的短信
        Cursor cur = contentresolver.query(uri, projection, null, null, sortOrder);
        if (null == cur) {
            return null;
        }
        if (cur.getCount() <= 0) {
            return null;
        }
        if (!cur.moveToFirst()) {
            return null;
        }

        String number = cur.getString(cur.getColumnIndex("address"));// 手机号
        String body = cur.getString(cur.getColumnIndex("body"));//短信类容  
        // 最后用完游标千万记得关闭
        cur.close();
        // 在这里我们的短信提供商的号码如果是固定的话.我们可以再加一个判断,这样就不会受到别的短信应用的验证码的影响了
        if (!number.startsWith("这里填写你的号码以xxxx开头的数字")) {
            return null;
        }

        if (!body.contains("这里填写你的过滤的名称"){
            return null;
        }
        return getyzm(body, codelength);
    }

    /**  * 从短信字符窜提取验证码  *  * @param body 短信内容  * @param codelength 验证码的长度 一般4 * @return 接取出来的验证码  */   public String getyzm(String body, int codelength) {
        Pattern p = Pattern.compile("(?<![0-9])([0-9]{" + codelength + "})(?![0-9])");
        Matcher matcher = p.matcher(body);
        if (matcher.find()) {
//            ContentValues values = new ContentValues();
//            values.put("read", "1"); // 修改短信为已读模式
            return matcher.group(0);
        }
        return null;
    }
}

  1. 首先([a-zA-Z0-9]{4})是得到一个连续的4位数字字母组合  
  2.  (?<![a-zA-Z0-9])负向断言([0-9]{YZMLENGTH})前面不能有数字  
  3.  (?![a-zA-Z0-9])断言([0-9]{YZMLENGTH})后面不能有数字出现
有些验证码是纯数字的那么直接用这个就可以了
//Pattern p = Pattern.compile("(?<![0-9])([0-9]{" + 验证码的长度可自定义+ "})(?![0-9])");
监听完成后记得在你的Activity中getContentResolver().unregisterContentObserver(c);注销监听 

哇 差点忘了,相信很多小伙伴们犯过这样的错误吧O(∩_∩)O哈哈~

<!-- 阅读消息 -->
    <uses-permission android:name="android.permission.READ_SMS" />

<!-- 接收消息 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

如果你还有其他操作还要加上一些权限

<!-- 发送短信-->

   <uses-permission android:name="android.permission.SEND_SMS" />

<!-- 写入消息 -->
    <uses-permission android:name="android.permission.WRITE_SMS" />

就是这么简单对不demo就不写了呵呵这里很清楚也很简单..不喜勿喷,有错回帖

来一句 弘洋大神 的名言  

生命不息,奋斗不止,万事起于忽微,量变引起质变 



你可能感兴趣的:(正则表达式,验证码,ContentObserver,自动填写)