首页 > 技术文章 > 通过监听短信和正则表达式实现自动填写短信验证码

demon9 2016-11-16 15:41 原文

 

实现短信监听要用到广播,这里我在Service里面注册这个广播

 

在activity里面启动service

intent = new Intent(MainActivity.this, SmsService.class);

intent.putExtra("cmd", 1);
startService(intent);

 

 

接下来看 service

在service的onCreate方法中 通过startForeground  让服务前台运行

在 onStartCommand方法中 接受到 activity 启动监听的指令,注册接收者

要注意优先级要尽量设高, Action为

android.provider.Telephony.SMS_RECEIVED

在广播接受者的 onReceive方法  9-19行 取出需要的短信信息

拿到短信内容后,就可以进行验证码匹配

 

举两个验证码短信例子

【百度】您在百度开发者中心进行的手机验证的验证码为:313253,请输入后进行验证,谢谢![百度开发者中心]
【哔哩哔哩】951422 为你的手机绑定验证码,请在5分钟内完成手机绑定。如非本人操作,请忽略或回复T退订。

 

通常手机接受到的验证码都是 4位或者6位的纯数字

可以用  \d{4,6}(?!\d)   , 红色部分 表示 4到6位的数字,粉色表示后面不能为数字,其实这个可有可无

 

如果遇到的是 数字字母混合的

可以用 [A-Za-z0-9]{4,}(?![A-Za-z0-9])   红色部分表示符合 A到Z a到z 0到9的这个类型 的字符,粉色表示四位以上 ,后面同上

没有使用\w 是因为\w 还可以代表汉字

 

^((https|http)?:\/\/)[^\s]+[jpg]

图片地址例子 

 

对于不同的短信验证码模板,肯定有不同的方法,我写的只是一种思路,不可能所有都适用,如果收到一条国外的验证码短信,就不是上面那么简单了

 

  1 public class SmsService extends Service {
  2 
  3     private NotificationManager manger;
  4     public static NotificationCompat.Builder builder;
  5     private BroadcastReceiver receiver = new BroadcastReceiver() {
  6         @Override
  7         public void onReceive(Context context, Intent intent) {
  8 
  9             SmsMessage msg = null;
 10             Bundle bundle = intent.getExtras();
 11             if (bundle != null) {
 12                 Object[] pdusObj = (Object[]) bundle.get("pdus");
 13                 for (Object p : pdusObj) {
 14                     msg = SmsMessage.createFromPdu((byte[]) p);
 15                     String msgTxt = msg.getMessageBody();//得到消息的内容
 16                     Date date = new Date(msg.getTimestampMillis());//时间
 17                     SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 18                     String receiveTime = format.format(date);
 19                     String senderNumber = msg.getOriginatingAddress();
 20                     //Toast.makeText(context, "发送人:" + senderNumber + "  短信内容:" + msgTxt + "接受时间:" + receiveTime, Toast.LENGTH_LONG).show();
 21 
 22 
 23                     //   \d{4,6}(?!\d)
 24                     // [A-Za-z0-9]{4,}(?![A-Za-z0-9])
 25                     Pattern pattern=Pattern.compile("[A-Za-z0-9]{4,}(?![A-Za-z0-9])");
 26                     Matcher matcher=pattern.matcher(msgTxt);
 27                     if (matcher.find()){
 28                         String code=matcher.group(0);
 29                         Toast.makeText(context,"验证码是 "+code,Toast.LENGTH_LONG).show();
 30                         context.sendBroadcast(new Intent().setAction("yzm").putExtra("code",code));
 31                         createNotification(code);
 32                     }
 33                     return;
 34                 }
 35                 return;
 36             }
 37         }
 38     };
 39 
 40     private void createNotification(String code) {
 41         NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
 42         builder.setSmallIcon(R.mipmap.ic_launcher);
 43         builder.setAutoCancel(true);
 44         builder.setContentTitle("收到验证码 "+code);
 45 
 46         Intent[] intents = new Intent[2];
 47         intents[0]=Intent.makeRestartActivityTask(new ComponentName(this,MainActivity.class));
 48         intents[1]=new Intent(this,CodeActivity.class);
 49         intents[1].putExtra("code",code);
 50 
 51         PendingIntent pendingIntent = PendingIntent.getActivities(this, 0, intents, PendingIntent.FLAG_UPDATE_CURRENT);
 52         builder.setContentIntent(pendingIntent);
 53 
 54         Notification notification = builder.build();
 55         manger.notify(666, notification);
 56     }
 57 
 58 
 59     @Nullable
 60     @Override
 61     public IBinder onBind(Intent intent) {
 62         return null;
 63     }
 64 
 65     @Override
 66     public void onCreate() {
 67         super.onCreate();
 68         manger = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 69         builder = new NotificationCompat.Builder(this);
 70 
 71         builder.setSmallIcon(R.mipmap.ic_launcher);
 72         builder.setAutoCancel(true);
 73         builder.setContentTitle("sms listening");
 74 
 75         Intent intent = new Intent(this, MainActivity.class);
 76         PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
 77         builder.setContentIntent(pendingIntent);
 78 
 79         Notification notification = builder.build();
 80         //manger.notify(333, notification);
 81         startForeground(333, notification);
 82 
 83     }
 84 
 85     @Override
 86     public int onStartCommand(Intent intent, int flags, int startId) {
 87         int i = intent.getExtras().getInt("cmd");
 88         if (1 == i) {
 89             initReceiver();
 90         } else {
 91             stopForeground(true);
 92         }
 93         return super.onStartCommand(intent, flags, startId);
 94     }
 95 
 96 
 97     private void initReceiver() {
 98         IntentFilter intentFilter = new IntentFilter();
 99         intentFilter.setPriority(1000);
100         intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
101         registerReceiver(receiver, intentFilter);
102     }
103 
104     @Override
105     public void onDestroy() {
106         super.onDestroy();
107         unregisterReceiver(receiver);
108         stopForeground(true);
109     }
110 }

 

最后拿到验证码之后,从service里面发送广播,activity里面注册接收者,拿到验证码,填充给 EditText,当然也可以用EventBus

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            switch (intent.getAction()) {
                case "yzm":
                    editText.setText(intent.getExtras().getString("code"));
                    break;
            }
        }
    };

 

如果想停止service,应该在service的onDestroy方法中

unregisterReceiver    注销短信接收者

stopForeground      停止服务前台运行

 

正则学习       调试网址

 

github

推荐阅读