PendingIntent
PendingIntent — это специальный объект в операционной системе Android, предоставляющий механизм для отложенного выполнения действия от имени приложения, даже если само приложение в данный момент неактивно или не запущено. По сути, это токен (маркер), который передаётся другому компоненту системы (например, системному менеджеру уведомлений, будильнику, другому приложению) и позволяет этому компоненту в будущем выполнить заранее заданное действие — запустить Activity, Service, BroadcastReceiver или отправить Intent — с теми же правами и разрешениями, что и у исходного приложения.
Принцип работы
Основная идея PendingIntent заключается в том, что приложение создаёт «заготовку» намерения (Intent), упаковывает её в объект PendingIntent и передаёт другому компоненту системы. Этот компонент, когда наступает подходящий момент (например, пользователь нажимает на уведомление, срабатывает будильник, поступает Push-уведомление), вызывает метод send() у объекта PendingIntent, что приводит к выполнению исходного Intent. При этом система Android при выполнении восстанавливает контекст исходного приложения, включая его идентификатор (UID) и разрешения, что гарантирует, что действие выполняется от имени создателя, а не вызывающего компонента.
Типы PendingIntent
В зависимости от того, какое действие должно быть выполнено, различают несколько типов PendingIntent, определяемых флагами, передаваемыми при создании:
- FLAG_ONE_SHOT: PendingIntent может быть выполнен только один раз. После вызова
send()он становится недействительным. Используется для одноразовых действий, например, для реакции на нажатие кнопки в уведомлении, которое после нажатия должно исчезнуть. - FLAG_NO_CREATE: Если PendingIntent с данным Intent уже существует, он возвращается, но не создаётся новый. Если не существует — возвращается
null. Используется для проверки существования PendingIntent без его создания. - FLAG_CANCEL_CURRENT: Если PendingIntent с данным Intent уже существует, он отменяется (становится недействительным) и создаётся новый. Полезно для обновления данных в уведомлениях, когда старый Intent должен быть заменён.
- FLAG_UPDATE_CURRENT: Если PendingIntent с данным Intent уже существует, он не отменяется, а обновляется: его внутренний Intent заменяется новым, но сам объект PendingIntent остаётся тем же. Это наиболее распространённый флаг для обновления уведомлений, так как позволяет сохранить привязку к существующему уведомлению.
- FLAG_IMMUTABLE (добавлен в Android 6.0, API 23): PendingIntent является неизменяемым — его внутренний Intent не может быть изменён другими приложениями. Рекомендуется для всех новых приложений, так как повышает безопасность, предотвращая атаки типа «замена Intent» (Intent redirection).
- FLAG_MUTABLE (добавлен в Android 12, API 31): PendingIntent является изменяемым — его внутренний Intent может быть модифицирован вызывающим компонентом. Используется только в тех случаях, когда это необходимо по функциональности (например, для заполнения данных в Intent сторонним приложением).
Создание PendingIntent
Для создания PendingIntent используются статические методы классов PendingIntent, которые принимают контекст, запрос (request code), сам Intent и флаги:
PendingIntent.getActivity()— для запуска Activity.PendingIntent.getService()— для запуска Service.PendingIntent.getBroadcast()— для отправки BroadcastReceiver.
Пример создания PendingIntent для запуска Activity при нажатии на уведомление:
``java Intent intent = new Intent(context, TargetActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); ``
Применение
PendingIntent широко используется в Android для реализации различных сценариев взаимодействия между компонентами системы:
- Уведомления (Notifications): Наиболее распространённое применение. При создании уведомления через
NotificationCompat.BuilderилиNotification.Builderобъект PendingIntent передаётся в методsetContentIntent(). При нажатии на уведомление система вызывает этот PendingIntent, что приводит к открытию указанного Activity. Также PendingIntent используется для действий на кнопках уведомлений (addAction()). - Будильники (AlarmManager): При установке будильника через
AlarmManager.set()передаётся PendingIntent, который будет выполнен в заданное время. Это может быть запуск Service, BroadcastReceiver или Activity. - Виджеты (AppWidgets): При нажатии на элемент виджета (например, кнопку) система вызывает PendingIntent, который был установлен для этого элемента через
RemoteViews.setOnClickPendingIntent(). - Push-уведомления (Firebase Cloud Messaging): При получении Push-уведомления, которое содержит данные для открытия определённого экрана, приложение создаёт PendingIntent и передаёт его в системное уведомление.
- Запуск приложений из других приложений: Приложение может передать PendingIntent другому приложению, чтобы то выполнило действие от имени первого. Например, приложение-календарь может передать PendingIntent для открытия события, а приложение-напоминание — для его выполнения.
- Системные вызовы: Некоторые системные сервисы, такие как
NotificationManager,AlarmManager,AppWidgetManager, принимают PendingIntent для выполнения действий в будущем.
Безопасность
Использование PendingIntent связано с рядом рисков безопасности, особенно в многопользовательской среде Android. Основные угрозы:
- Перехват Intent (Intent hijacking): Если PendingIntent является изменяемым (
FLAG_MUTABLE), злоумышленник может изменить его внутренний Intent, перенаправив действие на свой компонент. Это может привести к утечке данных или выполнению несанкционированных действий. Для защиты рекомендуется использоватьFLAG_IMMUTABLEво всех случаях, кроме тех, где изменяемость необходима. - Замена PendingIntent (PendingIntent replacement): Если приложение создаёт PendingIntent с одинаковым Intent и request code, но с флагом
FLAG_CANCEL_CURRENT, старый PendingIntent отменяется, что может нарушить работу других компонентов, ожидающих его выполнения. - Утечка контекста: PendingIntent сохраняет ссылку на контекст приложения, что может привести к утечке памяти, если объект PendingIntent не освобождается своевременно.
Рекомендации по безопасному использованию:
- Всегда указывать
FLAG_IMMUTABLEдля PendingIntent, если не требуется изменяемость. - Использовать уникальные request code для разных PendingIntent, чтобы избежать конфликтов.
- Не передавать PendingIntent ненадёжным приложениям без необходимости.
- Проверять, что Intent, который будет выполнен, не содержит конфиденциальных данных, которые могут быть перехвачены.
История версий
- Android 1.0 (API 1): PendingIntent представлен как часть базового фреймворка.
- Android 6.0 (API 23): Введён флаг
FLAG_IMMUTABLE, но его использование стало обязательным только с Android 12. - Android 12 (API 31): Введён флаг
FLAG_MUTABLE. При создании PendingIntent без указанияFLAG_IMMUTABLEилиFLAG_MUTABLEсистема выдаёт предупреждение, а начиная с Android 15 (API 35) такое создание вызывает исключениеIllegalArgumentException. Это сделано для повышения безопасности.
Источники
- Android Developers. PendingIntent. Официальная документация.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →