通过操作按钮关闭正在进行的Android通知而无需打开应用程序

24

我有一个应用程序,它有一个持续的通知来帮助记忆。 我想使用其中一个操作按钮解除此通知,但是当按下该按钮时,我不想打开应用程序。 我更喜欢使用内置的通知操作按钮,而不是创建一个RemoteViews对象来填充通知。 我看到一篇帖子提到使用BroadcastReceiver在此按钮上,该按钮在我的应用程序中接收,尽管他的教程并没有什么帮助,但听起来这正朝着正确的方向发展。

Intent resultIntent = new Intent(getBaseContext(), Dashboard.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(getBaseContext());
        stackBuilder.addParentStack(Dashboard.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                    0,
                    PendingIntent.FLAG_UPDATE_CURRENT
                );
    Intent cancel = new Intent(getBaseContext(), CancelNotification.class);
        stackBuilder.addParentStack(Dashboard.class);
        stackBuilder.addNextIntent(cancel);
        PendingIntent pendingCancel =
                stackBuilder.getPendingIntent(
                    0,
                    PendingIntent.FLAG_UPDATE_CURRENT
                );

    NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
        mb.setSmallIcon(R.drawable.cross_icon);
        mb.setContentTitle(ref);
        mb.setContentText(ver);
        mb.setPriority(NotificationCompat.PRIORITY_LOW);
        mb.setOngoing(true);
        mb.setStyle(new NotificationCompat.BigTextStyle().bigText(ver));
        mb.setContentIntent(resultPendingIntent);
        mb.addAction(R.drawable.ic_cancel_dark, "Dismiss", pendingCancel);

    manager.notify(1, mb.build());  

你能更清楚地表达你想要的吗?正在进行中的通知无法被用户解除,因此您的应用程序或服务必须负责取消它们。或者,如您所说,使用一个绑定到操作按钮的“BroadcastReceiver”来完成这个任务。该“BroadcastReceiver”只需要调用传递给它的通知ID上的cancel()方法即可。您还需要取消/结束引发通知的事件。 - ramaral
1
我想说的更普遍一些,我只是想能够按下通知按钮来执行某些操作,而不必打开应用程序。那么我应该如何实现BroadcastReceiver来执行任何操作呢?我尝试阅读的教程非常不清楚。 - cjbrooks12
3个回答

81

从这里开始:

int final NOTIFICATION_ID = 1;

//Create an Intent for the BroadcastReceiver
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId",NOTIFICATION_ID);

//Create the PendingIntent
PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, buttonIntent,0);

//Pass this PendingIntent to addAction method of Intent Builder
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
.....
.....
.....
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());  

创建广播接收器:

public class ButtonReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        int notificationId = intent.getIntExtra("notificationId", 0);

        // Do what you want were.
        ..............
        ..............

        // if you want cancel notification
        NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(notificationId);
    }
}  

如果您不希望在用户点击通知时显示任何活动,请按以下方式定义传递给setContentIntent的意图:

如果您不想在用户点击通知时触发任何操作,请将传递给setContentIntent的Intent定义为以下方式:

PendingIntent resultPendingIntent = PendingIntent.getActivity(context,  0, new Intent(), 0);
......
......
mb.setContentIntent(resultPendingIntent); 

在构建通知时,调用setAutoCancel()并将参数设置为true以在单击通知栏时关闭通知托盘:mb.setAutoCancel(true);


3
谢谢您提供的代码,它实现了预期的功能,但我遇到了一个额外的问题。代码能够关闭通知,但通知栏仍然保持打开状态。如何以编程方式隐藏/关闭它? - mudit
@mudit 在构建通知时将 setAutoCancel 设置为 true:mb.setAutoCancel(true); - ramaral
1
在我的情况下,onReceive 从未被调用。 - Roel
9
我严格按照你的示例操作,但是我忘记在清单文件中注册广播接收器:现在它能正常工作了! - Roel
1
谢谢,它帮助了我 :) - Cristian Hoyos
很棒的答案... - Ramesh

5

已接受的解决方案在Android 8.1及以上版本中不起作用。

按照已接受答案中的步骤操作,但更新以下这行:

//Create the PendingIntent
PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);

另请参阅PendingIntent.FLAG_UPDATE_CURRENT


我认为只有在使用与第一次显示通知时相同的接收器来解除通知时才需要这样做,因为在这种情况下,PendingIntent已经存在了?无论如何,这对我有效。 - Nicolas

1

我曾尝试使用@ramaral的答案,但是在onReceive方法中的notificationId总是-1,因此该解决方案不能正常工作。我已经找到了解决这个问题的方法,通过进行配置。

来自

PendingIntent.getBroadcast(context, 0, approvedIntent, 0)

为了

PendingIntent.getBroadcast(
    context,
    notificationId,
    approvedIntent,
    PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)

这里有一个例子,您可以跟着做。

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    super.onMessageReceived(remoteMessage)
    val notificationId = Random.nextInt()
    
    //Making Approve Intent for Button Action
    val approvedIntent = Intent(context, 
        BroadcastReceiverOuting::class.java).apply {
            action = ActionOuting.ACTION_APPROVED.name
            putExtra(
                Constant.NOTIFICATION_ID,
                notificationUid
            ) //Compulsory to dismiss this notification
            putExtra(Constant.STUDENT_IC, studentIc)
            putExtra(Constant.OUTING_ID, outingId)
        }
    val approvedPendingIntent: PendingIntent =
        PendingIntent.getBroadcast(
            context,
            notificationUid,
            approvedIntent,
            PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
        )
    val notification: Notification =
        notificationCompatBuilder
            .setStyle(bigTextStyle)
            .setContentTitle(title)
            .setContentText(description)
            .setSmallIcon(R.drawable.ic_logo_128)
            .setContentIntent(notifyPendingIntent)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .setAutoCancel(true)
            .addAction(
                R.drawable.ic_baseline_approve_check_24,
                context.getString(R.string.approve),
                approvedPendingIntent
            )
           .build()
    NotificationManagerCompat.from(context.applicationContext).apply {
       notify(notificationUid, notification)
    }
}

然后在BroadcastReceiverOuting

override fun onReceive(context: Context?, intent: Intent?) {
    if (intent != null && intent.action != null) {
        val notificationUid = intent.getIntExtra(Constant.NOTIFICATION_ID, -1)
        val studentIC = intent.getStringExtra(Constant.STUDENT_IC)!!
        val outingID = intent.getStringExtra(Constant.OUTING_ID)!!

        //Do something...

        //To dismiss the notification
        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.cancel(notificationUid)
    }
}

最后,不要忘记 AndroidManifest.xml 文件。
<receiver
    android:name=".utils.BroadcastReceiverOuting"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

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