首页

源码搜藏网

首页 > 安卓源码 > 技术博客 >

android开发两种方式实现短信验证码自动填写功能

创建时间:2017-10-13 17:28  浏览

实际应用开发中,会经常用到短信验证的功能,这个时候如果再让用户就查看短信.然后再回到界面进行短信的填写,难免有多少有些不方便,作为开发者.本着用户至上的原则我们也应该来实现验证码的自动填写功能,实现短信验证码自动填写有两种方式:

第一种,实现ContentObserver,把我们自己的Observer注册到短信服务,短信应用收到新的短信的时候会发送给我我们自己的Observer,然后我们在自己的Observer中.通过代码发送给我们的需要填充的界面就行了.这种方式是利用了观察者模式 .

 

SmsObserver的代码:

 

[java] view plain copy
 
  1. /** 
  2.  *  
  3.  */  
  4. package com.example.testgetsmscode;  
  5.   
  6. import java.util.regex.Matcher;  
  7. import java.util.regex.Pattern;  
  8.   
  9. import android.content.Context;  
  10. import android.database.ContentObserver;  
  11. import android.database.Cursor;  
  12. import android.net.Uri;  
  13. import android.os.Handler;  
  14. import android.os.Message;  
  15. import android.util.Log;  
  16.   
  17. /** 
  18.  * @author imgod 观察者模式 
  19.  */  
  20. public class SmsObserver extends ContentObserver {  
  21.   
  22.     private Context context;  
  23.     private Handler handler;  
  24.     private String compileValue;  
  25.   
  26.     /** 
  27.      * @param context 
  28.      *            上下文对象 
  29.      * @param handler 
  30.      *            handler对象,需要把code发送回去 
  31.      * @param codeLength 
  32.      *            验证码的长度,一个数字 
  33.      */  
  34.     public SmsObserver(Context context, Handler handler, int codeLength) {  
  35.         super(handler);  
  36.         // TODO Auto-generated constructor stub  
  37.         this.context = context;  
  38.         this.handler = handler;  
  39.         compileValue = "\\d{" + codeLength + "}";  
  40.     }  
  41.   
  42.     // 09-26 08:09:52.182: E/smsobserver(1239): selfChange:falseUri:content://sms/1  
  43.     // 09-26 08:09:53.692: E/smsobserver(1239): selfChange:falseUri:content://sms/raw  
  44.     // 收到短信一般来说都是执行了两次onchange方法.第一次一般都是raw的这个.这个时候虽然收到了短信.但是短信还没有写入到收件箱里面  
  45.     // 然后才是另外一个,后面的数字是该短信在收件箱中的位置  
  46.     @Override  
  47.     public void onChange(boolean selfChange, Uri uri) {  
  48.         Log.e("smsobserver""selfChange:" + selfChange + "Uri:" + uri.toString());  
  49.   
  50.         if (uri.toString().equals("content://sms/raw")) {  
  51.             return;  
  52.         }  
  53.   
  54.         // 降序查询我们的数据库,原作者代码竟然uri是"content://sms/inbox",而且还加了个查询条件(时间降序..)..感觉有点多此一举..  
  55.         Cursor cursor = context.getContentResolver().query(uri, nullnullnullnull);  
  56.         if (cursor != null) {  
  57.             if (cursor.moveToFirst()) {  
  58.                 String address = cursor.getString(cursor.getColumnIndex("address"));  
  59.                 String body = cursor.getString(cursor.getColumnIndex("body"));  
  60.                 Log.e("smsobserver""get sms:address:" + address + "body:" + body);  
  61.                 cursor.close();// 最后用完游标千万记得关闭  
  62.   
  63.                 // 在这里我们的短信提供商的号码如果是固定的话.我们可以再加一个判断,这样就不会受到别的短信应用的验证码的影响了  
  64.                 // 不然的话就在我们的正则表达式中,加一些自己的判断,例如短信中含有自己应用名字啊什么的...  
  65.                 // if (!address.equals("13676900000")) {  
  66.                 // return;  
  67.                 // }  
  68.   
  69.                 // 正则表达式的使用,从一段字符串中取出六位连续的数字  
  70.                 Pattern pattern = Pattern.compile(compileValue);  
  71.                 Matcher matcher = pattern.matcher(body);  
  72.                 if (matcher.find()) {  
  73.                     // String  
  74.                     Log.e("smsobserver""code:" + matcher.group(0));  
  75.                     Log.e("smsobserver""contentObserver get code time:" + System.currentTimeMillis());  
  76.   
  77.                     // 利用handler将得到的验证码发送给主界面  
  78.                     Message msg = Message.obtain();  
  79.                     msg.what = MainActivity.msg_received_code;  
  80.                     msg.obj = matcher.group(0);  
  81.                     handler.sendMessage(msg);  
  82.                 } else {  
  83.                     Log.e("smsobserver""没有在短信中获取到合格的验证码");  
  84.                 }  
  85.   
  86.             } else {  
  87.                 Log.e("smsobserver""movetofirst为false了");  
  88.             }  
  89.         } else {  
  90.             Log.e("smsobserver""cursor为null了");  
  91.         }  
  92.     }  
  93.   
  94. }  

 

 

