Android短信驗證碼自動填充

egret0502 7年前發布 | 9K 次閱讀 安卓開發 Android開發 移動開發

在我們的Android開發中會經常用到短信驗證的功能,這個時候如果再讓用戶就查看短信.然后再回到界面進行短信的填寫,難免有多少有些不方便,為了提高用戶體驗,我也就自己來實現驗證碼的自動填寫功能

一、簡介

之前筆者見過一些人的實現思路是這樣的:

創建一個廣播接收器,接受短信變化的廣播,然后在收到廣播的時候,再把驗證碼提取出來發送給我們的需要填充驗證碼的地方就行了。 但是,這種方式有它的缺陷:當你的手機安裝了其他一些短信應用(例如QQ通訊錄)或者手機本身限制了權限的情況下,這種方式有可能會不起作用,無法做到自動填寫,而且就算把優先級設高,也不能保證不會被別的應用“搶先”。 所以,通過查閱資料,發現了這種方式: 可以通過監聽短信數據庫的方式實現。監聽短信數據庫主要是通過ContentObserver這個類來完成。ContentObserver主要是通過Uri來監測特定的Databases的表,當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 待發送列表 (比如開啟飛行模式后,該短信就在待發送列表里)

 

 本文由用戶 egret0502 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!