有些项目为了方便客户操作,减去客户输入短信验证码的时间,会要求安卓app能够获取收到的短信验证码并自动填充到输入框。所以,我整理了安卓获取短信验证码并自动填充输入框的两种方法,而且正式在项目中使用并无bug。

       一:监听短信库的变化,获取收到的短信内容,并通过正则表达式取出数字验证码填充到输入框中。代码如下:

      

public class ObtainSmsVerifyCode {
 private Uri SMS_INBOX = Uri.parse("content://sms/");
  private Context context = null;
  private Handler handler = new Handler();
  private SmsObserver smsObserver;
  private SmsCodeReceivedListener listener = null;
  private String patternCoder = "(?<!\\d)\\d{6}(?!\\d)";
  private ApplicationContext application = new ApplicationContext();  /**
   * @Description: 获取到短信验证码监听
   */
  public interface SmsCodeReceivedListener {
   public void onSmsCodeReceived(String code);
  } public ObtainSmsVerifyCode(Context context) {
   this.context = context;
   ContentResolver cr = context.getContentResolver();
   smsObserver = new SmsObserver(handler);
   cr.registerContentObserver(SMS_INBOX, true, smsObserver);
  } public void setOnSmsCodeReceivedListener(SmsCodeReceivedListener lis) {
   listener = lis;
  } public void unRegisterContentObserver() {
   ContentResolver cr = context.getContentResolver();
   cr.unregisterContentObserver(smsObserver);
  } /**
   * @Description: 获取验证码
   */
  private void getVerifyCodeFromSms() {  ContentResolver cr = context.getContentResolver();
   /**
    * address:发件人手机号码
    * date:发件日期
    * read:是否阅读
    * status:状态,-1接受
    * body:短信内容
    */
   String[] projection = new String[] { "address", "body", "date", "type",
     "read" };
   Cursor cursor;
   try {
    cursor = cr
      .query(SMS_INBOX, projection, null, null, "date desc");
    if (cursor != null) {
     if (cursor.moveToFirst()) {
      SimpleDateFormat dateFormat = new SimpleDateFormat(
        "yyyy-MM-dd hh:mm:ss");
      Date d = new Date(cursor.getLong(cursor.getColumnIndex("date")));
      String date = dateFormat.format(d);
      StringBuilder sb = new StringBuilder();
      sb.append(
        "发件人手机号码:"
          + cursor.getString(cursor
            .getColumnIndex("address")))
        .append("信息内容:"
          + cursor.getString(cursor
            .getColumnIndex("body")))
        .append("是否查看:"
          + cursor.getString(cursor
            .getColumnIndex("read")))
        .append("类型:"
          + cursor.getInt(cursor.getColumnIndex("type")))
        .append(date);
      LogUtil.i("sb=======" + sb);
      if (listener != null) {
       if (SmsServiceUtils.smsPhoneNum(application.getSegmentId())
         .contains(
           cursor.getString(cursor
             .getColumnIndex("address")))) {
        LogUtil.i("here is it====="
          + cursor.getString(cursor
            .getColumnIndex("address")));
        if (hasSixNumOrNot(cursor.getString(cursor
          .getColumnIndex("body")))
          && cursor
            .getString(
              cursor.getColumnIndex("body"))
            .contains(
              "BOC Online Electronic Services")) {
         listener.onSmsCodeReceived(patternCode(cursor
           .getString(cursor.getColumnIndex("body"))));
        }
       }
      }    }
     cursor.close();
    }
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  } /**
   * 匹配短信中间的6个数字(验证码等)
   * 
   * @param patternContent
   * @return
   */
  private String patternCode(String patternContent) {
   if (TextUtils.isEmpty(patternContent)) {
    return "";
   }
   Pattern p = Pattern.compile(patternCoder);
   Matcher matcher = p.matcher(patternContent);
   if (matcher.find()) {
    return matcher.group();
   }
   return "";
  }
  /**
   * 判断短信中间是否包含6位数字(验证码等)
   * true:包含;false:不包含
   * @param patternContent
   * @return
   */
  private boolean hasSixNumOrNot(String patternContent) {
   if (TextUtils.isEmpty(patternContent)) {
    return false;
   }
   Pattern p = Pattern.compile(patternCoder);
   Matcher matcher = p.matcher(patternContent);
   if (matcher.find()) {
    return true;
   }
   return false;
  } /**
   * @Description: 监听短信数据
   */
  class SmsObserver extends ContentObserver {  public SmsObserver(Handler handler) {
    super(handler);
   }  @Override
   public void onChange(boolean selfChange) {
    super.onChange(selfChange);
    LogUtil.i("selfChange===" + selfChange);
    getVerifyCodeFromSms();
   }
  }
 }