主界面中的使用方法:

 

[java] view plain copy
 
  1. @Override  
  2.     protected void onCreate(Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.         setContentView(R.layout.activity_main);  
  5.         initView();  
  6.     }  
  7.   
  8.     /** 
  9.      * 将我们的ContentObserver注册一下 
  10.      */  
  11.     private void initView() {  
  12.         // TODO Auto-generated method stub  
  13.         et_main = (EditText) findViewById(R.id.et_main);  
  14.         // 验证码长度为6  
  15.         mSmsObserver = new SmsObserver(MainActivity.this, mHandler, 6);  
  16.         Uri uri = Uri.parse("content://sms");  
  17.         getContentResolver().registerContentObserver(uri, true, mSmsObserver);  
  18.     }  

注册之后,肯定要在界面销毁的时候取消注册咯:

 

 

[java] view plain copy
 
  1. /* 
  2.      * (non-Javadoc) 取消注册 
  3.      *  
  4.      * @see android.app.Activity#onDestroy() 
  5.      */  
  6.     @Override  
  7.     protected void onDestroy() {  
  8.         super.onDestroy();  
  9.         getContentResolver().unregisterContentObserver(mSmsObserver);  
  10.     }  

在ContentObserver构造方法中,我们传递了一个handler对象,目的就是通过handler把我们得到的短信验证码给接收过来:

 

 

[java] view plain copy
 
  1. public static final int msg_received_code = 1;  
  2.     public Handler mHandler = new Handler() {  
  3.         public void handleMessage(android.os.Message msg) {  
  4.             if (msg.what == msg_received_code) {  
  5.                 String code = (String) msg.obj;  
  6.                 et_main.setText(code);  
  7.                 Log.e("mainactivity""activity get code time:" + System.currentTimeMillis());  
  8.   
  9.             }  
  10.         };  
  11.     };  

最后的最后,一定不要忘记加权限:

 

 

[html] view plain copy
 
  1. <!-- 千万不要忘记声明权限,没有声明权限的时候,竟然还是可以得到收到短信通知的.但是读取不到短信的内容 -->  
  2.    <uses-permission android:name="android.permission.READ_SMS" />  


顺便一提:这种方式实现的验证码自动填写功能,在android2.3上竟然没有效果,在4.0上没问题,欢迎纠正和补充..

 

 

 

 

第二种,我们自己的应用创建一个广播接收器,接受短信变化的广播,然后在收到广播的时候,再把验证码提取出来发送给我们的需要填充验证码的地方就行了

 

广播接收器的代码:

 

