采用动态广播和观察者模式来分别实现验证码自动填写

采用动态广播和观察者模式来分别实现验证码自动填写



用户体验是至关重要的,我之前也实现过,就是通过短信广播的形式去监听,但是近期看了一下观察者模式,觉得实现起来也是极好的,那具体怎么做呢?大家跟我一起看下去

这里,我将用两种方式来实现短信自动填写,一种是短信广播,一种是观察者模式

我们再开始之前先定义一下规则,就是我们的短信号码和模板,一般的短信推送,你的服务号码是固定的,当然,也有可能你的量级比较大,所以在全国各地都有,但是我们这里就假设为一般的应用,所以

服务中心号码:6505551212
短信模板:感谢你使用某某应用,你的验证码为:123456!

我们就是要拿到这个验证码,既然如此,那我们开始吧!

一.BroadcastReceiver

既然通过广播来实现,我们首先先把权限给加上,不然你等下忘记了咋办

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

然后你就可以思考了,我这里写了两个控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:padding="10dp"
    android:gravity="center"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/et_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_get_code"
        android:text="获取验证码"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

我这里的逻辑也很简单,只要点击获取验证码的按钮,我就动态注册广播,然后短信广播来了之后拿到短信的内容,去截取短信验证码填入就好了,所以可以看到我们的代码如下

/*
 *项目名: SmsAutoWriter
 *包名:   com.liuguilin.smsautowriter
 *文件名:  ReceiverActivity
 *创建者:  LGL
 *创建时间:2017/1/715:34
 *描述:    广播监听
 */
public class ReceiverActivity extends AppCompatActivity {

    private static final String TAG = "ReceiverActivity";

    //短信Action
    public static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";

    private EditText et_sms;
    private Button btn_get_code;
    private SmsReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_receiver);
        initView();
    }

    private void initView() {
        et_sms = (EditText) findViewById(R.id.et_sms);
        btn_get_code = (Button) findViewById(R.id.btn_get_code);
        btn_get_code.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //动态注册广播
                receiver = new SmsReceiver();
                IntentFilter intentFilter = new IntentFilter();
                intentFilter.addAction(SMS_ACTION);
                intentFilter.setPriority(Integer.MAX_VALUE);
                registerReceiver(receiver,intentFilter);
            }
        });
    }

    private class SmsReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.i(TAG,"action:" + action);
            if(SMS_ACTION.equals(action)) {
                //获取短信内容返回的是一个Object数组
                Object[] objs = (Object[]) intent.getExtras().get("pdus");
                //遍历数组得到相关数据
                for (Object obj : objs) {
                    //把数组元素转换成短信对象
                    SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);
                    //发件人
                    String smsPhone = sms.getOriginatingAddress();
                    //内容
                    String smsContent = sms.getMessageBody();
                    Log.i(TAG, "短信的内容:" + smsPhone + ":" + smsContent);

                    if(smsPhone.equals("6505551212")){
                        String code = smsContent.substring(17,23);
                        et_sms.setText(code);
                    }
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }
}

这段代码的逻辑很简单,当我们获取到短信内容直接直接截取就好了,这是在知道短信内容的前提下才行的,也是之前做的,感觉思路不咋滴,而且里面获取验证码,其实我们可用去用正则表达式去解析的,这个我们下文继续讲解,嘿嘿,我们来看下运行演示的效果

恩效果是实现了,那还有没有更加逻辑性的实现方式呢?答案是有的,就是通过观察者模式去实现

二.ContentObserver

我在之前的Rx文章中提到过观察者模式,实际上大部分人还是知道以及使用观察者的

  • 观察者
    Observer将自己注册到被观察对象Subject中,被观察者将观察者存放在一个Container容器中
  • 被观察者
    被观察对象发生某种变化,从容器中得到所有观察过的观察者,将变化通知观察者

理论很简单,我们今天用到的是ContentObserver,有点类似于内容提供者,不过这里是内容观察者,他的主要工作就是观察特定的Uri引起的数据库变化,做出相应的处理,在数据库中,有点类似触发器Trigger,而我们监听短信自动填写,也是用的这个,我们具体去看下代码的实现吧,先来看下我们的Activity

