AndroidPub
Published in

AndroidPub

Detecting & sending SMS on Android 📮

Runtime permissions, BroadcastReceiver & SmsManger.

Motivation

With so many different ways to communicate (I’m 👀 at you Google Developers), one might find odd talking about integrating the old-school SMS service in your app. Truth is, besides the usual 2-step-verification and related services, there are some areas on the planet 🌍 where data is still rare and/or very expensive, so if we are to tackle the next billion, most of these new users are in emerging markets so, SMS might be a good alternative or at least something to consider.

TL;DR: Project is available on GitHub. Note & Overview👇 gives you the rest.

With relative low effort you can have your app using SMS as a data source while providing a pleasing UX, a material design UI (beats plain text👌).

Note: I’m using the Bus-eta project as a implementation example, you can read more about the it in my previous post. I’ve also created a simplified and easier to understand project, check the available on GitHub.

Overview

  1. Ask for SMS permissions (both manifest and runtime)
  2. Send SMS using the system’s SmsManager
  3. Setting up a BroadcastReceiver to listen and handle for incoming SMS.

1. Asking for permission

We’ll need to ask for some permissions in order for our app to work with SMS, start by declaring in your AndroidManifest

<!-- To use SMS based services -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />

Now our pre-M users will be asked to accept these permission when they choose to install the app through the PlayStore.

But, as of beginning in Android 6.0 (API level 23), permissions must be requested at runtime, so we still need to make our app Marshmallow ready, otherwise a big % of users won’t be able to use sms, resulting in a very useless and frustrating effort from our part.

Sending SMS when you don’t ask for permissions in Marshmallow

So whenever you need to use SMS, check if the app has permissions if not, request:

It’s important to not request beforehand, I personally hate it when I start a new app and I get asked for random permissions, sometimes I haven’t even used the app, so don’t be lazy, and only ask when needed.

Requesting the permission will present the user with the follow system AlertDialog:

Transport ETA requesting runtime SMS permission.

As you can see the message given by the system is quite strong, unless it’s straightforward to your users why your app would need to access SMS, I would recommend you to show a simple explanation beforehand to avoid some of your more paranoid users (like me) to deny and render the whole feature useless.

Give the user some some context, is simple:

Showing a simple explanation beforehand

With minimal effort, our users are presented with simple but crucial information. Now they know why they should allow the app to access such sensitive data.

After the user decides we need to handle the permission response:

Note: Similar to calling startActivityForResult() , the SMS_PERMISSION_CODE is just a constant variable, it should match for both asking the permission, and handling the response.

2. Sending SMS through our app

Now that we have the required permissions we’ll use the default SmsManager in order to send our text:

SmsManager.getDefault().sendTextMessage(number, null, smsText, null, null);

Voilá! Our App will use the device’s default sms-messenger-app to send the sms 🙂 👌.

It’s considered good practice to inform the user normal fees apply, our app is just a dolled up version of the usual/default process. 💸

3. Listening for incoming SMS

Nowadays apps rarely have a one-way communication flow, so in order to listen to incoming SMS’s we need to setup our custom BroadcastReceiver

Broadcast receiver that listens to incoming sms’s

Of course you could always create a simple BroadcastReceiver and have the logic present on your Activity, but I prefer to keep this wrapper under a custom SmsBroadcastReceiver and only passing a listener for when the data is received. Avoiding ugly code floating around and unnecessary coupling.

Looking at line 47 of the above gist you can see that I’ve implemented some stricter conditions to when the listener is called, this suits my specific case, I only want to detect sms that come from a specific number and have a starting pattern of “SMS@CARRIS” which is passed via constructor:

private final String serviceProviderNumber;private final String serviceProviderSmsCondition;

This way we may ignore any other incoming sms, now we need to register ou receiver, in my case I want to listen while the app is open, so I’ll register in my Application class

The final step is assigning a listener, will only be called if the conditions are met:

smsBroadcastReceiver.setListener(new SmsBroadcastReceiver.Listener( {
@Override
public void onTextReceived(String text) {
// Do stuff with received text!
}
});

You can also register your broadcast receiver via the manifest by adding the following line to your AndroidManifest:

<receiver android:name="SmsBroadcastReceiver" />

And handle all the logic inside your own BroadcasReceiver, this way you keep all of your business logic wrapped inside your own class. For my case I want to have more control and adaptability, but using the manifest is the same as registering in your Application. My actual project has a Controller which handles a lot of the underlying edge cases that may surface with these custom implementations, but are outside of the article’s scope.

While using BroadcastReceivers beware of the priority setting, (but don’t abuse it 🙌).

References:

Hello! My name is Joaquim Ley, I’m currently based in Copenhagen, Denmark.

If you liked this article hit that 💚, if you know someone who might extract value please share, I’ll be looking for your opinion and suggestions in the comments, feedback is always welcome.

If you would like to see more content from me, 👊 the follow button!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store