Search code examples
androidbroadcastreceiver

using SMS BroadcastReceiver for both Kitkat and old versions


I developing an app which needs to receive sms message and does not let any other application receive sms.

App must work well on both Kitkat and older versions.(I make my app default sms app in kitkat)

here is what I tried in my manifast file(not all of it):

    <receiver android:name=".SmsReceiver"
            android:permission="android.permission.BROADCAST_SMS">
        <intent-filter android:priority="2147483647" >
            <action android:name="android.provider.Telephony.SMS_DELIVER" />
        </intent-filter>
    </receiver>



    <receiver android:name=".SmsReceiver" android:enabled="true">
        <intent-filter android:priority="2147483647">
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>

First receiver is for kitkat to let my app be default sms app(when I remove this part kitkat don't let my app to be default sms app) and second one is for older versions

On kitkat , The problem is all of my codes run two times (As I have two reciver)

And on older versions , my App runs the onReceive method one time but I got new message notification from Go SMS Pro , but I need the sms be received only by my application

Here is my SmsReceiver class:

public class SmsReceiver extends BroadcastReceiver 
{

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        Bundle bundle = intent.getExtras();
        if (bundle != null) 
        {
            Object[] pdus = (Object[]) bundle.get("pdus");
            if (pdus.length == 0) 
            {
                return;
            }
            SmsMessage[] messages = new SmsMessage[pdus.length];
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < pdus.length; i++) 
            {
                messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                sb.append(messages[i].getMessageBody());
            }
            String sender = messages[0].getOriginatingAddress();
            String message = sb.toString();

            abortBroadcast();// prevent any other broadcast receivers from receiving broadcast

            // things I need to do on SMS

        }
    }// on Rec

}

Solution

  • To support SMS handling for both older and newer versions of Android, I'd recommend having two different BroadcastReceiver classes: one for the new SMS_DELIVER_ACTION, and one registered for the original SMS_RECEIVED action, which should be disabled on KitKat (API level 19) and above so that you don't receive the same message twice. Each Receiver can simply pass the retrieved messages to a common processing component – e.g., a background Service – so you're not repeating code.

    We can effect the version enabling/disabling with a resource bool that's true by default, but false on versions starting with KitKat. For example:

    res/values/booleans.xml:

    <resources>
        <bool name="isPreKitKat">true</bool>
    </resources>
    

    res/values-v19/booleans.xml:

    <resources>
        <bool name="isPreKitKat">false</bool>
    </resources>
    
    <receiver
        android:name=".SmsReceiver"
        android:permission="android.permission.BROADCAST_SMS">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_DELIVER" />
        </intent-filter>
    </receiver>
    
    <receiver
        android:name=".OldSmsReceiver"
        android:enabled="@bool/isPreKitKat"
        android:permission="android.permission.BROADCAST_SMS">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>
    

    SMS_DELIVER_ACTION doesn't exist on pre-KitKat versions, so that Receiver just shouldn't ever run on those versions, though you may wish to similarly enable/disable SmsReceiver appropriately, if only for security reasons.


    You won't be able to abort the SMS_RECEIVED_ACTION broadcast at all in newer versions, as that is now disallowed altogether starting with KitKat. (Source)

    Note that—beginning with Android 4.4—any attempt by your app to abort the SMS_RECEIVED_ACTION broadcast will be ignored so all apps interested have the chance to receive it.

    However, if other SMS/messaging apps are behaving as recommended, they like you should no longer be listening for the SMS_RECEIVED_ACTION broadcast anyway. And if they're not the default, they won't get the SMS_DELIVER_ACTION one.

    So, beyond those apps, any others able to listen for SMS are hopefully doing it only when necessary, and only for valid purposes, as you can't really do anything to prevent it on KitKat and above.


    As for your problem with GO SMS Pro on pre-KitKat versions, there may not be anything you can do about it. Among other sources, this post thread suggests that you might overcome the problem by ensuring that your app is installed before GO SMS Pro. However, you can see from the comments that this is not a guaranteed solution. You might advise your users to turn off GO SMS Pro's "Disable other message notification" option, so your app can at least receive the pertinent broadcasts, even if it can't abort them. Note that Hangouts often causes the same problem.