/*
 *项目名: SmsAutoWriter
 *包名:   com.liuguilin.smsautowriter
 *文件名:  ObserverActivity
 *创建者:  LGL
 *创建时间:2017/1/715:34
 *描述:    观察者模式
 */
public class ObserverActivity extends AppCompatActivity implements View.OnClickListener {

    private SmsObserver smsObserver;

    public Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1000:
                    String code = (String) msg.obj;
                    et_sms.setText(code);
                    break;
            }
        }
    };
    private EditText et_sms;
    private Button btn_get_code;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_observer);

        initView();
    }

    private void initView() {
        et_sms = (EditText) findViewById(R.id.et_sms);
        btn_get_code = (Button) findViewById(R.id.btn_get_code);
        btn_get_code.setOnClickListener(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(smsObserver != null){
            getContentResolver().unregisterContentObserver(smsObserver);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_get_code:
                if(smsObserver == null){
                    smsObserver = new SmsObserver(this, handler);
                }
                Uri uri = Uri.parse("content://sms");
                //注册
                getContentResolver().registerContentObserver(uri, true, smsObserver);
                break;
        }
    }

}

我在里面,同样是一模一样的控件,一个是输入框,一个是按钮,连理论也是很类似,如果你点击了按钮,我就给你注册,不过现在不是注册广播,而是注册观察者罢了,而在onDestroy中,我把观察者给取消掉了,其实主要的逻辑还是看SmsObserver

/*
 *项目名: SmsAutoWriter
 *包名:   com.liuguilin.smsautowriter
 *文件名:  SmsObserver
 *创建者:  LGL
 *创建时间:2017/1/716:04
 *描述:    短信
 */
public class SmsObserver extends ContentObserver{

    private static final String TAG = "SmsObserver";

    private Context mContext;
    private Handler handler;

    private String code = "";

    public SmsObserver(Context mContext,Handler handler) {
        super(handler);
        this.mContext = mContext;
        this.handler = handler;
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        Log.i(TAG,"短信有变化:" + uri.toString());

        //第一遍没有存储在数据库中
        if(uri.toString().equals("content://sms/raw")){
            return;
        }

        //收件箱
        Uri inboxUri = Uri.parse("content://sms/inbox");
        Cursor c = mContext.getContentResolver().query(inboxUri,null,null,null,"date desc");
        if(c != null){
            if(c.moveToFirst()){
                String phone = c.getString(c.getColumnIndex("address"));
                String content = c.getString(c.getColumnIndex("body"));
                Log.i(TAG,"短信内容:" + phone + ":" + content);

                //连续6个数字
                Pattern pattern = Pattern.compile("(\\d{6})");
                Matcher matcher = pattern.matcher(content);

                if(matcher.find()){
                    code = matcher.group(0);
                    Log.i(TAG,"验证码:" + code);
                }
                handler.obtainMessage(1000,code).sendToTarget();
            }
            c.close();
        }
    }
}

这里的逻辑比较多,我们慢慢来说,首先,我们的构造方法传一个上下文,一个handler进来,这个肯定是有需要的参数的,可以不提,继承的是ContentObserver,重写onChange方法这个才是重点,我们监听的就是数据库的这个url发生改变,很明显,我们设置的就是短信的数据库,所以一有短信就会触发这个方法,在这个方法里面,我们做了什么事情呢?首先判断这个url是否等于content://sms/raw,如果是的话,说明短信还没有存入数据库,一般一条短信来了之后会触发两次onChange方法,所以第一次就直接return获取,然后用Cursor 查询收件箱,这个没的说,拿到短信内容之后用正则表达式(\d{6})去获取里面连续6个数字,也就是我们的验证码,这样,通过Handler去更新UI,齐活,这个思路是不是更加的明了而且有效,我们这里要注意下需要添加一个阅读短信的权限

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

我们最后跑一遍

OK,到这里,我也说了两种监听的方式,你喜欢用哪种就用哪种咯,如果大家还有其他方式处理的话,欢迎来群里讨论一下哟!

源码下载:http://download.csdn.net/detail/qq_26787115/9731472

加群开车:555974449

时间: 2024-09-13 11:34:36

