面试官:说一下 PendingIntent 和 Intent 的区别

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

前言

  • 从字面意思上理解,PendingIntent 是一种延迟的 Intent,表示一种延迟执行的意图操作。对,但又不完全对。 一句话概括,PendingIntent 一种是支持授权其他应用以当前应用的身份执行包装的 Intent 操作的系统特性
  • 在这篇文章里,我将带你理解 PendingIntent 的使用方法、设计理念以及核心源码分析,相信阅读完这篇文章后你对 PendingIntent 的理解将超过绝大部分同学。GitHub参考更多

1. 认识 PendingIntent

1.1 为什么要使用 PendingIntent

PendingIntent 的应用场景关键在于间接的 Intent 跳转需求, 即先通过一级 Intent 跳转到某个组件,在该组件完成任务后再间接地跳转到二级的 IntentPendingIntent 中的单词 “pending” 指延迟或挂起,就是指它是延迟的或挂起的。例如,你在以下场景中就可以使用 PendingIntent

  • 场景 1 - 系统通知消息的点击操作
  • 场景 2 - 桌面微件的点击操作
  • 场景 3 - 系统闹钟操作
  • 场景 4 - 第三方应用回调操作

可以看到,在这些场景中,我们真正感兴趣的操作是挂起的,并且该操作并不是由当前应用执行,而是由某个外部应用来 “间接” 执行的。例如,我们在发送系统通知消息时,会通过 PendingIntent 构造一个系统通知 Notification ,并调用 NotificationManagerCompat.notify(…) 发送通知,此时并不会直接执行 PendingIntent。而是当系统显示通知,并且用户点击通知时,才会由系统通知这个系统应用间接执行 PendingIntent#send() ,而不是通过当前应用执行。

当然,在低版本系统中,你还可以使用嵌套 IntentIntent#extra 中嵌套另一个 Intent)来实现以上需求。但是从 Android 12 开始,嵌套 Intent 将被严格禁止,原因下文会说。

1.2 PendingIntentIntent 有什么区别?

从结构上来说,PendingIntentIntent 的包装类,其内部持有一个代表最终意图操作的 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 开始被严格禁止,为什么呢 —— 存在安全隐患。
举个例子,我们将启动 ClientCallbackActivityIntent 嵌套到启动 ApiServiceIntent 里,实现一个 场景 4 - 第三方应用回调操作 的效果:

  • 步骤 1: Client App 请求 Provider App 的一个服务(这通过一级 Intent 实现);
  • 步骤 2: Provider App 在任务结束后回调到 Client AppClientCallbackActivity(这通过嵌套的二级 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 时),还可以启动 Provider App 中任意 Activity。这意味着给了恶意应用启动 Provider App 中敏感或高风险的 Activity 的可能性,即使这个敏感的 Activity
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值