Verify OTP Without SMS Permission In Android Using Kotlin

Introduction

Google has updated the policy in Google Developer Blog about user privacy and security. As per the policy, we must remove SMS and Call Log permissions from manifest or else our app will be removed from the Google play store. But our app needs SMS permission for automatically authenticating app users. What is the solution?
Google offers an API named SMS Retriever API to allow our app to read SMS without SMS permission and we need to follow a set of rules while formatting the verification message. In this article, we will learn how to use SMS Retriever API in Kotlin to read SMS and rules need to be followed. If you are new to Kotlin, read my previous articles to read Kotlin from scratch.

Verification Message Format

We should follow the below rules while formatting verification message.
  1. A message should have a maximum of 140 bytes length.
  2. Should start with “<#>”.
  3. Followed by OTP - One Time Pass (code/word).
  4. 11 character length hash for the app (it is generated by our app).
Example
  1. <#> Your Example App code is: 123ABC78
  2. FA+9qCX9VSu

Coding Part

I have detailed the article as in the following steps.
  • Step 1: Creating a New Project with Empty Activity.
  • Step 2: Setting up the Google Auth Libraries.
  • Step 3: Implementation of SMS Retriever API using Kotlin.
Step 1 - Creating a new project with Kotlin
  1. Open Android Studio and select "Create new project".
  2. Name the project as your wish and tick the Kotlin Support checkbox.
  3. Then Select your Activity type (For example, Navigation Drawer Activity, Empty Activity, etc.).

    Verify OTP Without SMS Permission In Android Using Kotlin

  4. Then, click the “Finish” button to create a new project in Android Studio.
Step 2 - Setting up the Google Auth Libraries
In this part, we will see how to set up the library for the project.
  1. Then add the following lines in app level build.gradle file to apply Google services to your project.
    1. dependencies {
    2. implementation 'com.google.android.gms:play-services-base:11.6.0'
    3. implementation 'com.google.android.gms:play-services-auth-api-phone:11.6.0'
    4. }
  1. Then click “Sync Now” to setup your project.
  2. Now the project is ready and no need to add any permissions in Manifest.
Step 3 - Implementation of SMS Retriever API using Kotlin

You will receive the OTP in call back methods implemented in your Activity.

  1. override fun onOTPReceived(otp: String) {
  2. //showToast("OTP Received: " + otp)
  3. editText.setText(otp)
  4. if (smsReceiver != null) {
  5. LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
  6. }
  7. }
  8. override fun onOTPTimeOut() {
  9. showToast("OTP Time out")
  10. }

Full Code

You can find the full code implementation of the Activity here.
  1. class MainActivity : AppCompatActivity(), OTPReceiveListener {
  2. private var smsReceiver: MySMSBroadcastReceiver? = null
  3. override fun onCreate(savedInstanceState: Bundle?) {
  4. super.onCreate(savedInstanceState)
  5. setContentView(R.layout.activity_main)
  6. startSMSListener()
  7. }
  8. /**
  9. * Starts SmsRetriever, which waits for ONE matching SMS message until timeout
  10. * (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
  11. * action SmsRetriever#SMS_RETRIEVED_ACTION.
  12. */
  13. private fun startSMSListener() {
  14. try {
  15. smsReceiver = MySMSBroadcastReceiver()
  16. smsReceiver!!.initOTPListener(this)
  17. val intentFilter = IntentFilter()
  18. intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION)
  19. this.registerReceiver(smsReceiver, intentFilter)
  20. val client = SmsRetriever.getClient(this)
  21. val task = client.startSmsRetriever()
  22. task.addOnSuccessListener {
  23. // API successfully started
  24. }
  25. task.addOnFailureListener {
  26. // Fail to start API
  27. }
  28. } catch (e: Exception) {
  29. e.printStackTrace()
  30. }
  31. }
  32. fun onBtnResendClick(view: View){
  33. startSMSListener()
  34. }
  35. override fun onOTPReceived(otp: String) {
  36. //showToast("OTP Received: " + otp)
  37. editText.setText(otp)
  38. if (smsReceiver != null) {
  39. LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
  40. }
  41. }
  42. override fun onOTPTimeOut() {
  43. showToast("OTP Time out")
  44. }
  45. override fun onDestroy() {
  46. super.onDestroy()
  47. if (smsReceiver != null) {
  48. LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
  49. }
  50. }
  51. private fun showToast(msg: String) {
  52. Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
  53. }
  54. }
Reference
SMS Retriever API for Android
https://developers.google.com/identity/sms-retriever/overview
Google Announcement on Security Policy
https://android-developers.googleblog.com/2019/01/reminder-smscall-log-policy-changes.html
If you have any doubts or need any help, contact me.
Download Code
You can download the full source code of the article in GitHub. If you like this article, do star the repo on GitHub.