Android獲取驗證碼自動填充

NO IMAGE

前提

手機獲取驗證碼,這是每個APP都會實現的功能,但是獲取驗證碼之後,切換到短信界面,然後再返回到當前界面,感覺比較蛋疼,也比較麻煩,因此想著獲取到驗證碼之後自動填充這個功能相對來說就比較人性化,並且用戶體驗也比較好。

首先

來分析一下獲取驗證碼並且填充的流程:手機點擊獲取驗證碼,然後平臺發送短信,監測短信數據庫是否有更新,並且判斷是否是自己所需要的驗證碼短信,如果是則直接獲取驗證碼,並且填充到當前界面中去,如下圖所示:

Android獲取驗證碼自動填充

其次

我們監測短信驗證信息其中要涉及到設計模式中的觀察者模式,我們這裡直接繼承系統的ContentObserver這個類,實現短信信息的驗證,並且自動填充。現在來看看我們的實現方法吧,先上圖,no pic say a xx。

Android獲取驗證碼自動填充

  • 繼承ContentObserver

    public class PhoneCode extends ContentObserver {
    private Context mContext; // 上下文
    private String code; // 驗證碼
    SmsListener mListener;
    private String mPhone;
    Cursor mCursor;
    
    public PhoneCode(Context context, Handler handler, String phone, SmsListener listener) {
      super(handler);
      this.mContext = context;
      this.mPhone = phone;
      this.mListener = listener;
     }
    
    public PhoneCode(Context context, Handler handler, SmsListener listener) {
      super(handler);
      this.mContext = context;
      this.mListener = listener;
    }
    
    @Override
    public void onChange(boolean selfChange, Uri uri) {
      super.onChange(selfChange);
      // 第一次回調 不是我們想要的 直接返回
      if (uri.toString().equals("content://sms/raw")) {
          return;
      }
      // 第二次回調 查詢收件箱裡的內容
      Uri inboxUri = Uri.parse("content://sms/inbox");
      // 按時間順序排序短信數據庫
      mCursor = mContext.getContentResolver().query(inboxUri, null, null,
              null, "date desc");
      if (mCursor != null) {
          if (mCursor.moveToFirst()) {
              // 獲取手機號
              String address = mCursor.getString(mCursor.getColumnIndex("address"));
              Log.e("ADDRESS", address);
              // 獲取短信內容
              String body = mCursor.getString(mCursor.getColumnIndex("body"));
              Log.e("ADDRESS", body);
              // 判斷手機號是否為目標號碼,服務號號碼不固定請用正則表達式判斷前幾位。
              //加上這個判斷必須知道發送方的電話號碼,侷限性比較高
    //                if (!address.equals(mPhone)) {
    //                    return;
    //                }
              if (!body.startsWith("天下為公")) {
                  return;
              }
              // 正則表達式截取短信中的6位驗證碼
              String regEx = "(?<![0-9])([0-9]{" + 6 + "})(?![0-9])";
              Pattern pattern = Pattern.compile(regEx);
              Matcher matcher = pattern.matcher(body);
              // 如果找到通過Handler發送給主線程
              while (matcher.find()) {
                  code = matcher.group();
                  if (mListener != null) {
                      mListener.onResult(code);
                  }
              }
    
          }
      }
      mCursor.close();
    }
    
    /**
     * 短信回調接口
     */
     public interface SmsListener {
      /**
       * @param result 回調內容(驗證碼)
       */
      void onResult(String result);
     }
    }
    
  • 分析

       代碼很簡單,其中有兩個構造函數,一個是帶電話號碼的,一個是不帶電話號碼的。帶電話號碼(電話號
     碼是發送方的電話號碼,也就是說是平臺方或者發信人的電話號碼)的,這樣侷限性比較大,只能收到固
     定的發信人的電話驗證碼。這裡註釋了,因為我想直接獲取驗證碼,不管是誰發的短信。另外一個是不帶
     電話號碼的驗證碼,這裡對短信的內容加了判斷。試想,如果當我們獲取短信的時候收到了一條其他平臺
     的驗證碼,但卻不是我們需要的,這時候該怎麼辦?當然是直接拋棄了,然後等待我們自己的驗證碼了。
     因為短信驗證碼 都有一定的格式所以這裡只需要對驗證碼的開頭進行判斷就行。當然,我們也可以和後臺
     同學溝通好驗證碼格式,然後動態判斷即可,比如我這裡是 以“天下為公”開頭,你也可以寫成變量然後動
     態改變即可。
    
  • 使用

     /**
      * 固定手機號碼
      */
     private void fixedPhone(String phone) {
      mPhoneCode = new PhoneCode(this, new Handler(), phone,
              new PhoneCode.SmsListener() {
                  @Override
                  public void onResult(String result) {
                      ToastUtils.showMessage(PhoneActivity.this, result);
                      mEdtPhone.setText(result);
                  }
              });
      // 註冊短信變化監聽
      this.getContentResolver().registerContentObserver(
              Uri.parse("content://sms/"), true, mPhoneCode);
    }
    
    /**
     * 沒有手機號碼
     */
     private void fixedPhone() {
      mPhoneCode = new PhoneCode(this, new Handler(),
              new PhoneCode.SmsListener() {
                  @Override
                  public void onResult(String result) {
                      ToastUtils.showMessage(PhoneActivity.this, result);
                      mEdtPhone.setText(result);
                  }
              });
      // 註冊短信變化監聽
      this.getContentResolver().registerContentObserver(
              Uri.parse("content://sms/"), true, mPhoneCode);
    }
    
  • 分析

     這裡用的是兩個使用方式,一種是帶電話號碼的,一個是不帶的,要用哪個調那個,so easy。
    

最後

這是一個很小的功能,但是寫程序的時候要考慮的東西有很多。把我們自己當成使用者,用心寫好一個程序,不為了完成功能而完成。實現代碼一是要考慮功能,二是要考慮代碼的優雅。不可不經測試和推敲就拿出去分享或者使用,不僅誤導了他人,也讓自己蒙羞。現在網上千篇一律沒有經過推敲的文章很多,遇到過許多坑爹的,這裡就發一下牢騷和提醒一下自己做事一定要認真。

致謝

Android短信驗證碼自動填寫功能實現

相關文章

nexus3.x私服配置(windows版)

AndroidGoogle應用內支付

Android海外應用內支付之ONEstore(韓國支付SDK)集成

Androidsocket高級用法(自定義協議和ProtocolBuffer使用)