Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法
現(xiàn)如今,驗(yàn)證碼在Android的客戶端還是非常普遍的.通過手機(jī)賬號和驗(yàn)證碼直接去注冊應(yīng)用賬戶的信息.很多應(yīng)用都以這種方式來完成注冊.簡單的介紹一下吧.
Android獲取短信驗(yàn)證碼還是比較簡單的,通過Mob官網(wǎng)提供的ShareSDK,調(diào)用其中內(nèi)部的方法,就可以獲取到短信的驗(yàn)證碼了.提供一下Mob的官網(wǎng)地址.http://www.mob.com/#/在官網(wǎng)上注冊相關(guān)的信息之后,下載相關(guān)的jar包和.so文件就可以實(shí)現(xiàn)獲取短信驗(yàn)證碼了(2.0之前的版本都需要下載jar包和 .so文件,而現(xiàn)在的2.2版本已經(jīng)不需要下載.so文件了,通過加載SMSSDK.jar,MobCommons.jar,MobTools.jar包就可以直接使用).如何注冊我就不解釋了.
最后注冊完的樣式就是這樣的..我們來看看具體實(shí)現(xiàn)..
1.如何獲取短信驗(yàn)證碼.
i.首先需要初始化SDK,第三方這些東西首先必須要有的操作就是初始化SDK.一般都在OnCreate()函數(shù)中來完成.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); SMSSDK.initSDK(this, AppKey, APPSECRET); EventHandler eh = new EventHandler() { @Override public void afterEvent(int event, int result, Object data) { Message msg = new Message(); msg.arg1 = event; msg.arg2 = result; msg.obj = data; handler.sendMessage(msg); } }; SMSSDK.registerEventHandler(eh); }
這個(gè)是必須要進(jìn)行的操作,否則后續(xù)的東西都將無法完成.initSDK(Context context,String AppKey,String AppSECRET),初始化需要傳遞Context對象,以及我們申請的Key和SECRET.并且這里定義了一個(gè)EventHandler,用來進(jìn)行驗(yàn)證的時(shí)候?qū)⒁恍┫⑻峁┙o主線程的Handler,讓主線程來做一些相關(guān)的操作來通知用戶驗(yàn)證的情況到底如何.
ii.調(diào)用SMSSDK.getVerificationCode(String,String)方法
初始化SDK之后,我們就可以通過使用getVerificationCode()方法來獲取我們的驗(yàn)證碼了.
/** * @param string 電話號碼的區(qū)號 比如說86 * @param string 具體的電話號碼 */ SMSSDK.getVerificationCode("86", PhoneEd.getText().toString());
我們在調(diào)用方法的時(shí)候,需要傳遞我們手機(jī)號碼的區(qū)號和具體的手機(jī)號碼.由于中國國內(nèi)是86開頭.因此傳遞的區(qū)號就是86,在加上自己的電話號碼就可以通過網(wǎng)絡(luò)調(diào)用方法來獲取相關(guān)的驗(yàn)證碼了.
iii.驗(yàn)證我們輸入的驗(yàn)證碼和發(fā)送過來的驗(yàn)證碼是一致的.
當(dāng)驗(yàn)證碼發(fā)送過來的時(shí)候,客戶端一般就需要進(jìn)行輸入,但是這里需要一個(gè)驗(yàn)證的過程,判斷當(dāng)前用戶輸入的驗(yàn)證碼和發(fā)送過來的驗(yàn)證碼是否一致.
SMSSDK.submitVerificationCode("86", phone, CodeEd.getText().toString());
驗(yàn)證的方式通過調(diào)用submitVerificationCode()方法來完成.需要傳遞區(qū)號,電話號碼,以及我們輸入的驗(yàn)證碼的數(shù)值.驗(yàn)證的過程由ShareSDK幫我們完成.因此就不需要執(zhí)行太多復(fù)雜的操作.當(dāng)我們傳遞的數(shù)值和發(fā)送過來的數(shù)值是一樣的,那么就會(huì)驗(yàn)證成功,否則就會(huì)驗(yàn)證失敗.
這樣在我們的客戶端軟件上就可以通過這種驗(yàn)證方式來完成注冊功能.當(dāng)驗(yàn)證成功后,就可以進(jìn)入新的界面,如果驗(yàn)證失敗,那么就需要確認(rèn)輸入的驗(yàn)證碼.這樣就能夠完成應(yīng)用程序的驗(yàn)證碼驗(yàn)證.
一般情況下,我們只需要通過查看短信,然后提交相關(guān)的驗(yàn)證碼就可以了,但是還有一些其他的應(yīng)用更加的人性化,當(dāng)驗(yàn)證碼信息發(fā)送到手機(jī)內(nèi)部的時(shí)候直接就能夠獲取到相關(guān)的驗(yàn)證碼,然后直接添加在需要驗(yàn)證的地方,這樣非常的方便,并且還能防止用戶輸入錯(cuò)誤.那么這就涉及到讀取短信的相關(guān)內(nèi)容了.
iv.添加相關(guān)的權(quán)限
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
那么如何獲取短信的相關(guān)內(nèi)容呢?
2.如何獲取剛收到的短信的相關(guān)內(nèi)容.
一般而言,短信的驗(yàn)證是以新短信的方式直接發(fā)送給用戶的,那么應(yīng)用程序如果想到讀取剛收到的短息內(nèi)容,就需要有相關(guān)的監(jiān)聽事件.我通過使用ContentObserver來實(shí)現(xiàn)的.通過使用這個(gè)類可以捕捉特定的uri使數(shù)據(jù)庫改變,然后進(jìn)而作一些相關(guān)的處理.
那么我們就可以這樣去實(shí)現(xiàn),通過繼承ContentObserver類,重寫內(nèi)部的onChange方法,設(shè)置特定的Uri,使得我們的類能夠監(jiān)聽短信數(shù)據(jù)發(fā)生了變化這樣我們的應(yīng)用程序就知道什么時(shí)候短信到來了.那么短信到來之后,我們通過對短信內(nèi)容的獲取,然后讀取內(nèi)容中的驗(yàn)證碼信息就可以了.
private class SmsObserver extends ContentObserver { public SmsObserver(Handler handler) { super(handler); // TODO Auto-generated constructor stub } /** *Uri.parse("content://sms/inbox")表示對收到的短信的一個(gè)監(jiān)聽的uri. */ @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); Cursor cursor = getContentResolver().query( Uri.parse("content://sms/inbox"), null, null, null, null); //這里不要使用while循環(huán).我們只需要獲取當(dāng)前發(fā)送過來的短信數(shù)據(jù)就可以了. cursor.moveToNext(); sb.append("body=" + cursor.getString(cursor.getColumnIndex("body"))); //獲取短信內(nèi)容的實(shí)體數(shù)據(jù). Pattern pattern = Pattern.compile("[^0-9]"); //正則表達(dá)式. Matcher matcher = pattern.matcher(sb.toString()); CodeText = matcher.replaceAll(""); CodeEd.setText(CodeText); //將輸入驗(yàn)證碼的控件內(nèi)容進(jìn)行改變. cursor.close(); //關(guān)閉游標(biāo)指針. super.onChange(selfChange); } }
實(shí)現(xiàn)類的方式如上,通過重寫OnChange方法來進(jìn)行后續(xù)的操作,這里的cursor可以對當(dāng)前的短信數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行查找,這里的cursor指針不要使用while循環(huán),因?yàn)轵?yàn)證碼這條短信是隨發(fā)即用的,我們也只需要獲取當(dāng)前發(fā)送過來的驗(yàn)證碼短信中的相關(guān)內(nèi)容,如果cursor使用了while循環(huán),那么將會(huì)讀取短信中的所有內(nèi)容.這并不是我們想要的.
當(dāng)我們獲取到了短信的具體內(nèi)容之后,我們可以通過使用正則表達(dá)式,去匹配短信內(nèi)容的數(shù)字,然后就能夠獲取到驗(yàn)證碼數(shù)據(jù)了.大體的思路就是這樣一個(gè)情況.同時(shí)我們需要添加相關(guān)用戶權(quán)限.
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS" />
完成了上面的步驟之后,我們需要獲取ContentResolver實(shí)例,然后注冊ContentObserver。
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, new SmsObserver(new Handler()));
注冊我們需要傳遞相關(guān)的uri,第二個(gè)參數(shù)決定匹配uri的方式,如果設(shè)置為true的話,那么表示不精確匹配,那么也就表示,如果是一類的uri,那么都會(huì)被匹配到,如果設(shè)置為false,那么也就只能匹配到我們傳遞進(jìn)去的uri,也就是所謂的精確匹配.最后一個(gè)對象需要傳遞一個(gè)子類的實(shí)例,并且需要傳遞Handler對象.這樣我們也就可以在這個(gè)方法里去更新ui了.
當(dāng)我們不需要使用ContentObserver的時(shí)候,我們只需要注銷注冊就可以了.
相對而言,驗(yàn)證碼信息一般都是內(nèi)容比較少的,如果內(nèi)容比較復(fù)雜,然后還有其他額外的數(shù)字信息,那么我們在使用正則表達(dá)式的時(shí)候同時(shí)需要進(jìn)行相關(guān)的優(yōu)化.
最后上一個(gè)源代碼:
package com.example.sms; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.json.JSONObject; import cn.smssdk.EventHandler; import cn.smssdk.SMSSDK; import cn.smssdk.utils.SMSLog; import android.app.Activity; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private Button getCode; private Button Identity; private EditText PhoneEd; private EditText CodeEd; private String AppKey = "110ee66f30b40"; private String APPSECRET = "85ec67aed1b89e3ec73f37b8b89f5142"; public String phone; private String CodeText; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); int event = msg.arg1; int result = msg.arg2; Object data = msg.obj; if (result == SMSSDK.RESULT_COMPLETE) { if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) { Toast.makeText(getApplicationContext(), "提交驗(yàn)證碼成功", Toast.LENGTH_SHORT).show(); } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) { // 已經(jīng)驗(yàn)證 Toast.makeText(getApplicationContext(), "驗(yàn)證碼已經(jīng)發(fā)送", Toast.LENGTH_SHORT).show(); } } else { int status = 0; try { ((Throwable) data).printStackTrace(); Throwable throwable = (Throwable) data; JSONObject object = new JSONObject(throwable.getMessage()); String des = object.optString("detail"); status = object.optInt("status"); if (!TextUtils.isEmpty(des)) { Toast.makeText(MainActivity.this, des, Toast.LENGTH_SHORT).show(); return; } } catch (Exception e) { SMSLog.getInstance().w(e); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); SMSSDK.initSDK(this, AppKey, APPSECRET); EventHandler eh = new EventHandler() { @Override public void afterEvent(int event, int result, Object data) { Message msg = new Message(); msg.arg1 = event; msg.arg2 = result; msg.obj = data; handler.sendMessage(msg); } }; SMSSDK.registerEventHandler(eh); } private void init() { getCode = (Button) findViewById(R.id.getCode); Identity = (Button) findViewById(R.id.Indentity); PhoneEd = (EditText) findViewById(R.id.PhoneEd); CodeEd = (EditText) findViewById(R.id.Code); getCode.setOnClickListener(this); Identity.setOnClickListener(this); } private class SmsObserver extends ContentObserver { public SmsObserver(Handler handler) { super(handler); // TODO Auto-generated constructor stub } @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); Cursor cursor = getContentResolver().query( Uri.parse("content://sms/inbox"), null, null, null, null); cursor.moveToNext(); sb.append("body=" + cursor.getString(cursor.getColumnIndex("body"))); System.out.println(sb.toString()); Pattern pattern = Pattern.compile("[^0-9]"); Matcher matcher = pattern.matcher(sb.toString()); CodeText = matcher.replaceAll(""); CodeEd.setText(CodeText); cursor.close(); super.onChange(selfChange); } } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.getCode: // 獲取驗(yàn)證碼的過程. if (!TextUtils.isEmpty(PhoneEd.getText().toString())) { getContentResolver().registerContentObserver( Uri.parse("content://sms"), true, new SmsObserver(new Handler())); SMSSDK.getVerificationCode("86", PhoneEd.getText().toString()); phone = PhoneEd.getText().toString(); } else { Toast.makeText(MainActivity.this, "電話號碼不能為空", Toast.LENGTH_LONG) .show(); } break; case R.id.Indentity: SMSSDK.submitVerificationCode("86", phone, CodeEd.getText() .toString()); break; } } protected void onDestroy() { SMSSDK.unregisterAllEventHandler(); getContentResolver().unregisterContentObserver(new SmsObserver(handler)); }; }
這樣就能夠完成一個(gè)簡單的通過使用短信驗(yàn)證碼的方式來實(shí)現(xiàn)驗(yàn)證,在一般的項(xiàng)目中,我們可以根據(jù)具體的需求進(jìn)行相關(guān)的改良,總之萬變不離其宗思路基本都是一樣的.當(dāng)然在判斷是否有短信到來也可以使用BroadCaseReceiver來實(shí)現(xiàn),不過我看了網(wǎng)上的一些相關(guān)的資源,自己也試了一下,沒有實(shí)現(xiàn)出來.感覺沒有ContentObserver這么簡單方便.
以上就是Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法,希望對大家學(xué)習(xí)Android軟件編程有所幫助。
相關(guān)文章
基于barcodescanner實(shí)現(xiàn)Android二維碼掃描功能
這篇文章主要為大家詳細(xì)介紹了基于barcodescanner實(shí)現(xiàn)Android二維碼掃描功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Android使用多線程進(jìn)行網(wǎng)絡(luò)聊天室通信
這篇文章主要為大家詳細(xì)介紹了Android使用多線程進(jìn)行網(wǎng)絡(luò)聊天室通信,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android隨手筆記44之JSON數(shù)據(jù)解析
本文將主要介紹在Android開發(fā)中,如何在服務(wù)器端創(chuàng)建JSON數(shù)據(jù),以及如何在Android客戶端對JSON數(shù)據(jù)進(jìn)行解析,對android json解析 相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2015-12-12android開發(fā)教程之實(shí)現(xiàn)listview下拉刷新和上拉刷新效果
這篇文章主要介紹了android實(shí)現(xiàn)listview下拉刷新和上拉刷新效果,Android的ListView上拉下拉刷新,原理都一樣,在Touch事件中操作header/footer的paddingTop屬性,需要的朋友可以參考下2014-02-02AndroidStudio中重載方法@Override的使用詳解
這篇文章主要介紹了AndroidStudio中重載方法@Override的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Android中實(shí)現(xiàn)TCP和UDP傳輸實(shí)例
這篇文章主要介紹了Android中實(shí)現(xiàn)TCP和UDP傳輸實(shí)例,本文給出了TCP服務(wù)器端代碼、TCP客戶端代碼、UDP服務(wù)器端代碼、UDP客戶端代碼等代碼實(shí)例,需要的朋友可以參考下2015-03-03Android編程中context及全局變量實(shí)例詳解
這篇文章主要介紹了Android編程中context及全局變量的用法,結(jié)合實(shí)例形式較為詳細(xì)的分析講述了context及全局變量的使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2015-12-12解決video標(biāo)簽在安卓webview下無法自動(dòng)播放問題
這篇文章主要介紹了video標(biāo)簽在安卓webview下無法自動(dòng)播放問題的解決方法 ,需要的朋友可以參考下2014-03-03ViewPager+Fragment實(shí)現(xiàn)側(cè)滑導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了ViewPager+Fragment實(shí)現(xiàn)側(cè)滑導(dǎo)航欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05