     其中,SmsObserver是监听短信库变化的类,当短信库发生变化的时候会走OnChange的回调,此时遍历短信库,取出最近一条信息,信息包含的内容已经标记在代码的文档注释中,通过限制条件判断收到短信是否是工程所需发件人发过来的信息,同时根据正则表达式取出数字验证码,并通过SmsCodeReceivedListener接口,对外暴露所取出的短信验证码,在外面输入框就可以接收短信验证码。在关闭页面的时候,要调用unRegisterContentObserver()方法,取消对短信库的监听,以防内存泄露。

       二:通过自定义广播接收器,接收短信发过来的广播内容。代码如下

     

public class SMSReceiver extends BroadcastReceiver {
 public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
  private Context context;
  private EditText editText;
  private String patternCoder = "(?<!\\d)\\d{4}(?!\\d)"; public SMSReceiver(Context context, EditText editText) {
   super();
   this.context = context;
   this.editText = editText;
  } @Override
  public void onReceive(Context context, Intent intent) {
   if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {
    SmsMessage[] messages = getMessagesFromIntent(intent);
    for (SmsMessage message : messages) {
     LogUtil.i(message.getOriginatingAddress() + " : "
       + message.getDisplayOriginatingAddress() + " : "
       + message.getDisplayMessageBody() + " : "
       + message.getTimestampMillis());
     String smsContent = message.getDisplayMessageBody();
     LogUtil.i(smsContent);
     editText.setText(patternCode(smsContent));
    }
   }
  } public final SmsMessage[] getMessagesFromIntent(Intent intent) {
   Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
   byte[][] pduObjs = new byte[messages.length][];
   for (int i = 0; i < messages.length; i++) {
    pduObjs[i] = (byte[]) messages[i];
   }
   byte[][] pdus = new byte[pduObjs.length][];
   int pduCount = pdus.length;
   SmsMessage[] msgs = new SmsMessage[pduCount];
   for (int i = 0; i < pduCount; i++) {
    pdus[i] = pduObjs[i];
    msgs[i] = SmsMessage.createFromPdu(pdus[i]);
   }
   return msgs;
  } /**
   * 匹配短信中间的4个数字(验证码等)
   * 
   * @param patternContent
   * @return
   */
  private String patternCode(String patternContent) {
   if (TextUtils.isEmpty(patternContent)) {
    return null;
   }
   Pattern p = Pattern.compile(patternCoder);
   Matcher matcher = p.matcher(patternContent);
   if (matcher.find()) {
    return matcher.group();
   }
   return null;
  }}

       SmsMessage的详细用法可以参考API或者网上搜索一下具体用法。至于广播的注册和解绑都是基本知识,也不再赘述。

       其他还要注意在清单配置文件中加上短信读写和接收权限

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

另外,所谓的短信获取并自动填充,是在发送的短信格式是合法格式的前提下才成立,测试在短信平台发送的不合法的短信模板应该是不可能完全限制并拦截的。比如交易短信只包含6位数字,那合法短信本身就应该只会包含六位连续数字,不会在短信中出现几个连续六位数字,这是不合理的。