Receiving broadcast from notification on Android Oreo

I have a custom button in a sticky notification. I used to attach a PendingIntent to it for receiving button clicks:

Intent intent = new Intent();

intent.setAction("com.example.app.intent.action.BUTTON_CLICK");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 2000, intent, PendingIntent.FLAG_UPDATE_CURRENT);
contentViewExpanded.setOnClickPendingIntent(R.id.button, pendingIntent);

When i run this code on Oreo , i get BroadcastQueue: Background execution not allowed in logcat and don't receive button click.

I registered receiver with manifest:

<receiver
    android:name=".BroadcastReceiver.NotificationActionReceiver"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.intent.action.BUTTON_CLICK"/>
    </intent-filter>
</receiver>

I also tried registering receiver in my code:

NotificationActionReceiver mMyBroadcastReceiver = new NotificationActionReceiver();
IntentFilter filter = new IntentFilter("com.example.app.intent.action.BUTTON_CLICK");
mContext.registerReceiver(mMyBroadcastReceiver, filter);

This works but only when the app is visible to user.

Thanks for help

Answers


Never use an implicit Intent when an explicit Intent will work.

Replace:

Intent intent = new Intent();

intent.setAction("com.example.app.intent.action.BUTTON_CLICK");

with:

Intent intent = new Intent(this, NotificationActionReceiver.class);

And remove the <intent-filter> from the NotificationActionReceiver <receiver> element.


I ran into this issue as well on Android 8 - Oreo, but given my library project requirements, I don't have the explicitly named BroadcastReceiver class implementation, that the end-client will declare in it's AndroidManifest.

Solution:

Specify the application package on the Intent using setPackage(String).

Example:

// Application unique intent action String
final String receiverAction = getApplicationContext().getPackageName() 
                             + BaseLibraryReceiver.ACTION_SUFFIX;
// No need for Class definition in the constructor.
Intent intent = new Intent(); 
// Set the unique action.
intent.setAction(receiverAction);
// Set the application package name on the Intent, so only the application
// will have this Intent broadcasted, thus making it “explicit" and secure.
intent.setPackage(getApplicationContext().getPackageName());
...

From the Android Broadcasts: Security considerations and best practices docs.

In Android 4.0 and higher, you can specify a package with setPackage(String) when sending a broadcast. The system restricts the broadcast to the set of apps that match the package.

Here’s an example of the BroadcastReceiver declared (or merged) in to the end-client application’s AndroidManifest:

 <receiver
        android:name=“com.subclassed.receiver.ReceiverExtendedFromLibrary"
        android:exported="false"
        android:enabled="true">

        <intent-filter>
            <action android:name="${applicationId}.action.MY_UNIQUE_ACTION"/>
        </intent-filter>

 </receiver>

Since my example revolves around a library project that broadcasts an Intent, I’ve decided to keep the <intent-filter> and <action /> in the <receiver> declaration. Otherwise, there would be non-unique broadcast actions being fired, which could lead to potential issues where multiple applications receive the wrong broadcast. This is mostly a safety precaution. Of course you still need to check the action in the implementation of the BroadcastReceiver.

Hope someone finds this helpful!


Need Your Help

Cross Origin Resource Sharing with Credentials

http cors

I have a common authentication form across multiple subdomains (example.com, blog.example.com, and app.example.com). The login form must submit this data to example.com irrespective of where it is ...

How do you store an arbitrarily large integer value in memory?

c memory-management integer integer-arithmetic

I have to store an integer value that is larger than the maximum value for the long datatype. How would I store and manipulate this value in memory?