編輯:關於Android編程
現在的應用在注冊登錄或者修改密碼中都用到了短信驗證碼,那在android中是如何實現獲取短信驗證碼並自動填寫的呢?
首先,需要要在manifest中注冊接收和讀取短信的權限:
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.READ_SMS"/>
實現一個廣播SMSBroadcastReceiver來監聽短信:
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; /** * 短信監聽 * @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(); //短信內容 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); //過濾不需要讀取的短信的發送號碼 if ("+8613450214963".equals(sender)) { mMessageListener.onReceived(content); abortBroadcast(); } } } } //回調接口 public interface MessageListener { public void onReceived(String message); } public void setOnReceivedMessageListener(MessageListener messageListener) { this.mMessageListener = messageListener; } }
在需要填寫驗證碼的Activity中,生產SMSBroadcastReceiver的實例,實現onReceived的回調接口。為了節約系統資源,我們使用動態注冊注銷廣播的方法。
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(); //實例化過濾器並設置要過濾的廣播 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(); //注銷短信監聽廣播 this.unregisterReceiver(mSMSBroadcastReceiver); } }
上面提供了一種獲取短信息驗證碼並自動填寫的實現方式,就是直接通過短信廣播監聽短信。但是,這種方式有它的缺陷:當你的手機安裝了其他一些短信應用(例如QQ通訊錄)或者手機本身限制了權限的情況下,這種方式有可能會不起作用,無法做到自動填寫,而且就算把優先級設高,也不能保證不會被別的應用“搶先”。
後來查資料知道,可以通過監聽短信數據庫的方式實現。監聽短信數據庫主要是通過ContentObserver這個類來完成。ContentObserver主要是通過Uri來監測特定的Databases的表,當ContentObserver所觀察的Uri發生變化時,便會觸發它。思路就是監聽短信數據庫中特定號碼的未讀短信。我們可以通過百度找到許多demo,但是我發現很多demo中存在著Bug,在接收到短信後引起崩潰。還有一種情況,當真機連接著電腦,電腦裝有類似豌豆莢之類的軟件的時候,手機收到短信後,豌豆莢之類的可能會把該短信的狀態改成“已讀”,這樣也會導致崩潰。
通過調試,終於把Bug修復了,布局和短信權限就不再贅述。在MainActivity中增加一個內部類SmsContent。
/** * 監聽短信數據庫 */ 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排序的話,修改手機時間後,讀取的短信就不准了 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的時候,不能主動調用close()方法, 否則在Android 4.0+的系統上, 會發生崩潰 if(Build.VERSION.SDK_INT < 14) { cursor.close(); } } }
記得在onCreate中注冊短信變化監聽
SmsContent content = new SmsContent(new Handler()); //注冊短信變化監聽 this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, content);
記得注銷監聽
this.getContentResolver().unregisterContentObserver(content);
其中,下發的驗證碼短信一般都是一個字符串,其中包含6位數字,我們需要把這6位數字提取出來,我們可以用正則表達式寫一個靜態方法。
/** * 從字符串中截取連續6位數字 * 用於從短信中獲取動態密碼 * @param str 短信內容 * @return 截取得到的6位動態密碼 */ 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獲取短信驗證碼並自動填寫的功能就實現了。
補充:對於上面短信數據庫監聽中有個直接關閉游標的操作(現在已經更正):cursor.close();
但是,如果這樣直接關閉的話,會引起崩潰。例如,當獲取了短信密碼,自動填寫上了之後,按home鍵返回桌面,然後再進入應用,會引起應用崩潰。報的錯是:
android.database.StaleDataException: Attempted to access a cursor after it has been closed
後來通過查資料得知,是用managedQuery的時候, 不能主動調用close()方法, 否則在Android 4.0+的系統上, 會發生崩潰。對版本進行一個判斷再執行關閉游標的操作。
//在用managedQuery的時候,不能主動調用close()方法, 否則在Android 4.0+的系統上, 會發生崩潰 if(Build.VERSION.SDK_INT < 14) { cursor.close(); }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
很多時候,我們在使用應用時,會出現輸入法軟鍵盤彈出的問題,通常情況下,我們默認會使用戶點擊返回鍵或者下一步對軟鍵盤進行隱藏。為了更好的體驗,我們可以實現當用戶使用完畢軟鍵
Android手機同時使用Wi-Fi和數據流量大家都知道,當手機成功連接到Wi-Fi熱點以後,手機所產生的上網流量都是通過Wi-Fi來傳輸的,而手機的移動流量會被禁用。但
手機QQ透明頭像怎麼制作?下面就跟著小編一起來看看吧!QQ透明頭像制作方法方法一:在電腦版上操作即可同步到手機qq首先下載透明頭像的圖片,接著打開電腦版QQ
一、前言關於Android中的分包技術,已經不是什麼新的技術了,網上也有很多解析了,但是他們都是給了理論上的知道和原理解析,並沒有詳細的案例說明,所以這裡我們就來詳細講解