Skip to content

Instantly share code, notes, and snippets.

@masoudkarimi
Last active July 12, 2023 09:14
Show Gist options
  • Save masoudkarimi/dca2231e7dff5b0f1057d11a69f9fe39 to your computer and use it in GitHub Desktop.
Save masoudkarimi/dca2231e7dff5b0f1057d11a69f9fe39 to your computer and use it in GitHub Desktop.
SMS retriever using play service API and Kotlin delegates
An implementation of SMS Retriever API using Kotlin Delegates to simplify the usage.
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.0'
import androidx.fragment.app.Fragment
import com.your.packagename.smsRetrieverDelegate
class TargetFragment: Fragment() {
private val smsRetriever by smsRetrieverDelegate(::onSMSRetrieved)
private fun startRetriever() {
smsRetriever.register()
}
override fun onDestroy() {
smsRetriever.unregister()
super.onDestroy()
}
private fun onSMSRetrieved(message: String?) {
// Parse SMS message and extract the code or anything else you aimed to
}
}
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import androidx.fragment.app.Fragment
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 kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
fun smsRetrieverDelegate(
callback: (message: String?) -> Unit
): ReadOnlyProperty<Fragment, SMSReceiver> {
return SMSRetrieverDelegate(callback)
}
internal class SMSRetrieverDelegate(private val callback: (message: String?) -> Unit): ReadOnlyProperty<Fragment, SMSReceiver> {
override fun getValue(thisRef: Fragment, property: KProperty<*>): SMSReceiver {
return SMSReceiver(thisRef, callback)
}
}
class SMSReceiver internal constructor(
private val fragment: Fragment,
private val callback: (message: String?) -> Unit
) {
private val smsBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
intent ?: return
if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
val extras = intent.extras ?: return
val status = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
extras.getParcelable(SmsRetriever.EXTRA_STATUS, Status::class.java)
} else {
extras[SmsRetriever.EXTRA_STATUS] as Status?
}
when(status?.statusCode) {
CommonStatusCodes.SUCCESS -> {
val message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE)
callback(message)
}
CommonStatusCodes.TIMEOUT -> {
// Waiting for SMS timed out (5 minutes)
// Handle the error
}
else -> {
// handle error
}
}
}
}
}
fun register() {
val intentFilter = IntentFilter().apply {
addAction(SmsRetriever.SMS_RETRIEVED_ACTION)
priority = IntentFilter.SYSTEM_HIGH_PRIORITY
}
runCatching {
fragment.requireActivity().registerReceiver(smsBroadcastReceiver, intentFilter, SmsRetriever.SEND_PERMISSION, null)
}
}
fun unregister() {
runCatching {
fragment.requireActivity().unregisterReceiver(smsBroadcastReceiver)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment