已开通简书博客,欢迎拍砖。
Cursor用来直接读取安卓手机里的数据库记录,如何获取到Cursor?
- 可以通过SQLiteOpenHelper,打开SQLiteDatabase
- 通过ContentProvider/ContentResolver获取
自动读取验证码实现思路:
- 当验证码的短信到来,能有个监听回调或者广播之类,告知开发人员
- 读取短信是危险权限,android6.0权限适配
- 获取验证码的短信内容
- 从短信内容里刷选出验证码
- 显示验证码
接下来针对每一个步骤,做些分析和代码分享
监听接收到新短信
使用ContentResolver,引入内容观察者,监听短信内容的变化,代码如下:
public void register(){
mReadSmsContentObserver = new ReadSmsContentObserver(new Handler());
mContext.getContentResolver().registerContentObserver(URI_SMS,true,mReadSmsContentObserver);
}
class ReadSmsContentObserver extends ContentObserver{
public ReadSmsContentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
LOG.e(TAG,"selfChange = " + selfChange+" uri = " + uri);
if(PermissionHelper.checkReadSmsPermission(mContext)){
initReadSmsLoader();
}else{
takeReadSmsPermission();
}
}
}
短信验证码,权限适配
PermissionHelper是自己封装的工具类
PermissionHelper.takeReadSmsPermission(this,PermissionHelper.REQUEST_CODE_READ_SMS);
获取验证码的短信内容
这里有多个方案,网上相当多技术文章使用contentResolver.query()方法。我认为这个方法不够好。
- 该方法在UI线程里操作的,当查询的数据库的记录很多时,会出现卡顿现象。
- 需要手动关闭Cursor,Cursor维护操作交给开发人员。
好在,安卓已经提供了异步的(子线程)数据库查询方式,使用LoaderManager和CursorLoader这两个类,不存在上述两个问题。代码如下
更详细的LoaderManager.LoaderCallbacks各个回调方法的使用,可以参考android CursorLoader用法介绍
/**
* 注册内容观察者
*/
public void register(){
mReadSmsContentObserver = new ReadSmsContentObserver(new Handler());
mContext.getContentResolver().registerContentObserver(URI_SMS,true,mReadSmsContentObserver);
}
public class ReadSmsLoaderListener implements LoaderManager.LoaderCallbacks<Cursor>{
private static Uri URI_SMS_INBOX = Uri.parse("content://sms/inbox");
// "_id", "address", "person", "date", "type"
private static final String[] READ_SMS_PROJECTION = new String[]{"body"};
private static final String READ_SMS_SORT_ORDER = "date desc";
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//两分钟内,收到的短信,date降序排列
String readSmsWhere = "date >" + (System.currentTimeMillis() - 2*60*1000);
return new CursorLoader(mContext,URI_SMS_INBOX,READ_SMS_PROJECTION,readSmsWhere,null,READ_SMS_SORT_ORDER);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
fetchSmsCodeFromCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}
/**
* 从数据库获取短信并过滤出验证码
*/
private void fetchSmsCodeFromCursor(Cursor cursor) {
if(cursor != null) {
while (cursor.moveToNext()) {
String body = cursor.getString(cursor.getColumnIndex("body"));
if (!TextUtils.isEmpty(body)) {
//判断该短信是否是该App发送的
if (body.contains("走么")) {
String verifyCode = getSmsCode(body);
displayVerifyCode(verifyCode);
break;
}
}
}
}
}
从短信内容里刷选出验证码
使用正则表达式筛选,按正则的使用套路走起
/**
* 从短信中获取验证码
* @param smsContent 短信内容
* @return
*/
private String getSmsCode(String smsContent){
Pattern pattern = Pattern.compile("[0-9]{4,}");
Matcher m = pattern.matcher(smsContent);
while (m.find()) {
String group = m.group();
if(group != null && group.length() >= VERIFY_CODE_LENGTH){
return group;
}
}
return "";
}
显示验证码
/**
* 显示验证码
* @param verifyCode 验证码
*/
private void displayVerifyCode(String verifyCode) {
mSmsCodeEt.setText(verifyCode);
//获取焦点
mSmsCodeEt.setFocusable(true);
mSmsCodeEt.setFocusableInTouchMode(true);
mSmsCodeEt.requestFocus();
//设置光标位置
mSmsCodeEt.setSelection(verifyCode.length());
}
总结
至此,成功实现读取短信验证码。近来主流的App,并没有实现自动读取短信验证码,比如滴滴出行,钉钉。
参考资料
Google Android API 查询(可直接访问)