短信验证码自动填写的原理主要是ContentObserver监听短信变化,提取验证码,填写到相应的位置上。
ContentObserver类:内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,类似于数据库技术中的触发器,当ContentObserver所观察的Uri发生变化时,便会触发它。
观察者模式:此模式是软件设计模式中的一种,在此模式中,一个目标物件管理所有相依附它的观察者物件,并且在它本身的状态改变时主动发出通知。通常透过呼叫观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。此模式完美的将观察者和被观察者的对象分离开,在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动更新。
布局很简单,就放一个EditText,权限中加入<uses-permission android:name="android.permission.READ_SMS" />,主页面代码:
public static final int MSG_RECEIVED_CODE = 1;
private EditText et_ValidateCode = null;
private SmsObserver mObserver;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_RECEIVED_CODE) {
String code = (String)msg.obj;
//update the UI
et_ValidateCode.setText(code);
}
}
};
@Override
protected void onPause() {
super.onPause();
getContentResolver().unregisterContentObserver(mObserver);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_ValidateCode = (EditText)findViewById(R.id.et_validateCode);
mObserver = new SmsObserver(MainActivity.this, mHandler);
Uri uri = Uri.parse("content://sms");
getContentResolver().registerContentObserver(uri, true, mObserver);
}
就是通过handler在非UI线程中更新UI,填写验证码,重点是SmsObserver,下面看它的代码:
public class SmsObserver extends ContentObserver {
private Context mContext;
private Handler mHandler;
public SmsObserver(Context context, Handler handler) {
super(handler);
mContext = context;
mHandler = handler;
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.e("DEBUG", "SMS has changed!");
Log.e("DEBUG", uri.toString());
String code = "";
//第一次变化还没存储到数据库中,要的是第二次的
if (uri.toString().equals("content://sms/raw")) {
return;
}
Uri inboxUri = Uri.parse("content://sms/inbox");
Cursor c = mContext.getContentResolver().query(inboxUri, null, null, null, "date desc");
if (c != null) {
if (c.moveToFirst()) {
String address = c.getString(c.getColumnIndex("address"));
String body = c.getString(c.getColumnIndex("body"));
//如果不是正确的发件人
if (!address.equals("15555215556")) {
return;
}
Log.e("DEBUG", "发件人为:" + address + " " + "短信内容为:" + body);
//正则表达式,连续6个数字
Pattern pattern = Pattern.compile("(\\d{6})");
Matcher matcher = pattern.matcher(body);
if (matcher.find()) {
code = matcher.group(0);
Log.e("DEBUG", "code is " + code);
mHandler.obtainMessage(MainActivity.MSG_RECEIVED_CODE, code).sendToTarget();
}
}
c.close();
}
}
}
其中的Uri要注意,我们需要的是存储好数据后的sms/inbox的Uri,在得到短信数据后通过手机号码的匹配判断是否是我们想要的发送人,利用正则取得六个连续的数字(通常验证码是6个连续数字,此处也可自定义正则表达式),得到验证码后通过Handler传送出去,重点还是Uri的处理。