在Android Oreo上接收来自通知的广播

12

我有一个置顶通知中的自定义按钮。
我曾经附加了一个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);

这个方法有效,但仅限于应用程序对用户可见的情况下。

谢谢帮助。


@UmarHussain 我知道它已经被更改了:D 我已经阅读了文档,但没有成功。 - Behnam Maboudi
Ph 好的,实际上我还没有在奥利奥中实现广播,所以不知道为什么会出现这个问题。 - Umar Hussain
2个回答

29

当明确的 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>


成功了!谢谢。其实我认为我的意图已经很明确了,因为它是针对我的应用程序的。 - Behnam Maboudi
4
显式意图是指 Intent 知道目标的具体组件,通常通过使用带有 Java Class 对象的构造函数(例如 NotificationActionReceiver.class)来创建。而隐式意图则缺少组件,因此 Android 会依靠其他信息如操作字符串来为你找到对应的组件。 - CommonsWare

8
我也在Android 8 - Oreo上遇到了这个问题,但是考虑到我的库项目要求,我没有明确命名的BroadcastReceiver类实现,最终客户端将在其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 广播:安全注意事项和最佳实践文档。

在Android 4.0及以上版本中,当发送广播时,你可以使用setPackage(String)指定一个包名。系统会将广播限制在与该包名匹配的应用程序集合中。

以下是将BroadcastReceiver声明(或合并)到最终客户端应用程序的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的库项目,我决定保留<intent-filter><action /><receiver>声明中。否则,会发出非唯一广播操作,这可能导致多个应用程序接收错误的广播,这主要是为了安全起见。当然,在实现BroadcastReceiver时仍需要检查操作。

希望有人能找到此信息有所帮助!


1
做得非常好!!我一直在尝试使用动态包来解决这个问题,然后偶然发现了你的帖子。非常有效,谢谢!! - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接