实际应用开发中,会经常用到短信验证的功能,这个时候如果再让用户就查看短信.然后再回到界面进行短信的填写,难免有多少有些不方便,作为开发者.本着用户至上的原则我们也应该来实现验证码的自动填写功能,实现短信验证码自动填写有两种方式:
第一种,实现ContentObserver,把我们自己的Observer注册到短信服务,短信应用收到新的短信的时候会发送给我我们自己的Observer,然后我们在自己的Observer中.通过代码发送给我们的需要填充的界面就行了.这种方式是利用了观察者模式 .
SmsObserver的代码:
/** * */ package com.example.testgetsmscode; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.util.Log; /** * @author imgod 观察者模式 */ public class SmsObserver extends ContentObserver { private Context context; private Handler handler; private String compileValue; /** * @param context * 上下文对象 * @param handler * handler对象,需要把code发送回去 * @param codeLength * 验证码的长度,一个数字 */ public SmsObserver(Context context, Handler handler, int codeLength) { super(handler); // TODO Auto-generated constructor stub this.context = context; this.handler = handler; compileValue = "\\d{" + codeLength + "}"; } // 09-26 08:09:52.182: E/smsobserver(1239): selfChange:falseUri:content://sms/1 // 09-26 08:09:53.692: E/smsobserver(1239): selfChange:falseUri:content://sms/raw // 收到短信一般来说都是执行了两次onchange方法.第一次一般都是raw的这个.这个时候虽然收到了短信.但是短信还没有写入到收件箱里面 // 然后才是另外一个,后面的数字是该短信在收件箱中的位置 @Override public void onChange(boolean selfChange, Uri uri) { Log.e("smsobserver", "selfChange:" + selfChange + "Uri:" + uri.toString()); if (uri.toString().equals("content://sms/raw")) { return; } // 降序查询我们的数据库,原作者代码竟然uri是"content://sms/inbox",而且还加了个查询条件(时间降序..)..感觉有点多此一举.. Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { String address = cursor.getString(cursor.getColumnIndex("address")); String body = cursor.getString(cursor.getColumnIndex("body")); Log.e("smsobserver", "get sms:address:" + address + "body:" + body); cursor.close();// 最后用完游标千万记得关闭 // 在这里我们的短信提供商的号码如果是固定的话.我们可以再加一个判断,这样就不会受到别的短信应用的验证码的影响了 // 不然的话就在我们的正则表达式中,加一些自己的判断,例如短信中含有自己应用名字啊什么的... // if (!address.equals("13676900000")) { // return; // } // 正则表达式的使用,从一段字符串中取出六位连续的数字 Pattern pattern = Pattern.compile(compileValue); Matcher matcher = pattern.matcher(body); if (matcher.find()) { // String Log.e("smsobserver", "code:" + matcher.group(0)); Log.e("smsobserver", "contentObserver get code time:" + System.currentTimeMillis()); // 利用handler将得到的验证码发送给主界面 Message msg = Message.obtain(); msg.what = MainActivity.msg_received_code; msg.obj = matcher.group(0); handler.sendMessage(msg); } else { Log.e("smsobserver", "没有在短信中获取到合格的验证码"); } } else { Log.e("smsobserver", "movetofirst为false了"); } } else { Log.e("smsobserver", "cursor为null了"); } } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } /** * 将我们的ContentObserver注册一下 */ private void initView() { // TODO Auto-generated method stub et_main = (EditText) findViewById(R.id.et_main); // 验证码长度为6 mSmsObserver = new SmsObserver(MainActivity.this, mHandler, 6); Uri uri = Uri.parse("content://sms"); getContentResolver().registerContentObserver(uri, true, mSmsObserver); }
/* * (non-Javadoc) 取消注册 * * @see android.app.Activity#onDestroy() */ @Override protected void onDestroy() { super.onDestroy(); getContentResolver().unregisterContentObserver(mSmsObserver); }
public static final int msg_received_code = 1; public Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == msg_received_code) { String code = (String) msg.obj; et_main.setText(code); Log.e("mainactivity", "activity get code time:" + System.currentTimeMillis()); } }; };
<!-- 千万不要忘记声明权限,没有声明权限的时候,竟然还是可以得到收到短信通知的.但是读取不到短信的内容 --> <uses-permission android:name="android.permission.READ_SMS" />
第二种,我们自己的应用创建一个广播接收器,接受短信变化的广播,然后在收到广播的时候,再把验证码提取出来发送给我们的需要填充验证码的地方就行了
广播接收器的代码:
/** * */ package com.example.testsendandreceivesms; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.telephony.SmsMessage; import android.util.Log; /** * @author imgod * */ public class SmsReceiveBroadcastReceiver extends BroadcastReceiver { private Context context; private Handler handler; private int codeLength = 0; /** * */ public SmsReceiveBroadcastReceiver(Context context, Handler handler, int codeLength) { // TODO Auto-generated constructor stub this.context = context; this.handler = handler; this.codeLength = codeLength; } @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Bundle bundle = intent.getExtras(); Object[] objects = (Object[]) bundle.get("pdus"); if (objects != null) { String phone = null; StringBuffer content = new StringBuffer(); for (int i = 0; i < objects.length; i++) { SmsMessage sms = SmsMessage.createFromPdu((byte[]) objects[i]); phone = sms.getDisplayOriginatingAddress(); content.append(sms.getDisplayMessageBody()); } Log.e("smsbc", "phone:" + phone + "\ncontent:" + content.toString()); checkCodeAndSend(content.toString()); } } /** * @param content */ private void checkCodeAndSend(String content) { // 话说.如果我们的短信提供商的短信号码是固定的话.前面可以加一个判断 // 正则表达式验证是否含有验证码 Pattern pattern = Pattern.compile("\\d{" + codeLength + "}");// compile的是规则 Matcher matcher = pattern.matcher(content);// matcher的是内容 if (matcher.find()) { String code = matcher.group(0); Log.e("smsbc", "短信中找到了符合规则的验证码:" + code); handler.obtainMessage(MainActivity.BC_SMS_RECEIVE, code).sendToTarget(); Log.e("smsbc", "广播接收器接收到短信的时间:" + System.currentTimeMillis()); } else { Log.e("smsbc", "短信中没有找到符合规则的验证码"); } } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); broadcastReceiver = new SmsReceiveBroadcastReceiver(MainActivity.this, handler, 6); IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(broadcastReceiver, intentFilter); initView(); } /* * (non-Javadoc) * * @see android.app.Activity#onDestroy() */ @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(broadcastReceiver); }
handler:
private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == BC_SMS_RECEIVE) { String code = (String) msg.obj; tv_sms_code.setText(code); Log.e("mainactivity", "界面收到短信的时间:" + System.currentTimeMillis()); } }; };
特别注意权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>