Android:如何通过PendingIntent传参实现通知Action点击后取消并跳转?
解决通知Action按钮点击后跳转并取消通知的问题
我做了一个带Action按钮的通知,希望点击按钮后打开应用内指定页面,同时自动取消通知。点击通知主体时用setAutoCancel(true)就能取消,但Action按钮必须调用NotificationManager.cancel(id)才行。我尝试在Intent里传通知ID作为Extra,结果出现异常:应用后台时点击Action会拉到前台,但前台时点击没反应(跳不到目标页面),而且BroadcastReceiver接收不到任何参数。
现有代码
NotificationPublisher.kt
val intent = Intent(Intent.ACTION_VIEW).apply { //a uri to destination fragment data = intents.getDestination() flags = Intent.FLAG_ACTIVITY_NEW_TASK } intent.putExtra("notification_id", idHashCode) val pendingIntent = PendingIntent.getActivity(context,idHashCode,intent,PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) return NotificationCompat.Builder(context,CHANNEL) .setSmallIcon(R.drawable.notification_icon) .setContentTitle(title) .setContentText(subTitle) .setDefaults(Notification.DEFAULT_ALL) .setPriority(NotificationCompat.PRIORITY_HIGH) .setVibrate(LongArray(2) { 1000 }) .setNumber(1) .setOnlyAlertOnce(true) .setStyle(NotificationCompat.BigTextStyle()) .setAutoCancel(true) .addAction(0,getActionTextWithColor(context, R.string.go_to_destination, R.color.primary), pendingIntent)
NotificationReceiver.kt
class NotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val id = intent.getIntExtra("notification_id", -1) if(id > 0){ val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager manager.cancel(id) } } }
AndroidManifest.xml
<receiver android:name="com.myApp.notification.NotificationReceiver" android:exported="false" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <data android:host="myApp.com" android:pathPrefix="/destination" android:scheme="myApp" /> </intent-filter> </receiver>
解决方案
方案一:用广播接收器串联取消通知+跳转逻辑
核心是给Action按钮绑定广播PendingIntent,在广播里先取消通知,再启动页面跳转:
- 修改NotificationPublisher.kt
// 1. 定义跳转页面的Intent val pageIntent = Intent(Intent.ACTION_VIEW).apply { data = intents.getDestination() flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP } // 2. 定义取消通知的广播Intent val cancelIntent = Intent(context, NotificationReceiver::class.java).apply { putExtra("notification_id", idHashCode) action = "com.myApp.action.CANCEL_NOTIFICATION" // 自定义action避免冲突 } val cancelPendingIntent = PendingIntent.getBroadcast( context, idHashCode + 1000, // 用不同requestCode区分PendingIntent cancelIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 3. 给Action按钮绑定广播PendingIntent return NotificationCompat.Builder(context, CHANNEL) // 保留原有其他配置 .setSmallIcon(R.drawable.notification_icon) .setContentTitle(title) .setContentText(subTitle) .setDefaults(Notification.DEFAULT_ALL) .setPriority(NotificationCompat.PRIORITY_HIGH) .setVibrate(LongArray(2) { 1000 }) .setNumber(1) .setOnlyAlertOnce(true) .setStyle(NotificationCompat.BigTextStyle()) .setAutoCancel(true) .addAction( 0, getActionTextWithColor(context, R.string.go_to_destination, R.color.primary), cancelPendingIntent )
- 修改NotificationReceiver.kt
class NotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val id = intent.getIntExtra("notification_id", -1) if (id > 0) { // 先取消通知 val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager manager.cancel(id) // 再启动页面跳转 val pageIntent = Intent(Intent.ACTION_VIEW).apply { data = intents.getDestination() // 复用原目标Uri flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP } context.startActivity(pageIntent) } } }
- 修改AndroidManifest.xml的接收器配置
<receiver android:name="com.myApp.notification.NotificationReceiver" android:exported="false" android:enabled="true"> <intent-filter> <action android:name="com.myApp.action.CANCEL_NOTIFICATION"/> </intent-filter> </receiver>
方案二:在目标页面Activity中取消通知
如果跳转目标是Activity,直接在Activity里处理通知取消,无需广播接收器:
- 修改NotificationPublisher.kt
val intent = Intent(context, TargetActivity::class.java).apply { putExtra("notification_id", idHashCode) // 确保前台状态下也能触发页面更新 flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP } val pendingIntent = PendingIntent.getActivity( context, idHashCode, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) return NotificationCompat.Builder(context, CHANNEL) // 保留原有其他配置 .addAction( 0, getActionTextWithColor(context, R.string.go_to_destination, R.color.primary), pendingIntent )
- 在TargetActivity中处理取消逻辑
class TargetActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) handleNotificationCancel() // 切换到目标Fragment的逻辑 supportFragmentManager.beginTransaction() .replace(R.id.container, TargetFragment()) .commit() } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) setIntent(intent) handleNotificationCancel() } private fun handleNotificationCancel() { intent.getIntExtra("notification_id", -1).takeIf { it > 0 }?.let { id -> val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager manager.cancel(id) } } }
问题根源
之前的写法有两个核心问题:
- 用
PendingIntent.getActivity()创建的是启动Activity的PendingIntent,广播接收器根本接收不到这个Intent,自然拿不到notification_id - 应用前台时,仅设置
FLAG_ACTIVITY_NEW_TASK不会触发Activity的重新创建,如果Activity未处理onNewIntent,就不会执行跳转逻辑
内容的提问来源于stack exchange,提问作者Joan
相关产品推荐
相关产品推荐