[java] view plain copy
 
  1. /** 
  2.  *  
  3.  */  
  4. package com.example.testsendandreceivesms;  
  5.   
  6. import java.util.regex.Matcher;  
  7. import java.util.regex.Pattern;  
  8.   
  9. import android.content.BroadcastReceiver;  
  10. import android.content.Context;  
  11. import android.content.Intent;  
  12. import android.os.Bundle;  
  13. import android.os.Handler;  
  14. import android.telephony.SmsMessage;  
  15. import android.util.Log;  
  16.   
  17. /** 
  18.  * @author imgod 
  19.  * 
  20.  */  
  21. public class SmsReceiveBroadcastReceiver extends BroadcastReceiver {  
  22.   
  23.     private Context context;  
  24.     private Handler handler;  
  25.     private int codeLength = 0;  
  26.   
  27.     /** 
  28.      *  
  29.      */  
  30.     public SmsReceiveBroadcastReceiver(Context context, Handler handler, int codeLength) {  
  31.         // TODO Auto-generated constructor stub  
  32.         this.context = context;  
  33.         this.handler = handler;  
  34.         this.codeLength = codeLength;  
  35.     }  
  36.   
  37.     @Override  
  38.     public void onReceive(Context context, Intent intent) {  
  39.         // TODO Auto-generated method stub  
  40.         Bundle bundle = intent.getExtras();  
  41.         Object[] objects = (Object[]) bundle.get("pdus");  
  42.         if (objects != null) {  
  43.             String phone = null;  
  44.             StringBuffer content = new StringBuffer();  
  45.             for (int i = 0; i < objects.length; i++) {  
  46.                 SmsMessage sms = SmsMessage.createFromPdu((byte[]) objects[i]);  
  47.                 phone = sms.getDisplayOriginatingAddress();  
  48.                 content.append(sms.getDisplayMessageBody());  
  49.             }  
  50.             Log.e("smsbc""phone:" + phone + "\ncontent:" + content.toString());  
  51.             checkCodeAndSend(content.toString());  
  52.         }  
  53.     }  
  54.   
  55.     /** 
  56.      * @param content 
  57.      */  
  58.     private void checkCodeAndSend(String content) {  
  59.         // 话说.如果我们的短信提供商的短信号码是固定的话.前面可以加一个判断  
  60.         // 正则表达式验证是否含有验证码  
  61.         Pattern pattern = Pattern.compile("\\d{" + codeLength + "}");// compile的是规则  
  62.         Matcher matcher = pattern.matcher(content);// matcher的是内容  
  63.         if (matcher.find()) {  
  64.             String code = matcher.group(0);  
  65.             Log.e("smsbc""短信中找到了符合规则的验证码:" + code);  
  66.             handler.obtainMessage(MainActivity.BC_SMS_RECEIVE, code).sendToTarget();  
  67.             Log.e("smsbc""广播接收器接收到短信的时间:" + System.currentTimeMillis());  
  68.         } else {  
  69.             Log.e("smsbc""短信中没有找到符合规则的验证码");  
  70.         }  
  71.     }  
  72.   
  73. }  

主界面中的使用:

 

 

[java] view plain copy
 
  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.     setContentView(R.layout.activity_main);  
  5.   
  6.     broadcastReceiver = new SmsReceiveBroadcastReceiver(MainActivity.this, handler, 6);  
  7.     IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");  
  8.     registerReceiver(broadcastReceiver, intentFilter);  
  9.     initView();  
  10. }  
  11.   
  12. /* 
  13.  * (non-Javadoc) 
  14.  *  
  15.  * @see android.app.Activity#onDestroy() 
  16.  */  
  17. @Override  
  18. protected void onDestroy() {  
  19.     // TODO Auto-generated method stub  
  20.     super.onDestroy();  
  21.     unregisterReceiver(broadcastReceiver);  
  22. }  

 

handler:

 

[java] view plain copy
 
  1. private Handler handler = new Handler() {  
  2.         public void handleMessage(android.os.Message msg) {  
  3.             if (msg.what == BC_SMS_RECEIVE) {  
  4.                 String code = (String) msg.obj;  
  5.                 tv_sms_code.setText(code);  
  6.                 Log.e("mainactivity""界面收到短信的时间:" + System.currentTimeMillis());  
  7.             }  
  8.         };  
  9.     };  


 

特别注意权限:  

 

[html] view plain copy
 
  1. <uses-permission android:name="android.permission.RECEIVE_SMS"/>  

这种实现方式在android2.3上和android4.0上都表现良好,别的没测试,

 


和上一种方法一样,也是需要注册和取消注册操作的,而且,因为同样都是利用了handler把得到的内容发送回来.所以发送内容的效率产不多,不过在接受短信的效率上要比上一种方式要好.毕竟上一种方式是短信应用收到短信,然后再向他发送,而使用广播的话.直接就是从源头上进行接收短信了
短信自动填充demo下载:
https://github.com/zhouxu88/SMSContentObserver
上一篇:Android开发 百度云OCR识别身份证,银行卡等证件信息
下一篇:Android利用奇虎DroidPlugin实现插件化

相关内容

热门推荐