Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >关于 PendingIntent 您需要知道的那些事

关于 PendingIntent 您需要知道的那些事

作者头像
Android 开发者
发布于 2022-03-09 07:16:10
发布于 2022-03-09 07:16:10
1.6K03
代码可运行
举报
文章被收录于专栏:Android 开发者Android 开发者
运行总次数:3
代码可运行

PendingIntentAndroid 框架中非常重要的组成部分,但是目前大多数与该主题相关的开发者资源更关注它的实现细节,即 "PendingIntent 是由系统维护的 token 引用",而忽略了它的用途。

由于 Android 12 对 PendingIntent 进行了 重要更新,包括需要显式确定 PendingIntent 是否是可变的,所以我认为有必要和大家深入聊聊 PendingIntent 有什么作用,系统如何使用它,以及为什么您会需要可变类型的 PendingIntent。

PendingIntent 是什么?

PendingIntent 对象封装了 Intent 对象的功能,同时以您应用的名义指定其他应用允许哪些操作的执行,来响应用户未来会进行的操作。比如,所封装的 Intent 可能会在闹铃关闭后或者用户点击通知时被触发。

PendingIntent 的关键点是其他应用在触发 intent 时是 以您应用的名义。换而言之,其他应用会使用您应用的身份来触发 intent。

为了让 PendingIntent 具备和普通 Intent 一样的功能,系统会使用创建 PendingIntent 时的身份来触发它。在大多数情况下,比如闹铃和通知,其中所用到的身份就是应用本身。

我们来看应用中使用 PendingIntent 的不同方式,以及我们使用这些方式的原因。

常规用法