采用动态广播和观察者模式来分别实现验证码自动填写的相关文章

android-如何用动态广播传递和接收数据

问题描述 如何用动态广播传递和接收数据 如何用动态广播传递和接收数据,最好有个实例本人小白一个,越详细越好谢谢了 解决方案 http://zcj331.blog.163.com/blog/static/175625255201371951751758/ 解决方案二: 广播传递就是用intent传递参数,和activity之间一样的道理 解决方案三: 发送广播: Intent intent = new Intent(); intent.setAction("xxxxx"); sendBr

采用UDP广播模式写简单信息传输工具~

使用UDPClient类这个是我写的测试代码,供参考~ using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;using System.Globalization;using System.Net;using System.Net.Sockets;using System.Threadin

对采用动态原型方式无法展示继承机制得思考_javascript技巧

复制代码 代码如下: <script type="text/javascript"> function Polygon(iSides) { this.sides = iSides; if(typeof Polygon._initialized == "undefined") { Polygon.prototype.getArea = function() { return 0; }; Polygon._initialized = true; } } fu

动态的改变IFrame的高度实现IFrame自动伸展适应高度_javascript技巧

动态的改变IFrame的高度,实现IFrame自动伸展,父页面也自动神缩 原理: 在IFrame子页面一加载的时候,调用父IFrame对象,改变其高度 具体实现一: 1.在IFrame的具体页面(就是子页面),添加JavaScript 复制代码 代码如下: <script> function IFrameResize(){ //alert(this.document.body.scrollHeight); //弹出当前页面的高度 var obj = parent.document.getEle

12306彩色动态验证码遭网民调侃:毕加索抽象画么?

12306彩色动态验证码遭网民调侃像抽象画央广网北京1月2日消息(记者刘祎辰)据中国之声<新闻纵横>报道,"那个验证码,是毕加索的抽象画么!!!"12306网站一推出 新的"彩色动态验证码机制",就遭到了很多网民调侃,不少人大呼"看不清".同时,动态验证码的推出也影响到了抢票软件,多家抢票软件接近"报废",360浏览器第一时间就在官方微博上表达了不满.虽然12306进行了颇多改进,但不论是遭遇用户调侃,还是受到其他

Android实现短信验证码获取自动填写功能(详细版)_Android

现在的应用在注册登录或者修改密码中都用到了短信验证码,那在android中是如何实现获取短信验证码并自动填写的呢? 首先,需要要在manifest中注册接收和读取短信的权限:  <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> <uses-permission android:name="android.permission.READ

Android实现短信验证码自动填写功能

本实例为大家分享了Android实现短信验证码自动填写功能,供大家参考,具体内容如下 实现思路很简单: 1.在需要输入验证码的Activity代码注册监听短信的广播 2.拦截短信,获取其中的验证码 3.回写到EditText private SmsReciver smsReciver = new SmsReciver(); /** 收到短信Action **/ String ACTION_SMS_RECIVER = "android.provider.Telephony.SMS_RECEIVED

Android利用CursorLoader实现短信验证码自动填写_Android

概述 Android上实现短信验证码自动填写,常用的有两种方式.一种是利用BroadCastReceiver,还有一种是监听手机上短信数据库的变化.利用BroadCastReceiver来实现会在一些情况下无效,最常见的就是手机上安装了具有垃圾短信拦截功能的软件的情况下,短信验证码自动填写无效.所以,现在一般会选用监听数据库内容变化的方式来实现短信验证码自动填写. 网上对于利用监听数据库内容变化来实现短信验证码自动填写的文章也很多,主要分为一下步骤: 1. 继承ContentObserver实现

Android实现短信验证码自动填写功能_Android

android应用经常会涉及到注册登录功能,而许多的注册登录或修改密码功能常常需要输入短信验证码,通常,用户收到短信需要最小化应用去查看短信再填入验证码,必然比较麻烦,因此有必要能够自动获得下发的短信验证码,方便了用户的操作,用户体验更好. 原理讲解: 主要就是实时获取短信信息.涉及到ContentObserver类的使用.使用ContentProvider来监听短信数据库的变化,在自定义的ContentObserver当中实现onChange的方法进行监听特定手机号的短信,然后进行信息截取在填