Reputation: 39881
I'd like my app to catch incoming SMS messages. There are a few examples of this around. Looks like we just need to do this:
// AndroidManifest.xml
<receiver android:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
// SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "SMS received.");
....
}
}
is this correct? I'm sending my phone some sms messages, but the log statement never gets printed. I do have some other SMS applications installed on the phone, which display a popup when the sms is received - are they somehow blocking the intent from getting passed down to my app, they are just consuming it completely?
Thanks
Upvotes: 22
Views: 58905
Reputation: 1
Android Messenger (the SMS client) has a "Chat" feature which transmits messages over WiFi instead of SMS.
If the person you are testing with uses Messenger as well, you'll need to disable this feature on one or both of your devices otherwise there is no SMS message actually being received:
To turn chat features off:
- Open Messages Messages Logo Round.
- Tap More More and then Settings.
- Tap Advanced and then Chat features.
- Turn Enable chat features on or off.
https://support.google.com/messages/answer/7189714?hl=en
Upvotes: 0
Reputation: 36484
You would also need to specify a uses-permission in your manifest file:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
The following tutorials should help:
React on incoming SMS
SMS messaging in Android
Upvotes: 32
Reputation: 2049
There are a few gotchas on the way. You can find all the needed info on stackoverflow. I have gathered all the info in this answer, for convenience.
"android.provider.Telephony.SMS_RECEIVED"
"android.permission.RECEIVE_SMS"
in manifest xml, in order to receive sms messages. In android 6 and above, you additionally need to ask for the permission in runtime.adb shell am broadcast
will not work. Use telnet connection to simulator to test sms receiving.The most important thing is to have the possibility to send fake sms messages to the device, so we can test the code.
For this we will use a virtual device and a telnet connection to it.
Now connect to the port number shown in the simulator title bar with telnet
$ telnet localhost 5554
If you see this: Android Console: Authentication required
, then you need to authenticate the connection with this command:
auth xxxxxx
Replace the xxxxxx
above with the token read from ~/.emulator_console_auth_token
file.
Now you should be able to run all the commands. To send a sms message, type this command:
sms send 555 "This is a message"
Where you can replace 555 with the sender telephone number and a message of your own.
To get the broadcasts, you need to register a BroadcastReceiver
object. You can do this in the manifest.xml OR just call registerReceiver
function. I will show you the latter, as it is easier to reason about and yet more flexible.
Connecting the broadcast receiver with the main activity
The data flow is one way. From broadcast receiver to the main activity. So the simplest way to get them to talk is to use a function interface. The activity will implement such a function and the broadcast receiver will have the activity instance passed as a parameter in the constructor.
File SmsHandler.java:
package ...
interface SmsHandler {
void handleSms(String sender, String message);
}
Implementing the broadcast receiver
The broadcast receiver will get the intent in a callback. We will use the function Telephony.Sms.Intents.getMessagesFromIntent(intent)
to get the sms messages. Notice the SmsHandler parameter in the constructor. It will be the activity to which we will send the received sms.
File SmsInterceptor.java:
package ...
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsMessage;
public class SmsInterceptor extends BroadcastReceiver {
private SmsHandler handler;
/* Constructor. Handler is the activity *
* which will show the messages to user. */
public SmsInterceptor(SmsHandler handler) {
this.handler = handler;
}
@Override
public void onReceive(Context context, Intent intent) {
/* Retrieve the sms message chunks from the intent */
SmsMessage[] rawSmsChunks;
try {
rawSmsChunks = Telephony.Sms.Intents.getMessagesFromIntent(intent);
} catch (NullPointerException ignored) { return; }
/* Gather all sms chunks for each sender separately */
Map<String, StringBuilder> sendersMap = new HashMap<>();
for (SmsMessage rawSmsChunk : rawSmsChunks) {
if (rawSmsChunk != null) {
String sender = rawSmsChunk.getDisplayOriginatingAddress();
String smsChunk = rawSmsChunk.getDisplayMessageBody();
StringBuilder smsBuilder;
if ( ! sendersMap.containsKey(sender) ) {
/* For each new sender create a separate StringBuilder */
smsBuilder = new StringBuilder();
sendersMap.put(sender, smsBuilder);
} else {
/* Sender already in map. Retrieve the StringBuilder */
smsBuilder = sendersMap.get(sender);
}
/* Add the sms chunk to the string builder */
smsBuilder.append(smsChunk);
}
}
/* Loop over every sms thread and concatenate the sms chunks to one piece */
for ( Map.Entry<String, StringBuilder> smsThread : sendersMap.entrySet() ) {
String sender = smsThread.getKey();
StringBuilder smsBuilder = smsThread.getValue();
String message = smsBuilder.toString();
handler.handleSms(sender, message);
}
}
}
The main activity
Finally we need to implement SmsHandler interface into the main activity and add registering the broadcast receiver and permission check to the onCreate
function.
File MainActivity.java:
package ...
import ...
public class MainActivity extends AppCompatActivity implements SmsHandler {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Register the broadcast receiver */
registerSmsListener();
/* Make sure, we have the permissions */
requestSmsPermission();
}
/* This function will be called by the broadcast receiver */
@Override
public void handleSms(String sender, String message) {
/* Here you can display the message to the user */
}
private void registerSmsListener() {
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
/* filter.setPriority(999); This is optional. */
SmsInterceptor receiver = new SmsInterceptor(this);
registerReceiver(receiver, filter);
}
private void requestSmsPermission() {
String permission = Manifest.permission.RECEIVE_SMS;
int grant = ContextCompat.checkSelfPermission(this, permission);
if ( grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(this, permission_list, 1);
}
}
}
Finally remember to add RECEIVE_SMS permission to your manifest xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application>
...
</application>
</manifest>
Upvotes: 15
Reputation: 12219
Also note that the Hangouts application will currently block my BroadcastReceiver from receiving SMS messages. I had to disable SMS functionality in the Hangouts application (Settings->SMS->Turn on SMS), before my SMS BroadcastReceived started getting fired.
Edit: It appears as though some applications will abortBroadcast() on the intent which will prevent other applications from receiving the intent. The solution is to increase the android:priority
attribute in the intent-filter
tag:
<receiver android:name="com.company.application.SMSBroadcastReceiver" >
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
See more details here: Enabling SMS support in Hangouts 2.0 breaks the BroadcastReceiver of SMS_RECEIVED in my app
Upvotes: 3
Reputation: 1407
One more thing that these answers haven't mentioned - you should require the permission android.permission.BROADCAST_SMS. If you don't do this, any application can spoof messages in your app.
<receiver android:name=".SMSReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Upvotes: 9
Reputation: 24453
You should read this acticle about send and receive sms programmatically. http://mobiforge.com/developing/story/sms-messaging-android
Upvotes: 1
Reputation: 13045
Did you try with the emulator ?
After deploying your application in the emulator, you can send events like SMS via the DDMS or via the command line by connecting with telnet :
telnet localhost <port_emulator>
send sms <incoming_tel_number> <sms_content>
port_emulator is usually 5554
Upvotes: 2