已開通簡書博客,歡迎拍磚。
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 查詢(可直接訪問)