PendingIntent 中的单词 “pending” 指延迟或挂起,就是指它是延迟的或挂起的。一句话概括,PendingIntent 一种是支持授权其他应用以当前应用的身份执行包装的 Intent 操作的系统特性。
什么场景下会使用 PendingIntent?
场景 1 - 系统通知消息的点击操作
场景 2 - 桌面Widget的点击操作
场景 3 - 系统闹钟操作
场景 4 - 第三方应用回调操作
PendingIntent 和 Intent 有什么区别?
从结构上来说,PendingIntent 是 Intent 的包装类,其内部持有一个代表最终意图操作的 Intent。
1、执行进程不同 —— PendingIntent 在其他进程执行: Intent 通常会在创建进程中执行,而 PendingIntent 通常不会在创建进程中执行;
2、执行时间不同 —— PendingIntent 会延迟执行: Intent 通常会立即执行,而 PendingIntent 通常会延迟执行,延迟到其他进程完成任务后再执行,甚至延迟到创建进程消亡后。例如,在 场景 1 - 系统通知消息的点击操作 中,即使发送系统通知消息的进程已经消亡了,依然不妨碍二级 Intent 的跳转;
3、执行身份不同 —— PendingIntent 支持授权: PendingIntent 内部持有授权信息,支持其他应用以当前应用的身份执行,这有利于避免嵌套 Intent 存在的安全隐患。
PendingIntent 的使用方法
启动组件:
// 启动 Activity
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
// 启动 Service
PendingIntent.Service(Context context, int requestCode, Intent intent, int flags)
// 发送广播
PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, int flags)
PendingIntent 的 4 个参数:
1、context: 当前应用的上下文,PendingIntent 将从中抽取授权信息;
2、requestCode: PendingIntent 的请求码,与 Intent 的请求码类似;
3、intent: 需要跳转的包装intent;
4、flag: PendingIntent标记位
PendingIntent标记位
FLAG_IMMUTABLE:不可变标记位,将约束外部应用消费 PendingIntent 修改其中的 Intent;
FLAG_MUTABLE:可变标记位,不约束外部应用消费 PendingIntent 修改其中的 Intent;
FLAG_UPDATE_CURRENT:如果系统中已经存在相同的 PendingIntent,那么将保留原有 PendingIntent 对象,而更新其中的 Intent。即使不可变 PendingIntent,依然可以在当前应用更新;
FLAG_CANCEL_CURRENT:如果系统中已经存在相同的 PendingIntent,那么将先取消原有的 PendingIntent,并重新创建新的 PendingIntent。
FLAG_NO_CREATE:如果系统中已经存在相同的 PendingIntent,那么不会重新创建,而是直接返回 null;
FLAG_ONE_SHOT:一次有效标记位,PendingIntent 被消费后不支持重复消费,即只能使用一次。
PendingIntent 可变性是一种对外部应用消费行为的约束机制,通过标记位 FLAG_MUTABLE 和 FLAG_IMMUTABLE 控制 PendingIntent 可变或不可变。可变性意味着在消费 PendingIntent 时,可以针对其中包装的 Intent 进行修改。强烈建议在创建 PendingIntent 时使用 FLAG_IMMUTABLE。
完整使用示例:
val intent = Intent()
intent.action = "xxxaction"
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
var flag = PendingIntent.FLAG_UPDATE_CURRENT
if (android.os.Build.VERSION.SDK_INT >= 31) {
flag = flag or PendingIntent.FLAG_IMMUTABLE
}
PendingIntent.getActivity(
context,
appWidgetId,
intent,
flag
)