PendingIntent
is a very important part of the Android framework, but most of the developer resources related to this topic pay more attention to its implementation details, that is, "PendingIntent is a token reference maintained by the system", and ignores its purpose. .
Because Android 12 Dui PendingIntent were important updates , including the need to explicitly determine whether PendingIntent is variable, and so I think we need to talk in depth PendingIntent what role, how the system uses it and why you need to be PendingIntent of variable type.
What is PendingIntent?
The PendingIntent object encapsulates the functionality of the Intent object, and at the same time specifies what operations are allowed by other applications in your application's name to respond to future operations the user will perform. For example, the encapsulated Intent may be triggered after the alarm is turned off or when the user clicks on the notification.
The key point is PendingIntent other applications when triggered intent is in the name of your application . In other words, other apps will use your app's identity to trigger intents.
In order to make the PendingIntent have the same function as the ordinary Intent, the system will use the identity when the PendingIntent was created to trigger it. In most cases, such as alarms and notifications, the identity used is the application itself.
Let's look at the different ways in which PendingIntent is used in the application, and why we use these ways.
Regular usage
The PendingIntent
is as an operation associated with a notification.
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
)
You can see that we built a standard type of Intent
to open our application, and then simply encapsulated it PendingIntent
In this case, because we clearly know what the future needs of the operation, so we use FLAG_IMMUTABLE
marker construct that can not be modified PendingIntent
.
After calling NotificationManagerCompat.notify() ), the work is complete. When a notification system, and the user clicks on the notification, will be in our PendingIntent
call on PendingIntent.send () , to start our application.
Update immutable PendingIntent
You might think that if the application needs to update PendingIntent
, then it needs to be a variable type, but it is not. PendingIntent
created by the application can be updated with the FLAG_UPDATE_CURRENT
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 已被更新
In the following content we will explain why PendingIntent
set as a variable type.
Cross-application API
The usual usage is not limited to interacting with the system. Although after some operations startActivityForResult () ) and the onActivityResult () ) to receive callbacks is very common usage, but it is not the only usage.
Imagine that an online ordering application provides an API to enable other applications to integrate. When Intent
After starting the ordering of food processes, applications can Intent
of extra
way to access PendingIntent
. Once the order is delivered, the ordering application only needs to start PendingIntent
once.
In this example, the ordering application uses PendingIntent
without sending the activity result directly, because the order may take longer to submit, and it is unreasonable for the user to wait in the process.
We want to create an immutable PendingIntent
because we don’t want the online ordering application to modify our Intent
. When the order is valid, we only want other apps to send it and keep it unchanged.
Variable PendingIntent
But what if we, as a developer of an ordering application, want to add a feature that allows users to send messages back to the application that calls the ordering function? For example, the calling application can prompt, "It's pizza time!"
To achieve this effect, you need to use a variable PendingIntent.
Since PendingIntent
is essentially Intent
package, one might think by a PendingIntent.getIntent()
be obtained in which the encapsulated method Intent
. But the answer is no. So how can it be achieved?
PendingIntent
In addition no parameters send()
method, there are other versions of the send method, comprising the acceptable Intent
as a parameter version ):
fun PendingIntent.send(
context: Context!,
code: Int,
intent: Intent?
)
Here Intent
parameters not replaced PendingIntent
encapsulated Intent
, but by PendingIntent
when creating the encapsulated Intent
to filling parameter.
Let's look at the following example.
val orderDeliveredIntent = Intent(applicationContext, OrderDeliveredActivity::class.java).apply {
action = ACTION_ORDER_DELIVERED
}
val mutablePendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_REQUEST_CODE,
orderDeliveredIntent,
PendingIntent.FLAG_MUTABLE
)
The PendingIntent
here will be passed to our online ordering application. When the transfer is complete, the application can get a customerMessage
and return it as an extra of the intent, as shown in the following example:
val intentWithExtrasToFill = Intent().apply {
putExtra(EXTRA_CUSTOMER_MESSAGE, customerMessage)
}
mutablePendingIntent.send(
applicationContext,
PENDING_INTENT_CODE,
intentWithExtrasToFill
)
The calling application will get the EXTRA_CUSTOMER_MESSAGE
Intent
and display the message.
to pay special attention to when declaring a variable PendingIntent
⚠️When creating a variable PendingIntent
, always explicitly sets the component Intent
to be started. It can be operated by our implementation above, that is, explicitly setting the exact class name to be received, but it can also be achieved by Intent.setComponent() ).
Your application may call Intent.setPackage()
in some scenarios to make it more convenient. But please pay special attention to this approach may to multiple component . If possible, it is best to specify a specific component.
⚠️If you try to overwrite FLAG_IMMUTABLE
created with PendingIntent
, then the operation will without any prompt , and pass the original package unmodified Intent
.
Remember that the application can always update its own PendingIntent
, even if it is an immutable type. The only reason for making PendingIntent
a variable type is that other applications need to update the encapsulated Intent
some way.
about the tag
We have introduced a few PendingIntent
, and some tags are also introduced for everyone.
FLAG_IMMUTABLE : other applications represented by PendingIntent.send () sent to PendingIntent
the Intent
can not be modified. The application can always use the FLAG_UPDATE_CURRENT
tag to modify its own PendingIntent.
In systems prior to Android 12, PendingIntent
created without this mark is a variable type by default.
⚠️ In systems prior to Android 6 (API 23), PendingIntent
are all variable types.
🆕 FLAG_MUTABLE
: Indicates that the intent content passed in by PendingIntent.send() can be merged into the Intent in PendingIntent by the application.
⚠️ For any variable type of PendingIntent, is always set to the encapsulated Intent
ComponentName
. Failure to take this action may cause safety hazards.
This mark was added in the Android 12 version. In versions prior to Android 12, any PendingIntent created without specifying the FLAG_IMMUTABLE flag is an implicit variable type.
FLAG_UPDATE_CURRENT
: Initiate a request to the system to update the existing PendingIntent with new extra data instead of saving the new PendingIntent. If PendingIntent is not registered, register it.
FLAG_ONE_SHOT
: Only allow PendingIntent (via PendingIntent.send()) to be sent once. It is very important for the scenario where the internal Intent can only be sent once when the PendingIntent is passed. This mechanism may be easy to operate, or it may prevent the application from performing an operation multiple times.
🔐 Use FLAG_ONE_SHOT
to avoid replay attack ".
FLAG_CANCEL_CURRENT : Before registering a new PendingIntent
, cancel an PendingIntent
. This tag is used when a PendingIntent is sent to an application, and then you want to forward it to another application and update the data in it. After using FLAG_CANCEL_CURRENT
, the previous application can no longer call the send method, and the subsequent application can call it.
Receive PendingIntent
In some cases, the system or other frameworks will use PendingIntent
as the return value of the API call. A typical example is the method MediaStore.createWriteRequest()
, which was added in Android 11.
static fun MediaStore.createWriteRequest(
resolver: ContentResolver,
uris: MutableCollection<Uri>
): PendingIntent
PendingIntent
created by our application, it runs as our application, while PendingIntent
created by the system runs as the system. Specific to the usage scenario of the API here, it allows the application to open Activity
and give our application the write permission of the Uri
Summary
In this article we introduced PendingIntent
how as Intent
the Intent of the packaging system or other applications can be started in as one application at a future date the application is created.
We also introduced PendingIntent
needs to be set to immutable, and doing so will not affect the PendingIntent
object created by the application to modify itself. This can be achieved by FLAG_UPDATE_CURRENT
mark plus FLAG_IMMUTABLE
.
We also introduced the PendingIntent
that need to be done if 06110cb7599a9f is variable-to ensure that the encapsulated Intent
set to ComponentName
.
Finally, we introduced how sometimes systems or frameworks provide PendingIntent
to applications so that we can decide how and when to run them.
The security of apps has been improved in Android 12, and these updates to PendingIntent complement it well. For more information, please refer to our previous tweet " Android 12 first developer preview version arrives ".
For more information, welcome to use the Android 12 Developer Preview test your application, and tell us your experience.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。