Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Wook No.1

SMS Retriever API로 인증 문자 확인 본문

Android

SMS Retriever API로 인증 문자 확인

Wook No.1 2021. 6. 21. 18:49

기존에 android.permission.RECEIVE_SMS 를 사용하게 되면 그 권한을 무슨 목적으로 사용 하는지를 명확하게 신청해 달라는 경고로 리젝 사유가 됨.

 

그래서 제공된 SMS Retriever API를 사용해서 인증문자 확인 할수 있음.

 

1. 인증문자 140 bytes 이하만 가능

2. 인증문자 시작은 <#> 으로 시작해야함.

3. 마지막 문자는 11자리의 hash를 포함해야함.

 

https://developers.google.com/identity/sms-retriever/overview

 

SMS Retriever API를 사용한 자동 SMS 확인  |  SMS Verification APIs

SMS Retriever API를 사용하면 사용자가 인증 코드를 수동으로 입력 할 필요없이 추가 앱 권한 없이도 Android 앱에서 SMS 기반 사용자 인증을 자동으로 수행 할 수 있습니다. 앱에서 자동 SMS 확인을 구

developers.google.com

 

Hash 확인 코드

fun appSignatures() {
    val appCodes = mutableListOf<String>()
    try {
        val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES).signingInfo.apkContentsSigners
        } else {
            @Suppress("DEPRECATION")
            packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures
        }
        for (signature in signatures) {
            val hash = hash(packageName, signature.toCharsString())
            hash?.let {
                appCodes.add(String.format("%s", it))
            }
        }
    } catch (e: PackageManager.NameNotFoundException) {
        e.printStackTrace()
    }
}

fun hash(packageName: String, signature: String): String? {
    val appInfo = "$packageName $signature"
    try {
        val messageDigest = MessageDigest.getInstance("SHA-256")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))
        }
        var hashSignature = messageDigest.digest()
        hashSignature = Arrays.copyOfRange(hashSignature, 0, 9)
        var base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP)
        base64Hash = base64Hash.substring(0, 11)
        return base64Hash
    } catch (e: NoSuchAlgorithmException) {
        e.printStackTrace()
    }
    return null
}

 

 

Gradle 설정

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

 

BroadcastReceiver 코드

class SMSBroadcastReceiver : BroadcastReceiver() {
    private var prevMessage : String? = null
    private var otpReceiveListener : OtpReceiveListener? = null

    fun setOnOtpListener(listener: OtpReceiveListener) {
        otpReceiveListener = listener
    }

    override fun onReceive(context: Context, intent: Intent) {
        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 -> {
                    var message: String = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                    if(message == prevMessage) {
                        return
                    }
                    prevMessage = message
                    var otp = getOnlyDigit(message)
                    otpReceiveListener?.onOtpReceived(otp)
                }

                CommonStatusCodes.TIMEOUT -> {
                    otpReceiveListener?.onOtpTimeOut()
                }
            }
        }
    }

    // 해당 번호에 길이 맞게 정규식 적용
    private fun getOnlyDigit(str: String?): String? {
        // 인증번호가 5자이거나 6자일 경우
        var digitStr = ""
        Pattern.compile("\\d{6}").matcher(str).run {
            if(find()) {
                digitStr = group(0)
            }
        }

        if(digitStr.isNullOrBlank()) {
            Pattern.compile("\\d{5}").matcher(str).run {
                if(find()) {
                    digitStr = group(0)
                }
            }
        }

        return digitStr
    }

    interface OtpReceiveListener {
        fun onOtpReceived(otp: String?)
        fun onOtpTimeOut()
    }
}

 

 

Comments