前言
- 从字面意思上理解,
PendingIntent是一种延迟的Intent,表示一种延迟执行的意图操作。对,但又不完全对。 一句话概括,PendingIntent一种是支持授权其他应用以当前应用的身份执行包装的 Intent 操作的系统特性。 - 在这篇文章里,我将带你理解
PendingIntent的使用方法、设计理念以及核心源码分析,相信阅读完这篇文章后你对PendingIntent的理解将超过绝大部分同学。GitHub参考更多
1. 认识 PendingIntent
1.1 为什么要使用 PendingIntent?
PendingIntent 的应用场景关键在于间接的 Intent 跳转需求, 即先通过一级 Intent 跳转到某个组件,在该组件完成任务后再间接地跳转到二级的 Intent。PendingIntent 中的单词 “pending” 指延迟或挂起,就是指它是延迟的或挂起的。例如,你在以下场景中就可以使用 PendingIntent:
- 场景 1 - 系统通知消息的点击操作
- 场景 2 - 桌面微件的点击操作
- 场景 3 - 系统闹钟操作
- 场景 4 - 第三方应用回调操作
可以看到,在这些场景中,我们真正感兴趣的操作是挂起的,并且该操作并不是由当前应用执行,而是由某个外部应用来 “间接” 执行的。例如,我们在发送系统通知消息时,会通过 PendingIntent 构造一个系统通知 Notification ,并调用 NotificationManagerCompat.notify(…) 发送通知,此时并不会直接执行 PendingIntent。而是当系统显示通知,并且用户点击通知时,才会由系统通知这个系统应用间接执行 PendingIntent#send() ,而不是通过当前应用执行。
当然,在低版本系统中,你还可以使用嵌套 Intent(Intent#extra 中嵌套另一个 Intent)来实现以上需求。但是从 Android 12 开始,嵌套 Intent 将被严格禁止,原因下文会说。
1.2 PendingIntent 和 Intent 有什么区别?
从结构上来说,PendingIntent 是 Intent 的包装类,其内部持有一个代表最终意图操作的 Intent(事实上,内部是通过 IIntentSender 间接持有)。它们的区别我认为可以概括为 3 个维度:
- 1、执行进程不同 ——
PendingIntent在其他进程执行:Intent通常会在创建进程中执行,而PendingIntent通常不会在创建进程中执行; - 2、执行时间不同 ——
PendingIntent会延迟执行:Intent通常会立即执行,而PendingIntent通常会延迟执行,延迟到其他进程完成任务后再执行,甚至延迟到创建进程消亡后。例如,在 场景 1 - 系统通知消息的点击操作 中,即使发送系统通知消息的进程已经消亡了,依然不妨碍二级 Intent 的跳转; - 3、执行身份不同 ——
PendingIntent支持授权:PendingIntent内部持有授权信息,支持其他应用以当前应用的身份执行,这有利于避免嵌套 Intent 存在的安全隐患。而直接使用Intent的话,一般只能以当前应用的身份执行(为什么说一般?因为有Activity#startActivityAsUser()这个 API,但一般你拿不到所需的参数)。
提示: 当然了,如果你创建
PendingIntent后又马上同步地在当前进程消费这个PendingIntent,那么时间维度上就没区别了。但是这样做其实不符合PendingIntent的应用场景。
1.3 嵌套 Intent 存在的安全隐患
上文提到,在低版本系统中,你可以使用嵌套 Intent 实现类似于 PendingIntent 的需求。但这一方案从 Android 12 开始被严格禁止,为什么呢 —— 存在安全隐患。
举个例子,我们将启动 ClientCallbackActivity 的 Intent 嵌套到启动 ApiService 的 Intent 里,实现一个 场景 4 - 第三方应用回调操作 的效果:
- 步骤 1:
Client App请求Provider App的一个服务(这通过一级 Intent 实现); - 步骤 2:
Provider App在任务结束后回调到Client App的ClientCallbackActivity(这通过嵌套的二级 Intent 实现)。
该过程用示意图表示如下:

乍看起来没有问题,但其实存在 2 个隐蔽的安全隐患:
- 隐患 1 -
Client App: 由于ClientCallbackActivity是从另一个应用Provider App启动的,因此该Activity必须暴露为exported。这意味着除了Provider App可以启动该Activity外,同时也给了恶意应用启动该Activity的可能性。如果ClientCallbackActivity是一个普通的Activity还要说,要是ClientCallbackActivity是一个敏感或高风险的行为(例如支付回调),那么这就存在很大的安全隐患了; - 隐患 2 -
Provider App: 由于嵌套的Intent是在Provider App的上下文中启动的,那么二级Intent不仅可以正常启动Client App中的ClientCallbackActivity(打开exported时),还可以启动ProviderApp 中任意Activity。这意味着给了恶意应用启动Provider App中敏感或高风险的Activity的可能性,即使这个敏感的Activity

本文深入探讨了PendingIntent与Intent的区别,强调PendingIntent在延迟执行和跨进程操作中的作用,以及Android 12以后禁止嵌套PendingIntent的原因。文章详细介绍了PendingIntent的使用方法,包括创建、取消、可变性与不可变性,以及其背后的实现原理,帮助读者掌握PendingIntent在系统通知、桌面组件和第三方应用回调等场景中的正确应用。
最低0.47元/天 解锁文章
196

被折叠的 条评论
为什么被折叠?