使用 PendingIntent 最常规最基础的用法是作为关联某个通知所进行的操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val intent = Intent(applicationContext, MainActivity::class.java).apply {
    action = NOTIFICATION_ACTION
    data = deepLink
}
val pendingIntent = PendingIntent.getActivity(
    applicationContext,
    NOTIFICATION_REQUEST_CODE,
    intent,
    PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(
        applicationContext,
        NOTIFICATION_CHANNEL
    ).apply {
        // ...
        setContentIntent(pendingIntent)
        // ...
    }.build()
notificationManager.notify(
    NOTIFICATION_TAG,
    NOTIFICATION_ID,
    notification
)

可以看到我们构建了一个标准类型的 Intent 来打开我们的应用,然后,在添加到通知之前简单用 PendingIntent 封装了一下。

在本例中,由于我们明确知道未来需要进行的操作,所以我们使用 FLAG_IMMUTABLE 标记构建了无法被修改的 PendingIntent

调用 NotificationManagerCompat.notify() 之后工作就完成了。当系统显示通知,且用户点击通知时,会在我们的 PendingIntent 上调用 PendingIntent.send(),来启动我们的应用。

更新不可变的 PendingIntent

您也许会认为如果应用需要更新 PendingIntent,那么它需要是可变类型,但其实并不是。应用所创建的 PendingIntent 可通过 FLAG_UPDATE_CURRENT 标记来更新。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val updatedIntent = Intent(applicationContext, MainActivity::class.java).apply {
   action = NOTIFICATION_ACTION
   data = differentDeepLink
}

// 由于我们使用了 FLAG_UPDATE_CURRENT 标记,所以这里可以更新我们在上面创建的 
// PendingIntent
val updatedPendingIntent = PendingIntent.getActivity(
   applicationContext,
   NOTIFICATION_REQUEST_CODE,
   updatedIntent,
   PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// 该 PendingIntent 已被更新

在接下来的内容中我们会解释为什么将 PendingIntent 设置为可变类型。

跨应用 API

通常的用法并不局限于与系统交互。虽然在某些操作后使用 startActivityForResult()onActivityResult()接收回调 是非常常见的用法,但它并不是唯一用法。

想象一下一个线上订购应用提供了 API 使其他应用可以集成。当 Intent 启动了订购食物的流程后,应用可以 Intentextra 的方式访问 PendingIntent。一旦订单完成传递,订购应用仅需启动一次 PendingIntent

在本例中,订购应用使用了 PendingIntent 而没有直接发送 activity 结果,因为订单可能需要更长时间进行提交,而让用户在这个过程中等待是不合理的。

我们希望创建一个不可变的 PendingIntent,因为我们不希望线上订购应用修改我们的 Intent。当订单生效时,我们仅希望其他应用发送它,并保持它本身不变。

可变 PendingIntent

但是如果我们作为订购应用的开发者,希望添加一个特性可以允许用户回送消息至调用订购功能的应用呢?比如可以让调用的应用提示,"现在是披萨时间!"

要实现这样的效果就需要使用可变的 PendingIntent 了。

既然 PendingIntent 本质上是 Intent 的封装,有人可能会想可以通过一个 PendingIntent.getIntent() 方法来获得其中所封装的 Intent。但是答案是不可以的。那么该如何实现呢?

PendingIntent 中除了不含任何参数的 send() 方法之外,还有其他 send 方法的版本,包括这个可以接受 Intent 作为参数的 版本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fun PendingIntent.send(
   context: Context!,
   code: Int,
   intent: Intent?
)

这里的 Intent 参数并不会替换 PendingIntent 所封装的 Intent,而是通过 PendingIntent 在创建时所封装的 Intent 来填充参数。

我们来看下面的例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val orderDeliveredIntent = Intent(applicationContext, OrderDeliveredActivity::class.java).apply {
   action = ACTION_ORDER_DELIVERED
}
val mutablePendingIntent = PendingIntent.getActivity(
   applicationContext,
   NOTIFICATION_REQUEST_CODE,
   orderDeliveredIntent,
   PendingIntent.FLAG_MUTABLE
)

这里的 PendingIntent 会被传递到我们的线上订购应用。当传递完成后,应用可以得到一个 customerMessage,并将其作为 intent 的 extra 回传,如下示例所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val intentWithExtrasToFill = Intent().apply {
  putExtra(EXTRA_CUSTOMER_MESSAGE, customerMessage)
}
mutablePendingIntent.send(
  applicationContext,
  PENDING_INTENT_CODE,
  intentWithExtrasToFill
)

调用端的应用会在它的 Intent 中得到 EXTRA_CUSTOMER_MESSAGE extra,并显示消息。

声明可变的 PendingIntent 时需要特别注意的事

⚠️当创建可变的 PendingIntent 时,始终 显式设置要启动的 Intent 的 component。可以通过我们上面的实现方式操作,即显式设置要接收的准确类名,不过也可以通过 Intent.setComponent() 实现。

您的应用可能会在某些场景下调用 Intent.setPackage() 来实现更方便。但是请特别注意这样的做法有可能会 匹配到多个 component。如果可以的话,最好指定特定的 component。

⚠️如果您尝试覆写使用 FLAG_IMMUTABLE 创建的 PendingIntent 中的值,那么该操作会失败且没有任何提示,并传递原始封装未修改的 Intent

请记住应用总是可以更新自身的 PendingIntent,即使是不可变类型。使 PendingIntent 成为可变类型的唯一原因是其他应用需要通过某种方式更新其中封装的 Intent

关于标记的详情

我们上面介绍了少数几个可用于创建 PendingIntent 的标记,还有一些标记也为大家介绍一下。

FLAG_IMMUTABLE: 表示其他应用通过 PendingIntent.send() 发送到 PendingIntent 中的 Intent 无法被修改。应用总是可以使用 FLAG_UPDATE_CURRENT 标记来修改它自己的 PendingIntent。

在 Android 12 之前的系统中,不带有该标记创建的 PendingIntent 默认是可变类型。

⚠️ Android 6 (API 23) 之前的系统中,PendingIntent 都是可变类型。

🆕FLAG_MUTABLE: 表示由 PendingIntent.send() 传入的 intent 内容可以被应用合并到 PendingIntent 中的 Intent。

⚠️ 对于任何可变类型的 PendingIntent,始终 设置其中所封装的 IntentComponentName。如果未采取该操作的话可能会造成安全隐患。

该标记是在 Android 12 版本中加入。Android 12 之前的版本中,任何未指定 FLAG_IMMUTABLE标记所创建的 PendingIntent 都是隐式可变类型。

FLAG_UPDATE_CURRENT: 向系统发起请求,使用新的 extra 数据更新已有的 PendingIntent,而不是保存新的 PendingIntent。如果 PendingIntent 未注册,则进行注册。

FLAG_ONE_SHOT: 仅允许 PendingIntent (通过 PendingIntent.send()) 被发送一次。对于传递 PendingIntent 时,其内部的 Intent 仅能被发送一次的场景就非常重要了。该机制可能便于操作,或者可以避免应用多次执行某项操作。

🔐 使用 FLAG_ONE_SHOT 来避免类似 "重放攻击" 的问题。

FLAG_CANCEL_CURRENT: 在注册新的 PendingIntent 之前,取消已存在的某个 PendingIntent。该标记用于当某个 PendingIntent 被发送到某应用,然后您希望将它转发到另一个应用,并更新其中的数据。使用 FLAG_CANCEL_CURRENT 之后,之前的应用将无法再调用 send 方法,而之后的应用可以调用。

接收 PendingIntent

有些情况下系统或者其他框架会将 PendingIntent 作为 API 调用的返回值。举一个典型例子是方法 MediaStore.createWriteRequest(),它是在 Android 11 中新增的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static fun MediaStore.createWriteRequest(
   resolver: ContentResolver,
   uris: MutableCollection<Uri>
): PendingIntent

正如我们应用创建的 PendingIntent 一样,它是以我们应用的身份运行,而系统创建的 PendingIntent,它是以系统的身份运行。具体到这里 API 的使用场景,它允许应用打开 Activity 并赋予我们的应用 Uri 集合的写权限。

总结

我们在本文中介绍了 PendingIntent 如何作为 Intent 的封装使系统或者其他应用能够在未来某一时间以某个应用的身份启动该应用所创建的 Intent。

我们还介绍了 PendingIntent 为何需要设置为不可变,以及这么做并不会影响应用修改自身所创建的 PendingIntent 对象。可以通过 FLAG_UPDATE_CURRENT 标记加上 FLAG_IMMUTABLE 来实现该操作。

我们还介绍了如果 PendingIntent 是可变的,需要做的预防措施 — 保证对封装的 Intent 设置 ComponentName

最后,我们介绍了有时系统或者框架如何向应用提供 PendingIntent,以便我们能够决定如何并且何时运行它们。

Android 12 中提升了应用的安全性,PendingIntent 的这些更新与之相得益彰。更多内容请查阅我们之前的推文《Android 12 首个开发者预览版到来》。

如需了解更多,欢迎 使用 Android 12 开发者预览版 测试您的应用,并 告诉我们 您的使用体验。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
你说一下 PendingIntent 和 Intent 的区别?
PendingIntent 的应用场景关键在于间接的 Intent 跳转需求, 即先通过一级 Intent 跳转到某个组件,在该组件完成任务后再间接地跳转到二级的 Intent。PendingIntent 中的单词 “pending” 指延迟或挂起,就是指它是延迟的或挂起的。例如,你在以下场景中就可以使用 PendingIntent:
用户9995743
2022/09/26
7750
你说一下 PendingIntent 和 Intent 的区别?
Intent 和 PendingIntent 区别
intent 英文意思是意图,pending 表示即将发生或来临的事情。  PendingIntent 这个类用于处理即将发生的事情,比如在通知Notification中用于跳转页面,但不是马上跳转。 
阳光岛主
2019/02/19
2.2K0
Intent 和 PendingIntent 区别
Android通知Notification使用全解析,看这篇就够了
通知是 Android 在您的应用 UI 之外显示的消息,用于向用户提供提醒、来自其他人的通信或来自您的应用的其他及时信息。用户可以点击通知打开您的应用或直接从通知中执行操作。
yechaoa
2022/06/27
7.5K0
Android通知Notification使用全解析,看这篇就够了
Android画中画(PIP)进阶---Action按钮的使用
上一篇《Android画中画(PIP)模式使用》介绍了画中画的使用,今天这篇来讲讲Action按钮的使用,主要是广播方式更新UI及Android 12后的兼容性问题。
Vaccae
2022/12/29
1.3K0
Android画中画(PIP)进阶---Action按钮的使用
Android8.0+ 通知适配实战代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //分组(可选) //groupId要唯一
Zachary46
2018/12/06
1.1K0
Android Notification细思极恐的适配
近期项目的迭代版本开发,部门惊喜的申请了一台9.0的机器,是目前部门有史以来第一台8.0以上的机器,满怀喜悦的跑起项目,惊讶地发现Notification的在9.0以上的机器突然不能弹出通知了,惊讶之余发现发通知管理的权限没有开启(就觉得在我的代码怎么会有问题),结果开启了仍然无法接收到通知(打脸了...),马上请教了google大神,发现了毛病
包子388321
2020/06/16
1.4K0
你知道Android Nougat (牛轧糖)有哪些新鲜口味吗?
Android 7.0 经过5个开发者预览版本的改善,终于在8.22日正式推送,并确定版本名为Nougat(牛轧糖)。结合本人的体验,在此简单的聊聊Android 7.0新特性。
open
2020/03/19
8510
你知道Android Nougat (牛轧糖)有哪些新鲜口味吗?
Android 中使用通知Kotlin 版
在 MainActivity 中重写 onRequestPermissionsResult:
龙小雨
2025/05/16
1590
Art of Android Development Reading Notes 5
《Android开发艺术探索》读书笔记 (5) 第5章 理解RemoteViews
宅男潇涧
2018/08/01
6570
Android14 适配之——现有 App 安装到 Android14 手机上需要注意些什么?
Android14 即将正式发布,作为开发者需要注意哪些内容?长话短说,一起来看看吧~
修之竹
2023/11/22
5.1K0
Android14 适配之——现有 App 安装到 Android14 手机上需要注意些什么?
消息栏通知(Notification)介绍
用过安卓的应该对通知栏消息都很熟悉了,下面是演示通知栏消息的一个Demo,首先来看一下界面,后面是代码,解释就都放在代码里了.
全栈程序员站长
2022/07/20
1.7K0
消息栏通知(Notification)介绍
10.多媒体
通知 通知(Notification)是 Android系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容。 通知的基本用法 通知的用法比较灵活,既可以在活动里创建,也可以在广播接收器里创建,当然还可以服务里创建。相比于广播接收器和服务,在活动里创建通知的场景还是比较少的,因为一般只有当程序进入到后台的时候才需要使用通知。 publicclass
六月的雨
2018/05/14
1.4K0
android notification,notificationmanager详解
我们知道在使用Android的通知的时候一定会用到NotificationManager 、 Notification这两个类,这两个类的作用分别是: NotificationManager :  是状态栏通知的管理类,负责发通知、清楚通知等。 Notification:状态栏通知对象,可以设置icon、文字、提示声音、振动等等参数。 这里需要声明一点,由于Android的系统升级,Android在通知这块也有很多老的东西被抛弃了,一个是api11的版本,一个是api16的版本。我们来比较下api11之前
xiangzhihong
2018/02/05
1.7K0
android notification,notificationmanager详解
0703-APP-Notification-statue-bar
1.展示显示textTicker和仅仅有icon的两种情况:当參数showTicker为true时显示否则不显示
全栈程序员站长
2022/07/11
3710
消息通知Notificatio在8.0上不显示,适配Android8.0
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
黄林晴
2019/08/31
1.4K0
App和SDK开发必看 | 个推分享Android12适配指南
10 月 4 日,谷歌将Android12源代码推送至 Android 开源项目 (AOSP)。自从2021年2月发布Android12第一个预览版以来,历经9个月时间测试和优化,正式版本的Android12终于来了!不仅在UI方面做了不少升级,Android12对个人隐私安全的保护也得到了进一步增强。整体来讲,Android12更加智能、高效和安全,感兴趣的开发者可以登录官网下载源码测试学习。
个推君
2021/12/24
1.7K0
App和SDK开发必看 | 个推分享Android12适配指南
Android12,你的适配开始了吗
Android 12 开发者预览版计划从 2021 年 2 月开始启动,到向 AOSP 和 OEM 提供最终的公开版本时结束,目前应该已经到beta3阶段了,看看官方里程碑时间轴,你的适配工作开始了吗
Android扫地僧
2021/04/26
4.5K0
Android12,你的适配开始了吗
笔记49 | Android通讯之Notification
地址 https://www.cnblogs.com/travellife/p/Android-Notification-xiang-jie.html http://www.jianshu.com/p/8f7b59a1c43d http://blog.csdn.net/xiangyong_1521/article/details/78783806 ---- 目录 Notification 概述 Notification 的基本操作 创建 Notification 给 Notification 设置 Act
项勇
2018/06/19
1.9K1
Notification与Widget(其实没怎么讲)Android应用界面开发
Notification与Widget,他们为什么要一起讲呢?因为他们很相似,甚至自定义界面的方法都是一样的,这点可能很多书里没有写
爱因斯坦福
2018/09/10
1.5K0
android的消息通知栏
在android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等。 下面就来说说经常会使用到通知机制中的通知栏框架(Notificaiton),它适用于交互事件的通知。它是位于顶层可以展开的通知列表。它会时不时的提醒你什么软件该更新了,什么人发你微信消息了等。 (网上看了下,全面介绍的文章不多,所以就萌生了写这篇的念头,随便当作回顾笔记。下面我就通过官方文档、源代码、书上的一些
xiangzhihong
2018/01/30
4.5K0
android的消息通知栏
相关推荐
你说一下 PendingIntent 和 Intent 的区别?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验