코딩하는 일용직 노동자

SMS Retriever 본문

안드로이드

SMS Retriever

bacass 2020. 5. 3. 16:35

2019년 1월9일부터 안드로이드 SMS 권한정책이 변경되었습니다.
기존에는 RECEIVE_SMS 권한을 이용해서 SMS 내용을 읽고 인증번호를 자동입력을 해주었지만 이제는 예외신청을 하지 않으면 구글 플레이스토어에서 삭제 대상이 됩니다.
https://developers.google.com/identity/sms-retriever/verify

이제는 SMS Retriever를 이용해서 권한 허용없이 문자를 읽어올 수 있습니다.
이 기능에는 약간의 제한사항이 있습니다.
Android 단말에 Google Play Service version 이 10.2 이상 설치되어 있어야합니다.

그리고 SMS에도 몇가지 규칙이 있습니다.
1. 문자내용이 140byte를 초과하면 안됩니다.
2. SMS 맨앞에 <#>가 반드시 포함되어야 합니다.
3. SMS 맨마지막에 앱을 식별하는 11글자 해시문자열을 포함해야 합니다.

ex) <#> 인증번호 [1234] 6jXBVVzakXo

# app/gradle 에서 설정.

implementation 'com.google.android.gms:play-services-auth:18.0.0'

 

# 매니페스트 파일에서 설정

<uses-permission android:name="android.permission.RECEIVE_SMS"/>

<receiver android:name=".ui.authmember.AuthSmsBroadcastReceiver" android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

 

# 브로드캐스트 리시버 클래스

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status
import timber.log.Timber


class AuthSmsBroadcastReceiver : BroadcastReceiver() {

    private var otpReceiver: OTPReceiveListener? = null

    fun initOTPListener(receiver: OTPReceiveListener) {
        this.otpReceiver = receiver
    }

    override fun onReceive(context: Context, intent: Intent) {
        Timber.d("Real onReceive SMS")
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
            val extras = intent.extras
            val status = extras!!.get(SmsRetriever.EXTRA_STATUS) as Status

            when (status.statusCode) {
                CommonStatusCodes.SUCCESS -> {
					// 여기서 파싱해준다.
                    // Get SMS message contents
                    var otp: String = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String

                    // Extract one-time code from the message and complete verification
                    // by sending the code back to your server for SMS authenticity.
                    // But here we are just passing it to MainActivity
                    if (otpReceiver != null) {
//                        otp = otp.replace("<#> Your ExampleApp code is: ", "").split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
                        var startIndex = otp.indexOf("입니다.")
                        otp = otp.substring(startIndex - 6, startIndex)
                        otpReceiver!!.onOTPReceived(otp)
                    }
                }

                //CommonStatusCodes.TIMEOUT ->
                    // Waiting for SMS timed out (5 minutes)
                    // Handle the error ...
                    // otpReceiver!!.onOTPTimeOut()
            }
        }
    }

    interface OTPReceiveListener {

        fun onOTPReceived(otp: String)

        fun onOTPTimeOut()
    }
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...

    // 객체를 정의함.
    val smsBroadcast = AuthSmsBroadcastReceiver()

    // onCreated() 에서 셋팅함.
    smsBroadcast.initOTPListener(this)
    val intentFilter = IntentFilter()
    intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION)

    context?.registerReceiver(smsBroadcast, intentFilter)
}


override fun onDestroy() {
    super.onDestroy()
    // onDestroy() 에서 해제함.

    context?.unregisterReceiver(smsBroadcast)
}