Android SMS Retriever​ API: To Auto Verify SMS

Content posted here with the permission of the author Chandrashekhar Sahu, who is currently employed at Josh Software. Original post available here.

The Android app needs SMS receive/read permission to retrieve SMS content.

Imagine an application where the use case is to get the SMS only for validating the user using OTP. And rest of the app does not use SMS reading feature again. Then in this case, it is a waste of the resources & time and of course code to check the SMS permissions.

To solve this problem, Google has introduced SMS Retriever API, this API allows to retrieve the OTP without needing of the SMS permission in your application.

Image Credit: Google

Dependency for SMS Retriever API

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

Obtain the user’s phone number (Phone Selector API)

First, we need the number of the user on which the OTP will be received. We create a hint request object and set the phone number identifier supported field to true.

HintRequest hintRequest = new HintRequest.Builder()
        .setHintPickerConfig(newCredentialPickerConfig.Builder().setShowCancelButton(true).build())
        .setPhoneNumberIdentifierSupported(true)
        .build();

Then, we get a pending intent from that hint request for the phone number selector dialogue.

GoogleApiClient apiClient = new GoogleApiClient.Builder(getContext()).addApi(Auth.CREDENTIALS_API).enableAutoManage(getActivity(),
        GoogleApiHelper.getSafeAutoManageId(), new GoogleApiClient.OnConnectionFailedListener() {
            @Override
            public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
                Log.e(TAG, "Client connection failed: " + connectionResult.getErrorMessage());
            }).build();

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

Once the user selects the phone number, that phone number is returned to our app in the onActivityResult().

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == RC_PHONE_HINT) {
       if (data != null) {
          Credential cred = data.getParcelableExtra(Credential.EXTRA_KEY);
            if (cred != null) {
               final String unformattedPhone = cred.getId();
            }
       }    
    }
}

Start the SMS retriever

When we are ready to verify the user’s phone number, get an instance of the SmsRetrieverClientobject. Will call startSmsRetriever and attach success and failure listeners to the SMS retrieval task:

SmsRetrieverClient client = SmsRetriever.getClient(mContext);

// Starts SmsRetriever, waits for ONE matching SMS message until timeout
// (5 minutes).
Task<Void> task = client.startSmsRetriever();

// Listen for success/failure of the start Task. 
task.addOnSuccessListener(new OnSuccessListener<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        // Log.d(TAG,"Successfully started retriever");
    }
});

task.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        Log.e(TAG, "Failed to start retriever");
    });
);

Our server can then send the message to the phone using existing SMS infrastructure or service. When this message is received, Google Play services broadcasts an intent which contains the text of the message.

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 for SMS authenticity.
                    break;
                case CommonStatusCodes.TIMEOUT:
                    // Waiting for SMS timed out (5 minutes)
                    // Handle the error ...
                    break;
            }
        }
    }
}

We need to register this BroadcastReceiver in our Manifest file as follows

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

Construct a verification message:

When our server receives a request to verify a phone number, first construct the verification message that you will send to the user’s device. This message must:

Otherwise, the contents of the verification message can be whatever you choose. It is helpful to create a message from which you can easily extract the one-time code later on. For example, a valid verification message might look like the following:

<#> Use 123456 as your verification code 
FC+7qAH5AZu

Optional: Save the phone number with Smart Lock for Passwords

Optionally, after the user has verified their phone number, We can prompt the user to save this phone number account with Smart Lock for Passwords so it will be available automatically in other apps and on other devices without having to type or select the phone number again.

Click here to get the source code.

Happy Coding 🙂

Advertisements

About Sachin Shintre

Director, Josh Software
This entry was posted in General. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s