Android實(shí)現(xiàn)短信驗(yàn)證碼獲取自動(dòng)填寫功能(詳細(xì)版)
現(xiàn)在的應(yīng)用在注冊登錄或者修改密碼中都用到了短信驗(yàn)證碼,那在android中是如何實(shí)現(xiàn)獲取短信驗(yàn)證碼并自動(dòng)填寫的呢?
首先,需要要在manifest中注冊接收和讀取短信的權(quán)限:
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.READ_SMS"/>
實(shí)現(xiàn)一個(gè)廣播SMSBroadcastReceiver來監(jiān)聽短信:
package com.example.receive; import java.text.SimpleDateFormat; import java.util.Date; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.SmsMessage; /** * 短信監(jiān)聽 * @author * */ public class SMSBroadcastReceiver extends BroadcastReceiver { private static MessageListener mMessageListener; public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; public SMSBroadcastReceiver() { super(); } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(SMS_RECEIVED_ACTION)) { Object[] pdus = (Object[]) intent.getExtras().get("pdus"); for(Object pdu:pdus) { SmsMessage smsMessage = SmsMessage.createFromPdu((byte [])pdu); String sender = smsMessage.getDisplayOriginatingAddress(); //短信內(nèi)容 String content = smsMessage.getDisplayMessageBody(); long date = smsMessage.getTimestampMillis(); Date tiemDate = new Date(date); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = simpleDateFormat.format(tiemDate); //過濾不需要讀取的短信的發(fā)送號碼 if ("+8613450214963".equals(sender)) { mMessageListener.onReceived(content); abortBroadcast(); } } } } //回調(diào)接口 public interface MessageListener { public void onReceived(String message); } public void setOnReceivedMessageListener(MessageListener messageListener) { this.mMessageListener = messageListener; } }
在需要填寫驗(yàn)證碼的Activity中,生產(chǎn)SMSBroadcastReceiver的實(shí)例,實(shí)現(xiàn)onReceived的回調(diào)接口。為了節(jié)約系統(tǒng)資源,我們使用動(dòng)態(tài)注冊注銷廣播的方法。
package com.example.smstest; import com.example.receive.SMSBroadcastReceiver; import android.os.Bundle; import android.app.Activity; import android.content.IntentFilter; import android.view.Menu; import android.widget.EditText; public class MainActivity extends Activity { private EditText edtPassword; private SMSBroadcastReceiver mSMSBroadcastReceiver; private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edtPassword = (EditText) findViewById(R.id.password); } @Override protected void onStart() { super.onStart(); //生成廣播處理 mSMSBroadcastReceiver = new SMSBroadcastReceiver(); //實(shí)例化過濾器并設(shè)置要過濾的廣播 IntentFilter intentFilter = new IntentFilter(ACTION); intentFilter.setPriority(Integer.MAX_VALUE); //注冊廣播 this.registerReceiver(mSMSBroadcastReceiver, intentFilter); mSMSBroadcastReceiver.setOnReceivedMessageListener(new SMSBroadcastReceiver.MessageListener() { @Override public void onReceived(String message) { edtPassword.setText(message); } }); } @Override protected void onDestroy() { super.onDestroy(); //注銷短信監(jiān)聽廣播 this.unregisterReceiver(mSMSBroadcastReceiver); } }
上面提供了一種獲取短信息驗(yàn)證碼并自動(dòng)填寫的實(shí)現(xiàn)方式,就是直接通過短信廣播監(jiān)聽短信。但是,這種方式有它的缺陷:當(dāng)你的手機(jī)安裝了其他一些短信應(yīng)用(例如QQ通訊錄)或者手機(jī)本身限制了權(quán)限的情況下,這種方式有可能會(huì)不起作用,無法做到自動(dòng)填寫,而且就算把優(yōu)先級設(shè)高,也不能保證不會(huì)被別的應(yīng)用“搶先”。
后來查資料知道,可以通過監(jiān)聽短信數(shù)據(jù)庫的方式實(shí)現(xiàn)。監(jiān)聽短信數(shù)據(jù)庫主要是通過ContentObserver這個(gè)類來完成。ContentObserver主要是通過Uri來監(jiān)測特定的Databases的表,當(dāng)ContentObserver所觀察的Uri發(fā)生變化時(shí),便會(huì)觸發(fā)它。思路就是監(jiān)聽短信數(shù)據(jù)庫中特定號碼的未讀短信。我們可以通過百度找到許多demo,但是我發(fā)現(xiàn)很多demo中存在著Bug,在接收到短信后引起崩潰。還有一種情況,當(dāng)真機(jī)連接著電腦,電腦裝有類似豌豆莢之類的軟件的時(shí)候,手機(jī)收到短信后,豌豆莢之類的可能會(huì)把該短信的狀態(tài)改成“已讀”,這樣也會(huì)導(dǎo)致崩潰。
通過調(diào)試,終于把Bug修復(fù)了,布局和短信權(quán)限就不再贅述。在MainActivity中增加一個(gè)內(nèi)部類SmsContent。
/** * 監(jiān)聽短信數(shù)據(jù)庫 */ class SmsContent extends ContentObserver { private Cursor cursor = null; public SmsContent(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //讀取收件箱中指定號碼的短信 cursor = managedQuery(Uri.parse("content://sms/inbox"), new String[]{"_id", "address", "read", "body"}, " address=? and read=?", new String[]{"1065811201", "0"}, "_id desc");//按id排序,如果按date排序的話,修改手機(jī)時(shí)間后,讀取的短信就不準(zhǔn)了 MyLog.l("cursor.isBeforeFirst() " + cursor.isBeforeFirst() + " cursor.getCount() " + cursor.getCount()); if (cursor != null && cursor.getCount() > 0) { ContentValues values = new ContentValues(); values.put("read", "1"); //修改短信為已讀模式 cursor.moveToNext(); int smsbodyColumn = cursor.getColumnIndex("body"); String smsBody = cursor.getString(smsbodyColumn); MyLog.v("smsBody = " + smsBody); edtPassword.setText(MatchesUtil.getDynamicPassword(smsBody)); } //在用managedQuery的時(shí)候,不能主動(dòng)調(diào)用close()方法, 否則在Android 4.0+的系統(tǒng)上, 會(huì)發(fā)生崩潰 if(Build.VERSION.SDK_INT < 14) { cursor.close(); } } }
記得在onCreate中注冊短信變化監(jiān)聽
SmsContent content = new SmsContent(new Handler()); //注冊短信變化監(jiān)聽 this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, content);
記得注銷監(jiān)聽
this.getContentResolver().unregisterContentObserver(content);
其中,下發(fā)的驗(yàn)證碼短信一般都是一個(gè)字符串,其中包含6位數(shù)字,我們需要把這6位數(shù)字提取出來,我們可以用正則表達(dá)式寫一個(gè)靜態(tài)方法。
/** * 從字符串中截取連續(xù)6位數(shù)字 * 用于從短信中獲取動(dòng)態(tài)密碼 * @param str 短信內(nèi)容 * @return 截取得到的6位動(dòng)態(tài)密碼 */ public static String getDynamicPassword(String str) { Pattern continuousNumberPattern = Pattern.compile("[0-9\\.]+"); Matcher m = continuousNumberPattern.matcher(str); String dynamicPassword = ""; while(m.find()){ if(m.group().length() == 6) { System.out.print(m.group()); dynamicPassword = m.group(); } } return dynamicPassword; }
至此,android獲取短信驗(yàn)證碼并自動(dòng)填寫的功能就實(shí)現(xiàn)了。
補(bǔ)充:對于上面短信數(shù)據(jù)庫監(jiān)聽中有個(gè)直接關(guān)閉游標(biāo)的操作(現(xiàn)在已經(jīng)更正):cursor.close();
但是,如果這樣直接關(guān)閉的話,會(huì)引起崩潰。例如,當(dāng)獲取了短信密碼,自動(dòng)填寫上了之后,按home鍵返回桌面,然后再進(jìn)入應(yīng)用,會(huì)引起應(yīng)用崩潰。報(bào)的錯(cuò)是:
android.database.StaleDataException: Attempted to access a cursor after it has been closed
后來通過查資料得知,是用managedQuery的時(shí)候, 不能主動(dòng)調(diào)用close()方法, 否則在Android 4.0+的系統(tǒng)上, 會(huì)發(fā)生崩潰。對版本進(jìn)行一個(gè)判斷再執(zhí)行關(guān)閉游標(biāo)的操作。
//在用managedQuery的時(shí)候,不能主動(dòng)調(diào)用close()方法, 否則在Android 4.0+的系統(tǒng)上, 會(huì)發(fā)生崩潰 if(Build.VERSION.SDK_INT < 14) { cursor.close(); }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android如何通過手機(jī)獲取驗(yàn)證碼來完成注冊功能
- Android開發(fā)中通過手機(jī)號+短信驗(yàn)證碼登錄的實(shí)例代碼
- Android開發(fā)工程中集成mob短信驗(yàn)證碼功能的方法
- Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法
- Android實(shí)現(xiàn)自動(dòng)提取短信驗(yàn)證碼功能
- Android實(shí)現(xiàn)短信驗(yàn)證碼自動(dòng)填寫功能
- Android獲取短信驗(yàn)證碼的實(shí)現(xiàn)方法
- Android實(shí)現(xiàn)常見的驗(yàn)證碼輸入框?qū)嵗a
- Android自定義控件通用驗(yàn)證碼輸入框的實(shí)現(xiàn)
- Android實(shí)現(xiàn)隨機(jī)生成驗(yàn)證碼
相關(guān)文章
解析Android中如何做到Service被關(guān)閉后又自動(dòng)啟動(dòng)的實(shí)現(xiàn)方法
本篇文章是對在Android中如何做到Service被關(guān)閉后又自動(dòng)啟動(dòng)的方法進(jìn)行了詳細(xì)的分析和介紹。需要的朋友參考下2013-05-05基于Android studio3.6的JNI教程之opencv實(shí)例詳解
這篇文章主要介紹了基于Android studio3.6的JNI教程之opencv實(shí)例詳解,本文通過實(shí)例代碼截圖的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03Android編程實(shí)現(xiàn)帶漸變效果的圓角矩形示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)帶漸變效果的圓角矩形,涉及Android界面布局及屬性設(shè)置相關(guān)操作技巧,需要的朋友可以參考下2017-08-08Android中自定義Window Title樣式實(shí)例
這篇文章主要介紹了Android中自定義Window Title樣式實(shí)例,本文給出效果預(yù)覽和實(shí)現(xiàn)方法,需要的朋友可以參考下2015-01-01android 傳感器(OnSensorChanged)使用介紹
當(dāng)傳感器的值發(fā)生變化時(shí),例如磁阻傳感器方向改變時(shí)會(huì)調(diào)用OnSensorChanged(). 當(dāng)傳感器的精度發(fā)生變化時(shí)會(huì)調(diào)用OnAccuracyChanged()方法2014-11-11edittext + listview 實(shí)現(xiàn)搜索listview中的內(nèi)容方法(推薦)
下面小編就為大家?guī)硪黄猠dittext + listview 實(shí)現(xiàn)搜索listview中的內(nèi)容方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03利用Android 防止系統(tǒng)字體變化、顯示大小變化影響
這篇文章主要介紹了利用Android 防止系統(tǒng)字體變化、顯示大小變化影響方法的相關(guān)資料,需要的朋友可以參考下面文章的具體內(nèi)容,希望對你有所幫助2021-10-10Android動(dòng)畫學(xué)習(xí)筆記之補(bǔ)間動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android動(dòng)畫學(xué)習(xí)筆記之補(bǔ)間動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12Android ReboundScrollView仿IOS拖拽回彈效果
這篇文章主要為大家詳細(xì)介紹了Android ReboundScrollView仿IOS拖拽回彈效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11