Developer Stories Easy Ways to Implement Automatic SMS Verification in Android

Easy Ways to Implement Automatic SMS Verification in Android

There are many ways to do the verification process in an Android application. As mobile developer, we know that one of the best way is using SMS verification. Since we all know most mobile phone users have a phone number for their phone.

But, input the code that we received from SMS is not user friendly. User has to view all the messages in the phone and see the code on it, then back again to the app to input the code. We, as mobile developer on mobile application deveopment, need “something” that can read those messages and get the code then fill in the field automatically.

Actually, there are many ways to automatically fill the OTP field by reading the message in our phone using READ_SMS permission. But, Google has strictly prohibited the usage of that permission for security purposes. You can read the full explanation here.

Since we can’t use the READ_SMS permission anymore, Google has given some other choices to implement automatic SMS verification using SMS Verification API which includes the automatic and one-tap SMS verification. Let’s find out how they work and implement it in our mobile application development!

Automatic SMS Verification

android - android developer - android developer indonesia - mobile application development - app developer indonesia
Automatic SMS Verification Flow

The automatic SMS verification is the best way to do the SMS verification. Because, users don’t have to do any action and just wait until the verification process is complete. Also, it doesn’t require any permission, but you have to make sure that you follow these criterias:

  1. Messages that are sent to the user’s device must be no longer than 140 bytes.
  2. Message must contains a one-time code that user’s will send back to the server.
  3. Message must contain an 11-character hash string.

Now, let’s implement automatic SMS verification in our app!

Prerequisites

This only works in Android devices with play service version 10.2 or latest.

Import Library

Import these libraries into your app’s gradle to start using SMS Retriever API.

implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.4.0'

Obtain Phone Number

There are several ways to obtain a user’s phone number. The best way that Google recommends is using a hint picker. Look at these codes below.

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
           .setPhoneNumberIdentifierSupported(true)
           .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId();  <-- will need to process phone number string
      }
  }
}

Start SMS Retriever

After you have got the user’s phone number, then you are ready to start the SMS Retriever to listen to SMS that contains a unique string to identify your app for up to 5 minutes.

// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
// action SmsRetriever#SMS_RETRIEVED_ACTION.
Task<Void> task = client.startSmsRetriever();

// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
  @Override
  public void onSuccess(Void aVoid) {
    // Successfully started retriever, expect broadcast intent
    // ...
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
    // Failed to start retriever, inspect Exception for more details
    // ...
  }
});

Send User’s Phone Number to Server

Then, you should send the user’s phone number to the server for triggering the verification process. The server will send an SMS containing the one-time code and a unique string to identify your app.

Receive Verification Message

When a client’s phone receives any message containing a unique string, SMS Retriever API will broadcast the message with SmsRetriever.SMS_RETRIEVED_ACTION intent. Then, you should use a broadcast receiver to receive the verification message.

/**
 * BroadcastReceiver to wait for SMS messages. This can be registered either
 * in the AndroidManifest or at runtime.  Should filter Intents on
 * SmsRetriever.SMS_RETRIEVED_ACTION.
 */
public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          // Get SMS message contents
          String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
          // Extract one-time code from the message and complete verification
          // by sending the code back to your server.
          break;
        case CommonStatusCodes.TIMEOUT:
          // Waiting for SMS timed out (5 minutes)
          // Handle the error ...
          break;
      }
    }
  }
}

Don’t forget to register your Broadcast Receiver to manifest.

<receiver android:name=".MySMSBroadcastReceiver" android:exported="true" android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

Send OTP Code Back to Your Server

After you got the message that contains one-time code, use some regex or other logic to extract your code from the message. Then, send that code back to the server.


One-tap SMS Verification

Up there, we have talked about how to do Automatic SMS Verification. It will help us as Android developer, for sure, on developing our mobile application. But then, there still another way from Google. Let’s try it as well!

The other way that Google provides for SMS verification is using One-tap Verification method. This method has a similar process with the previous one, but you don’t have to generate any unique code to verify your application. This method will show a bottom sheet to ask user permission to read the content of a single SMS. If the user gives their consent, your app then will have access to the message and you can get the one-time code on it.

android - android developer - android developer indonesia - mobile application development - app developer indonesia
One-tap Verification Process

Now, let’s implement One-tap verification on your mobile application!

Import Library

First thing that you need to do is import these libraries into your app’s gradle.

implementation 'com.google.android.gms:play-services-auth:17.0.0'                       implementation 'com.google.android.gms:play-services-auth-api-phone:17.4.0'

Obtain User’s Phone Number

Again, before we start the SMS verification process, we need to obtain the user’s phone number. You can use any method to do this, but Google recommends using a hint picker. See the code below to implement hint picker.

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
           .setPhoneNumberIdentifierSupported(true)
           .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId();  <-- will need to process phone number string
      }
  }
}

Listening for an Incoming Message

Same with the previous method, we should start listening for an incoming message before sending that phone number to the server. This listener will listen to any message for up to 5 minutes. In this method, you can specify the phone number that will send a message contains the OTP code. But, if you don’t want to set it, you can fill it with null value.

// Start listening for SMS User Consent broadcasts from senderPhoneNumber
// The Task<Void> will be successful if SmsRetriever was able to start
// SMS User Consent, and will error if there was an error starting.
val task = SmsRetriever.getClient(context).startSmsUserConsent(senderPhoneNumber /* or null */)

Another thing that you have to know about this method is you have to make sure your message completes these criterias:

  1. The message contains a 4–10 character alphanumeric string with at least one number.
  2. The message was sent by a phone number that’s not in the user’s contacts.
  3. If you specified the sender’s phone number, the message was sent by that number.

Implement this code in your Activity class to start listening for an incoming message.

private val SMS_CONSENT_REQUEST = 2  // Set to an unused request code
private val smsVerificationReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
            val extras = intent.extras
            val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status

            when (smsRetrieverStatus.statusCode) {
                CommonStatusCodes.SUCCESS -> {
                    // Get consent intent
                    val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
                    try {
                        // Start activity to show consent dialog to user, activity must be started in
                        // 5 minutes, otherwise you'll receive another TIMEOUT intent
                        startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
                    } catch (e: ActivityNotFoundException) {
                        // Handle the exception ...
                    }
                }
                CommonStatusCodes.TIMEOUT -> {
                    // Time out occurred, handle the error.
                }
            }
        }
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
    registerReceiver(smsVerificationReceiver, SmsRetriever.SEND_PERMISSION, intentFilter)
}

Starting an activity with EXTRA_CONSENT_INTENT means that a bottom sheet will appear to the user to give one-time permission to read the SMS.

android - android developer - android developer indonesia - mobile application development - app developer indonesia
Permission Appears

Get the Verification Code

In onActivityResult(), if you got the RESULT_OK, it means the user gives you permission to read the SMS and you can get the SMS content from intent.

public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        // ...
        SMS_CONSENT_REQUEST ->
            // Obtain the phone number from the result
            if (resultCode == Activity.RESULT_OK && data != null) {
                // Get SMS message content
                val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
                // Extract one-time code from the message and complete verification
                // `message` contains the entire text of the SMS message, so you will need
                // to parse the string.
                val oneTimeCode = parseOneTimeCode(message) // define this function

                // send one time code to the server
            } else {
                // Consent denied. User can type OTC manually.
            }
    }
}

Then, you can extract the code from SMS and send it back to the server to complete the verification process.


That’s it! We have implemented the verification process using SMS Retriever API to help on our mobile application development. Those are easy to try, aren’t they?

If you have any questions, please let me know in the comments below!


References


Anang Kurniawan is one of Android developer in GITS Indonesia.


SMS verification is a common thing in an Android application. Android developers at GITS Indonesia have developed many mobile applications for Android. One of them is JRku, an application that is used all around Indonesia, to help user on paying insurance with Jasa Raharja. Want to know more about it?  Find out here.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

More articles

Latest article

Implementasi REST API di iOS Development menggunakan Alamofire dan SwiftyJSON

iOS Development – Tentang REST API Bagi seorang developer, mungkin sudah tidak asing lagi...

GITS Expert Talks: Guide to Building a Learning Organization

In 1995, Peter Senge coined the term of a Learning Organization. He defines it as a company that facilitates learning of its...

GITS Webinar: How to Build UI UX Portfolio that Stand Out

Apa saja yang harus disiapkan UI/UX designer dalam membuat portfolio? Setelah kamu membuat UI design, lalu bagaimana cara mendokumentasikan...

12 Pelajaran dalam GITS 12 Tahun

GITS genap berumur 12 tahun pada 13 September ini. Ini juga tandanya saya sudah 2 tahun lebih 1...

Customer Loyalty Program yang Cocok untuk Masa Pandemi COVID-19

Customer loyalty program atau program loyalitas kepada pelanggan adalah tentang bagaimana menghargai pelanggan. Kemudian, pada akhirnya, pelanggan yang...