Method of Android SMS Verification Code Monitoring to Solve Multiple Calls of onChange

  • 2021-08-21 21:33:33
  • OfStack

Let's say one sentence first: MIUI, please give up treatment! Here's a portal:

Pit of MIUI Notification SMS Permission

Identifying and extracting SMS verification codes is still a common requirement. The main problems to be solved are:

1. How to monitor

2. How to extract the verification code from SMS

3. Listen for multiple calls

Look directly at the following code, it is very clear. One thing to note is that onChange will be called many times. In fact, you can see it by calling Log. When you receive a short message, you will call onChange twice. The result of Log is as follows:


mUri===content://sms/raw/20
mUri===content://sms/inbox/20

For Android 7.0 or above, click on the mark as read, and it will also be called once


mUri===content://sms

Received a short message is uri will be followed by a certain number, corresponding to the database _ id, such as the above 20


public static class SMSCodeObserver extends ContentObserver {
    private Activity mActivity;
    private static final String TAG = "SMSCodeObserver";
    private SMSCodeListener mSMSCodeListener;
    private Uri mUri;

    public void setSMSCodeListener(SMSCodeListener SMSCodeListener) {
      mSMSCodeListener = SMSCodeListener;
    }

    public interface SMSCodeListener {
      void onResult(String code);
    }

    public SMSCodeObserver(Handler handler, Activity activity) {
      super(handler);
      mActivity = activity;
    }


    public void register() {
      mActivity.getContentResolver().registerContentObserver(
          Uri.parse("content://sms/"), true, this);
    }

    public void unRegister() {
      mActivity.getContentResolver().unregisterContentObserver(this);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
      super.onChange(selfChange, uri);
      if (uri == null) {
        mUri = Uri.parse("content://sms/inbox");
      } else {
        mUri = uri;
      }
      if (mUri.toString().contains("content://sms/raw") || mUri.toString().equals("content://sms")) {
        return;
      }
      LogUtils.d(TAG, "mUri===" + mUri.toString());
      AndPermission.with(mActivity)
          .permission(Manifest.permission.READ_SMS)
          .requestCode(100)
          .callback(this)
          .rationale(new RationaleListener() {
            @Override
            public void showRequestPermissionRationale(int requestCode, Rationale rationale) {
              AndPermission.rationaleDialog(mActivity, rationale)
                  .show();
            }
          })
          .start();
    }

    @PermissionYes(100)
    @SuppressWarnings("unused")
    private void getPermissionYes(List<String> grantedPermissions) {
      handleSMS();
    }

    @PermissionNo(100)
    @SuppressWarnings("unused")
    private void getPermissionNo(List<String> deniedPermissions) {
      if (AndPermission.hasPermission(mActivity, Manifest.permission.READ_SMS)) {
        handleSMS();
      } else {
        AndPermission.defaultSettingDialog(mActivity)
            .show();
      }
    }

    private void handleSMS() {

       /*  Sort in reverse order by date  */
      Cursor cursor = mActivity.getContentResolver().query(mUri, null, null, null, "date desc");
      if (cursor != null) {
        if (cursor.moveToFirst()) {// Cursor moves to first Position 
          /*  Sender's number  */
          String address = cursor.getString(cursor.getColumnIndex("address"));
          /*  Content of SMS  */
          String body = cursor.getString(cursor.getColumnIndex("body"));
          LogUtils.d(TAG, "address:" + address + ",body:" + body);
          if (!body.contains(" Verification code ")) {
            return;
          }

          /*  Extracting verification code by regularity (modified according to actual situation)  */
          String code = getSMSCode(body);
          if (code != null) {
            if (mSMSCodeListener != null) {
              mSMSCodeListener.onResult(code);
            }
            LogUtils.d(TAG, "code:" + code);
          }
        }
        cursor.close();
      }
    }

    private static String getSMSCode(String msg) {
      /* Extract regular expressions, which need to be modified as needed */
      Pattern p = Pattern.compile("(?<![0-9])([0-9]{6})(?![0-9])");
      Matcher m = p.matcher(msg);
      if (m.find()) {
        LogUtils.d(TAG, m.group());
        return m.group(0);
      }
      return null;
    }
  }

Related articles: