SMS 簡訊自動攔截/解析
現今的服務中,許多登入或是認證的行為,都會用到所謂的 OTP (one-time passcode) 也就是在登入過程中,透過手機驗證的方式來確認用戶身份
有些大一點的公司會使用自家的驗證器(Authenticator),像是 Facebook / Google / Steam ...etc 但是大部分的服務,方便一點的就會使用簡訊服務(SMS)
與其讓用戶收到訊息後還要去查看簡訊,然後把簡訊中的驗證碼記住或是複製,再回到你的 App 做輸入。 一來流程麻煩,二來用戶可能會記錯/貼錯。
所以更方便的方式就是自動擷取簡訊,然後把驗證碼自動幫用戶帶入對應的欄位。
具體作法
- 註冊 SMS Receiver
- 取得 Runtime Permission
- 解析簡訊內容
宣告 Permission
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS" />
註冊 Receiver
<receiver android:name=".SMSListener"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
在 Activity 需要時取得 Runtime Permission
如果用戶不同意的話,Receiver 就會收不到訊息
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... if (checkSelfPermission(Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) { requestPermissions( arrayOf( Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS ), SMS_PERMISSION_REQUEST_CODE ) } ... }
最後在收到簡訊時,解析簡訊的內容
SMSListener.kt
class SMSListener : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val bundle = intent.extras if (bundle != null) { //---retrieve the SMS message received--- try { val pdus = bundle.get("pdus") as Array<Any> for (i in 0..pdus.size) { var msg = SmsMessage.createFromPdu(pdus[i] as ByteArray) /* handle message content via msg.displayMessageBody */ } } catch (e: Exception) {} } } }
理論上 SmsMessage.createFromPdu(pdus[i] as ByteArray) 應該還要帶入第二個參數
format
GSM/UMTS/LTE 使用SmsConstants.FORMAT_3GPP
CDMA/LTE 使用SmsConstants.FORMAT_3GPP2
最後就可以從 msg.displayMessageBody
取得完整的見訊文字內容
然後再看看透過 LiveData 或是其他機制通知 View 元件然後幫用戶自動帶入