Android短信验证码自动填充

github地址

https://github.com/zhouxu88/SMSContentObserver

** 在我们的Android开发中会经常用到短信验证的功能,这个时候如果再让用户就查看短信.然后再回到界面进行短信的填写,难免有多少有些不方便,为了提高用户体验,我也就自己来实现验证码的自动填写功能**

一、简介

之前笔者见过一些人的实现思路是这样的:
创建一个广播接收器,接受短信变化的广播,然后在收到广播的时候,再把验证码提取出来发送给我们的需要填充验证码的地方就行了。但是,这种方式有它的缺陷:当你的手机安装了其他一些短信应用(例如QQ通讯录)或者手机本身限制了权限的情况下,这种方式有可能会不起作用,无法做到自动填写,而且就算把优先级设高,也不能保证不会被别的应用“抢先”。所以,通过查阅资料,发现了这种方式:可以通过监听短信数据库的方式实现。监听短信数据库主要是通过ContentObserver这个类来完成。ContentObserver主要是通过Uri来监测特定的Databases的表,当ContentObserver所观察的Uri发生变化时,便会触发它。ContentObserver——内容观察者,可监听观察特定Uri指向的数据库项的变化,进而进行相应的处理。

二、短信验证码自动填充的工具类

/**
 * 短信验证码自动填充
 *
 * @author 周旭
 */
public class SMSContentObserver extends ContentObserver {

    private Context mContext; // 上下文
    private Handler mHandler; // 更新UI线程
    private String code; // 验证码

    public SMSContentObserver(Context context, Handler handler) {
        super(handler);
        mContext = context;
        mHandler = handler;
    }

    /**
     * 回调函数, 当所监听的Uri发生改变时,就会回调此方法
     * <p>
     * 注意当收到短信的时候会回调两次
     * 收到短信一般来说都是执行了两次onchange方法.第一次一般都是raw的这个.
     * 这个时候虽然收到了短信.但是短信还没有写入到收件箱里面
     * 然后才是另外一个,后面的数字是该短信在收件箱中的位置
     *
     * @param selfChange 此值意义不大 一般情况下该回调值false
     */
    @Override
    public void onChange(boolean selfChange, Uri uri) {

        Log.e("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 address = c.getString(c.getColumnIndex("address"));
                // 获取短信内容
                String body = c.getString(c.getColumnIndex("body"));
                Log.i("tag", "body------->" + body);
                // 判断手机号是否为目标号码(短信提供商的号码)
                // 在这里我们的短信提供商的号码如果是固定的话.我们可以再加一个判断,这样就不会受到别的短信应用的验证码的影响了
                // 不然的话就在我们的正则表达式中,加一些自己的判断,例如短信中含有自己应用名字啊什么的...
                /*if (!address.equals("13342290623"))
                {
                    Log.i("tag","------->没有读取到内容");
                    return;
                }*/
                // 正则表达式截取短信中的6位验证码
                Pattern pattern = Pattern.compile("(\\d{6})");
                Matcher matcher = pattern.matcher(body);

                // 利用handler将得到的验证码发送给主线程
                if (matcher.find()) {
                    code = matcher.group(0);
                    //mHandler.obtainMessage(1, code).sendToTarget();
                    Message msg = Message.obtain();
                    msg.what = MainActivity.MSG_RECEIVE_CODE;
                    msg.obj = code;
                    mHandler.sendMessage(msg);
                }
            }
            c.close();
        }
    }
}

调用的Activity:

/**
 * 短信验证码自动填写功能的实现
 */
public class MainActivity extends AppCompatActivity {

    public static final int MSG_RECEIVE_CODE = 1; //收到短信的验证码
    private EditText codeEdt; //短信验证码的输入框
    private SMSContentObserver smsContentObserver;

    //回调接口
    @SuppressLint("HandlerLeak")
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_RECEIVE_CODE) {
                codeEdt.setText(msg.obj.toString()); //设置读取到的内容
            }
        }
    };

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

        codeEdt = (EditText) findViewById(R.id.smsCode);

        findViewById(R.id.send_sms_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                senSMSCode();
            }
        });

        smsContentObserver = new SMSContentObserver(
                MainActivity.this, handler);

        //ContentObserver注册
        getContentResolver().registerContentObserver(
                Uri.parse("content://sms/"), true, smsContentObserver);

    }

    /**
     * 取消注册
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        getContentResolver().unregisterContentObserver(smsContentObserver);
    }


    //使用Bmob云的短信验证功能来发送短信
    private void senSMSCode() {

        BmobSMS.requestSMSCode("13342290623", "知么网络", new QueryListener<Integer>() {

            @Override
            public void done(Integer smsId, BmobException ex) {
                if (ex == null) {//验证码发送成功
                    Log.i("smile", "短信id:" + smsId);//用于后续的查询本次短信发送状态
                    Toast.makeText(MainActivity.this, "发送验证码成功", Toast.LENGTH_SHORT).show();
                }
            }
        });

    }
}

添加权限

<!--读取短信的权限-->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS" />

三、短信的Uri共有一下几种:

content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱 (正在发送的信息)
content://sms/failed 发送失败
content://sms/queued 待发送列表 (比如开启飞行模式后,该短信就在待发送列表里)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容