Hyeyeon blog

[Android] Kotlin - SMS Retriever API 본문

개발/Android

[Android] Kotlin - SMS Retriever API

Hyeyeon.P 2019. 2. 15. 13:01
반응형

# Google의 SMS 및 Call 권한 정책 변경으로 앱의 주요 기능이 아닌 경우 관련 퍼미션을 요청할 수 없게 되었으며,

 대신 퍼미션 요청 없이 SMS Retriever API를 이용하여 문자 메세지의 내용을 얻을 수 있다.


0. 구글 플레이 서비스 버전 확인

- 전제 조건: 구글 플레이 서비스 1.02 버전 이상

- 8자리의 숫자가 반환되는데, 15000000의 경우 15.0을 의미

val gpsVersion = packageManager.getPackageInfo(GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, 0).versionCode

1. dependency 추가

implementation 'com.google.android.gms:play-services-auth:16.0.1' implementation 'com.google.android.gms:play-services-auth-api-phone:16.0.0'


2. SMS Retriever 실행

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

private fun startSMSRetriever(){
    val client = SmsRetriever.getClient(this)
    val task = client.startSmsRetriever()

    task.addOnSuccessListener {
        // Start retriever successfully
    }

    task.addOnFailureListener {
        // Failed to start retriever
    }
}

3. 문자 메세지 내용 가져오기

3-1. BroadcastReceiver 생성

class SMSBroadcastReceiver : BroadcastReceiver() {
    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 -> {
                    // Get SMS message
                    val message = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                    val format = message.split(":")[1]
                    val number = format.split("\n")[0] // 인증번호
                }
                CommonStatusCodes.TIMEOUT -> {
                    // 5 mitues
                    return
                }
            }
        }
    }
}

3-2. BroadcastReceiver 등록

// AndroidManifest.xml
<application> 
    ...
    <receiver android:name=".SMSBroadcastReceiver" android:exported="true">
        <intent-filter>
            <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"></action>
        </intent-filter>
    </receiver>
</application>

3-3. 동적으로 등록할 경우

(1) 사용할 Activity에 리시버 등록

val intentFilter = IntentFilter()
intentFilter.addAction("com.google.android.gms.auth.api.phone.SMS_RETRIEVED")
this.registerReceiver(broadCastReceiver, intentFilter)

(2) 리시버 해지

private lateinit var smsBroadcaseReceiver: BroadcastReceiver
...
override fun onDestroy() {
    if (::smsBroadcaseReceiver.isInitialized) {
        this.unregisterReceiver(smsBroadcaseReceiver)
    }
    super.onDestroy()
}

4. 테스트

1-1. 해시 문자열 생성

fun getAppSignatures(): ArrayList<String>

{ val appCodes :ArrayList<String> = ArrayList() try { // Get all package signatures for the current package val packageName = packageName val packageManager = packageManager val signatures = packageManager.getPackageInfo( packageName, PackageManager.GET_SIGNATURES ).signatures // 앱의 공개키 인증서 // For each signature create a compatible hash for (signature in signatures) { val hash = hash(packageName, signature.toCharsString()) if (hash != null) { appCodes.add(String.format("%s", hash)) } } } catch (e: PackageManager.NameNotFoundException) { Log.e("Hash", "Unable to find package to obtain hash.", e) } return appCodes } private fun hash(packageName: String, signature: String): String? { val HASH_TYPE = "SHA-256" val NUM_HASHED_BYTES = 9 val NUM_BASE64_CHAR = 11 val appInfo = "$packageName $signature" try { val messageDigest = MessageDigest.getInstance(HASH_TYPE) messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8)) var hashSignature = messageDigest.digest() // truncated into NUM_HASHED_BYTES hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES) // encode into Base64 var base64Hash = android.util.Base64. encodeToString(hashSignature, android.util.Base64.NO_PADDING 또는 android.util.Base64.NO_WRAP) base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR) Log.d("HASH", String.format("pkg: %s -- hash: %s", packageName, base64Hash)) return base64Hash } catch (e: NoSuchAlgorithmException) { Log.e("Hash", "hash:NoSuchAlgorithm", e) } return null }

1-2. 서버 또는 ADV에서 수신한 문자 메세지 형식

<#> ExampleApp 코드 : 123ABC78 FA + 9qCX9VSu // getAppSignatures()[0]로 가져온 해시 문자열


[참고 및 출처]

[Google Developers - SMS Retriever API]

728x90
Comments