Incoming SMS forwarder article cover image

In short, this Android application could forward any SMS to the provided URL.

Let’s say you are writing all your spendings to Google Spreadsheets and want to fill it in from the SMS automatically. This is just one use-case of this app as an example.

The app is free. It doesn’t contain any ads or data sharing. The source code is open.

You could download the latest release from here.

What is SMS forwarding and why you might need it

The Android phone can receive SMS. You might need the SMS to be processed on your webserver. Using this app you can send a received text message immediately to your API endpoint or any website URL.

The app will compare the sender’s name or number with parameters. If it matches, the app will send SMS to a specified URL.

How to install the application

Download the latest release from here.

I have submitted the app to the F-Droid App Repository and the Amazon Appstore for Android. I will provide links after the review process will be finished.

The app is not in the Play Market. The reason is Google has not accepted apps, which is needed the “read SMS” permission but not is a default SMS handler. This app can only forward text messages, not store, etc, that’s why it can’t be used as a default SMS handler.

Here is a cite from Policy Center

Restricted Permission:
SMS permission group (e.g. READ_SMS, SEND_SMS, WRITE_SMS, RECEIVE_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS)

Requirement:
It must be actively registered as the default SMS or Assistant handler on the device.

Apps lacking default SMS, Phone, or Assistant handler capability may not declare use of the above permissions in the manifest.

How to forward text messages

At first, install the app and run it.

To add a new forwarding rule, press the floating button in the bottom right.
Incoming SMS forwarder main screen

Enter sender number or name. Usually, it is a number, but sometimes it might be a text name. Better to copy it from the default SMS messenger application.

If you want to forward every SMS, just enter * (asterisk) instead of a number.

Then enter the URL to which text messager will be forwarded and press ADD button.
Incoming SMS forwarder new forwarding rule dialog

Now you will see your text message forwarding rule in the list. If you want to change or delete a rule, press the Delete button.
Incoming SMS forwarder delete forwarding rule dialog

From now on, every received SMS will be compared with the sender number or name you entered. If it matched, the text message will be forwarded to the provided URL.

The request will be sent with a JSON payload. Here is a payload example:

1
2
3
4
{
"from": "123456789",
"text": "example SMS content"
}

If your phone is not connected to the internet or lost connection during sending, the application will make up to 10 attempts after internet connection recovery. The same will be when a request to provided URL is not Successful, i.e. response code is not 2XX.

There is a delay between attempts. The first delay will be at least 10 seconds, next will increase in the exponential progression. So the first delay will be at least 10 seconds, the second is 20 seconds, the third is 40 seconds, the fourth is 80 seconds, and so on.

SMS forwarder internals in Java

Here I provide some code snippets. If you are familiar with the Java language and wanted to know how this app works internally, this section is for you.

All files are located in the main folder.

When the app starts, first it invokes onCreate function. It checks RECEIVE_SMS permission and asks for it if the permission is not granted.

The next step is to render SMS forwarding rules. A rule is just a sender number or name and a URL. Rules are handling using ForwardingConfig class. The class is an abstraction for the Android SharedPreferences class.

The user interface is simple and provides the user to add or delete forwarding rules.

Next app part is a SmsReceiver. It is declared as an intent filter in AndroidManifest.xml file.

When your phone receives an SMS, the onReceive function in the SmsReceive class will be invoked. Here the app gets forwarding rules and checks if receive text message matching any rule:

1
2
3
4
5
6
7
8
String sender = message.getOriginatingAddress();

for (ForwardingConfig config : configs) {
if (sender.equals(config.getSender()) || config.getSender().equals(asterisk)) {
JSONObject messageJson = this.prepareMessage(sender, message.getMessageBody());
this.callWebHook(config.getUrl(), messageJson.toString());
}
}

The next step is to send a text message to the provided URL. The app uses WorkManager to do this task. The main advantage is that tasks are expected to run even if the app exits or the phone restarts. Also, it is convenient to handle retry attempts.

SmsReceive class will pass ULR and text to WebHookWorkRequest class.

WebHookWorkRequest is built with NetworkType.CONNECTED constraint. It means any working network connection is required for this query to be performed.

The backoff criteria is a no less than 10 seconds delay with an exponential increase between retry attempts.

The simplified exponential function looks like this:

1
Math.scalb(10, attempt - 1)

The app will try to make a request to the URL. If there is an error in the forwarding rule, like URL is not in the correct format, WebHookWorkRequest will not make any new attempt. If the app encounters a network error or a server responded with an error code, WorkManager will schedule a retry.

This was a simplified explanation with code samples. If you want to see all code, feel free to explore SMS forwarder source code.

Url monitoring

The current app version (v2) will try to resend text messages up to 10 times. If you have an error with a URL, e.g. server return 500 HTTP code, your server might not receive SMS.

To be sure your website or API endpoint is working I would suggest you monitor it. Read my post about website monitoring tools.