Automatically-read-OTP from SMSes — Android 4.3 to 8.x

E-commerce apps are the new rage and understandably so. They provide convenience and value to the user all the while backing this experience with reliable security. That said, creating a balanced user-experience is tricker to achieve than it looks; it’s easy to overdo, or underdo.

SMS is one of the common modes to authenticate, communicate and provide service to the users. As a preliminary step to even enable any of those, the user has to voluntarily register with their mobile number with the service provider.

Such “one-time” registration is usually seen as follows:

  1. User initiates a registration request,
  2. A one-time-password (OTP) is sent to the requested mobile number as a part of an SMS,
  3. User returns this OTP back to the server.

This is simple enough, but we can automate the last step! There are 3 common techniques to automatically read the OTP on behalf of your users:

  1. With a broadcast receiver (tested to work upto Android 8.x)
  2. With the official SMS verification and retrieval API
  3. With the official SMS manager API (token based)

Let’s discuss the broadcast receiver approach since it’s also the most well known. It’s quicker and does not require additional setups on the server. The other two approaches have been documented on the aforementioned links.

However, before we continue, there’s a breaking change with Android 8.x some of you may be stuck with. We’ll share our experience and offer a fix.

THE PROBLEM

When major changes were introduced on Android 8.x, our app STYFI was hit when the broadcast receiver failed on this latest version of Android. Snap! It seemed implicit broadcast may have been the concern, since a number of intent actions had been blacklisted as a part of “Background execution limits. But the action we’re interested in, was still whitelisted! After digging further, it was found that the permission wasn’t working right. There’s a subtle difference between the permission your app may request for — READ SMS or RECEIVE SMS.

THE FIX

READ SMS allows the app to read all SMSes that exist on device and also the incoming ones. RECEIVE SMS only allows reading the incoming ones. With the broadcast receiver approach, STYFI was earlier configured with the READ SMS permission which caused the failure on 8.x (while it worked absolutely fine on versions prior). What’s odd is that this permission isn’t deprecated either, and the documentation (as of the day this article is published) doesn’t talk anything about this behaviour.

Fear not! SMS_RECEIVED_ACTION is tested to work with the RECEIVE SMS permission! That’s how STYFI resumed its support for Android 8.x!

The steps go as follows:

  1. Request for a specific permission from the user,
  2. Construct an interface (A bridge between the broadcast receiver and the bound views),
  3. Construct a custom broadcast receiver,
  4. Register this receiver in the manifest,
  5. Bind it with any Activity or fragment,
  6. Unbind when onDestroy is called.

Request for a specific permission from the user

If permission is denied, rest of the steps won’t work and the app will throw a non-fatal error saying:

Permission Denial: receiving Intent { act=android.provider.Telephony.SMS_RECEIVED …

So it’s important that this permission is granted.

Construct an interface (A bridge between the broadcast receiver and the bound views)

Construct a custom broadcast receiver

Register this receiver in your manifest

Bind it with any Activity or fragment!

Don’t forget to unbind this listener

So this is how you can have your app listening for a specific SMS, and automatically read the contents within, on behalf of your users. It’s quick to setup, doesn’t break on Android Oreo and a nice addition to the overall user-experience.

— Raj Agrawal

Ideator/Indie-developer — ‘Le Face Keyboard’. Guitar Noodler.

Android, STYLABS.