Android Broadcast Receiver for Sent Sms Messages

How can I send an SMS from a BroadcastReceiver and check its status?

OK, ended up finding the solution in the end. Since the context passed in to the onReceive() method in the BroadCastReceiver doesn't let me register other BroadcastReceivers to listen for the "message sent" event, I ended up getting a grip of the app context and doing what follows:

In the BroadcastReceiver:

SmsManager smsManager = SmsManager.getDefault();
Intent intent = new Intent(SENT_SMS_FLAG);
PendingIntent sentIntent = PendingIntent.getBroadcast(context, 0,
intent, 0);
SMSForwarderApp.getAppContext().registerReceiver(
new MessageSentListener(),
new IntentFilter(SENT_SMS_FLAG));
smsManager.sendTextMessage("Here goes the destination of the SMS", null,
"Here goes the content of the SMS", sentIntent, null);

SENT_SMS_FLAG is simply a static string that uniquely identifies the intent I just made. My MessageSentListener looks like this:

public class MessageSentListener extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
int resultCode = this.getResultCode();
boolean successfullySent = resultCode == Activity.RESULT_OK;
//That boolean up there indicates the status of the message
SMSForwarderApp.getAppContext().unregisterReceiver(this);
//Notice how I get the app context again here and unregister this broadcast
//receiver to clear it from the system since it won't be used again
}

}

Android Broadcast Receiver for Sent SMS messages?

Unfortunately there is (currently) no way to implement a BroadcastReceiver because the standard sms application uses a SmsManger to send the messages but specifies concrete internal classes for the sent and delivered intents (SmsReceiver.class and MessageStatusReceiver.class respectively). Not that it is any consolation but you can find the following comment in the Sms application's source:

// TODO: Fix: It should not be necessary to
// specify the class in this intent. Doing that
// unnecessarily limits customizability.

The best alternative seems to be polling content://sms/sent, potentially using a ContentObserver.

Android - SMS Broadcast receiver

android.provider.Telephony.SMS_RECEIVED has a capital T, and yours in the manifest does not.

Please bear in mind that this Intent action is not documented.

How to get sms data in a Broadcast receiver

Here's your problem:

registerReceiver(..., new IntentFilter(SENT));

You're registering that Receiver for the action you're using for the sent confirmation, not for the SMS_RECEIVED action, which is what is broadcast when a message arrives.

The sent PendingIntent is used to confirm that the message has successfully left the device. The resulting Intent from that will not have any message PDUs on it, which is why you're crashing.

The action you need to register an incoming SMS Receiver for is "android.provider.Telephony.SMS_RECEIVED", or the constant Telephony.Sms.Intents.SMS_RECEIVED_ACTION, if you're compiling with API 19 or above.


To address the specific questions:

  1. Do I need the Receiver/Intent-filter block in my manifest, and if so, how do I name the listener in the first line?

Registering a Receiver in the manifest will allow your app to receive messages even when it's not already running, or in the foreground. If you don't need to do that, you don't necessarily need to register in the manifest. However, if the user navigates away from your Activity before receiving the message, the paused Activity won't get the broadcast.

The "safest" way to handle it would be to register in the manifest, but there you're registering a class, not a dynamic instance. You would need to create a MyBroadcastListener class, and somehow notify the Activity from that upon receipt; e.g., using startActivity(), or LocalBroadcastManager, or some other event bus implementation, etc.


  1. What is the likely reason I can not receive a copy of the incoming message in onReceive(), and what should I do to correct it?

As mentioned above, the PendingIntent passed in the sendTextMessage() call is for sent confirmation. Its resulting Intent won't have the incoming message on it. You just need to listen for the correct broadcast.


  1. Do I need to send a message and "catch it" in onReceive() in order to reliably get the devices phone number, or can I request permission to read SMS from the user, and just read the first message to get the incoming phone number?

You need to actually send a message. Incoming messages won't have the recipient number attached.

Broadcast receiver for sent messages

Finally I solved the problem just replacing this line:

sentIntents.add(PendingIntent.getBroadcast(ctx, 0, myIntent,0));

with this one:

sentIntents.add(PendingIntent.getBroadcast(ctx, 0, myIntent,PendingIntent.FLAG_UPDATE_CURRENT));

From the documentation:

FLAG_UPDATE_CURRENT
...if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.

How do I listen to SMS Delivered broadcast inside of a Service?

The code above is actually fine. Seems like the problem was that my Telecom Carrier (EthioTel) did not provide reliable sms delivered reports.

SMS Broadcast Receiver in Oreo+

I finally figured out what was wrong. Apparently, Android version Oreo+ does not deliver implicit broadcasts any more* (i.e., those specified in the manifest file <receiver>). You now must explicitly register your receiver (i.e., with registerReceiver()) in your code.

(*Note: Mike M correctly pointed out that received SMS broadcasts are excluded from this restriction according to Android doc, but nonetheless this was not so for me in practice).

So what I did to make this work was:

  • Completely Remove <receiver> from manifest.
  • Create an instance of my receiver and an intentFilter in my activities onCreate();

        MyReceiver = new SmsRecv();
    MyFilter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION );
  • Register the receiver in my Activity's onResume().

        i = registerReceiver( MyReceiver, MyFilter);  
  • Unregister the receiver in my Activity's onPause(). (This is neccessary to prevent leaks).

        unregisterReceiver( MyReceiver );

With the changes, the app worked perfectly.



Related Topics



Leave a reply



Submit