接收来自 Android Oreo 通知的广播

Receiving broadcast from notification on Android Oreo

我在置顶通知中有一个自定义按钮。
我曾经在其上附加一个 PendingIntent 以接收按钮点击:

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);

当我在 Oreo 上 运行 此代码时,我在 logcat 中得到 BroadcastQueue: Background execution not allowed 并且没有收到按钮点击。

我用清单注册了接收器:

<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>

我也试过在我的代码中注册接收器:

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

这有效,但仅当应用对用户可见时。

感谢帮助

当显式 Intent 有效时,切勿使用隐式 Intent

替换:

Intent intent = new Intent();

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

与:

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

并从 NotificationActionReceiver <receiver> 元素中删除 <intent-filter>

我 运行 也在 Android 8 - Oreo 上解决了这个问题,但是考虑到我的图书馆项目要求,我没有明确命名的 BroadcastReceiver class 实现, end-client 将在 AndroidManifest.

中声明

解法:

使用setPackage(String)指定Intent上的应用程序包。

例子:

// 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());
...

来自 Android Broadcasts: Security considerations and best practices 文档。

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.

下面是 BroadcastReceiver 声明(或合并)到 end-client 应用程序的 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>

由于我的示例围绕广播 Intent 的库项目展开,因此我决定在 <receiver> 声明中保留 <intent-filter><action />。否则,将触发 non-unique 个广播操作,这 可能 导致多个应用程序收到错误广播的潜在问题。这主要是一种安全预防措施。当然你还需要检查BroadcastReceiver.

中执行的action

希望有人觉得这有用!