Intent — это объект сообщения, который можно использовать для запроса действия у другого компонента приложения . Хотя намерения облегчают взаимодействие между компонентами несколькими способами, существует три основных варианта их использования:
- Начало деятельности
Activityпредставляет собой отдельный экран в приложении. Вы можете запустить новый экземплярActivity, передавIntentвstartActivity().Intentописывает запускаемую активность и содержит все необходимые данные.Если вы хотите получить результат от активности после её завершения, вызовите
startActivityForResult(). Ваша активность получает результат в виде отдельного объектаIntentв обратном вызовеonActivityResult(). Подробнее см. в руководстве по активности . - Запуск службы
Service— это компонент, выполняющий операции в фоновом режиме без пользовательского интерфейса. В Android 5.0 (API уровня 21) и более поздних версиях можно запустить службу с помощьюJobScheduler. Подробнее оJobSchedulerсм.API-reference documentation.В версиях до Android 5.0 (уровень API 21) запустить службу можно с помощью методов класса
Service. Вы можете запустить службу для выполнения однократной операции (например, загрузки файла), передавIntentвstartService().Intentописывает запускаемую службу и содержит все необходимые данные.Если служба разработана с клиент-серверным интерфейсом, вы можете подключиться к службе из другого компонента, передав
IntentвbindService(). Подробнее см. в руководстве по службам . - Проведение трансляции
Широковещательное сообщение — это сообщение, которое может получить любое приложение. Система отправляет различные широковещательные сообщения о системных событиях, например, о загрузке системы или начале зарядки устройства. Вы можете отправить широковещательное сообщение другим приложениям, передав
Intentв методsendBroadcast()илиsendOrderedBroadcast().
Далее на этой странице объясняется, как работают намерения и как их использовать. Подробнее см. в разделах «Взаимодействие с другими приложениями» и «Обмен контентом» .
Типы намерений
Существует два типа намерений:
- Явные намерения определяют, какой компонент какого приложения будет соответствовать намерению, указывая полное
ComponentName. Обычно вы используете явное намерение для запуска компонента в своём приложении, поскольку знаете имя класса активности или службы, которую хотите запустить. Например, вы можете запустить новую активность в своём приложении в ответ на действие пользователя или запустить службу для загрузки файла в фоновом режиме. - Неявные намерения не называют конкретный компонент, а вместо этого объявляют общее действие, которое необходимо выполнить, что позволяет компоненту из другого приложения выполнить его. Например, если вы хотите показать пользователю местоположение на карте, вы можете использовать неявное намерение, чтобы запросить у другого совместимого приложения отображение указанного местоположения на карте.
На рисунке 1 показано, как используется намерение при запуске действия. Когда объект Intent явно указывает конкретный компонент действия, система немедленно запускает этот компонент.

Рисунок 1. Как неявное намерение передаётся через систему для запуска другого действия: [1] Действие A создаёт Intent с описанием действия и передаёт его методу startActivity() . [2] Система Android ищет во всех приложениях фильтр намерений, соответствующий этому намерению. При обнаружении совпадения [3] система запускает соответствующее действие ( действие B ), вызывая его метод onCreate() и передавая ему Intent .
При использовании неявного намерения система Android находит подходящий компонент для запуска, сравнивая его содержимое с фильтрами намерений, объявленными в файле манифеста других приложений на устройстве. Если намерение соответствует фильтру намерений, система запускает этот компонент и передаёт ему объект Intent . Если несколько фильтров намерений совместимы, система отображает диалоговое окно, позволяющее пользователю выбрать приложение для использования.
Фильтр намерений — это выражение в файле манифеста приложения, которое определяет тип намерений, которые компонент хотел бы получать. Например, объявляя фильтр намерений для активности, вы позволяете другим приложениям напрямую запускать вашу активность с определённым типом намерения. Аналогично, если вы не объявляете фильтры намерений для активности, её можно запустить только с явным намерением.
Внимание: Чтобы обеспечить безопасность вашего приложения, всегда используйте явное намерение при запуске Service и не объявляйте фильтры намерений для своих служб. Использование неявного намерения для запуска службы представляет угрозу безопасности, поскольку невозможно точно знать, какая служба отреагирует на намерение, и пользователь не видит, какая служба запустится. Начиная с Android 5.0 (уровень API 21), система выдаёт исключение при вызове bindService() с неявным намерением.
Формирование намерения
Объект Intent несет информацию, которую система Android использует для определения того, какой компонент запустить (например, точное имя компонента или категория компонента, который должен получить намерение), а также информацию, которую компонент-получатель использует для правильного выполнения действия (например, действие, которое нужно выполнить, и данные, с которыми нужно выполнить действие).
Основная информация, содержащаяся в Intent , следующая:
- Имя компонента
- Имя компонента, который необходимо запустить.
Это необязательный, но критически важный элемент информации, который делает намерение явным , то есть оно должно быть передано только компоненту приложения, указанному в его имени. Без имени компонента намерение неявное , и система решает, какой компонент должен получить намерение, основываясь на другой информации о намерении (например, о действии, данных и категории, описанной ниже). Если вам нужно запустить определенный компонент в приложении, необходимо указать его имя.
Примечание: При запуске
Serviceвсегда указывайте имя компонента . В противном случае вы не сможете точно знать, какая служба отреагирует на намерение, и пользователь не сможет увидеть, какая служба запустится.Это поле объекта
Intentпредставляет собой объектComponentName, который можно указать, используя полное имя класса целевого компонента, включая имя пакета приложения, например,com.example.ExampleActivity. Имя компонента можно задать с помощьюsetComponent(),setClass(),setClassName()или конструктораIntent. - Действие
- Строка, которая определяет общее действие, которое необходимо выполнить (например, просмотр или выбор ).
В случае трансляции намерения это действие, которое произошло и о котором сообщается. Действие во многом определяет структуру остальной части намерения, в частности, информацию, содержащуюся в данных и дополнительных материалах.
Вы можете указать собственные действия для использования намерениями в вашем приложении (или для использования другими приложениями для вызова компонентов вашего приложения), но обычно вы указываете константы действий, определяемые классом
Intentили другими классами фреймворка. Вот некоторые распространённые действия для запуска активности:-
ACTION_VIEW - Используйте это действие в намерении с
startActivity()когда у вас есть некоторая информация, которую действие может показать пользователю, например фотография для просмотра в приложении галереи или адрес для просмотра в приложении карты. -
ACTION_SEND - Также известное как намерение поделиться , его следует использовать в намерении с
startActivity()когда у вас есть данные, которыми пользователь может поделиться через другое приложение, например, приложение электронной почты или приложение для обмена сообщениями в социальных сетях.
Дополнительные константы, определяющие общие действия, см. в справочнике по классу
Intent. Другие действия определены в других разделах фреймворка Android, например, в разделеSettingsдля действий, открывающих определённые экраны в системном приложении «Настройки».Вы можете указать действие для намерения с помощью
setAction()или с помощью конструктораIntent.Если вы определяете собственные действия, обязательно укажите имя пакета вашего приложения в качестве префикса, как показано в следующем примере:
Котлин
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Ява
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
-
- Данные
- URI (объект
Uri), ссылающийся на данные, над которыми необходимо выполнить действие, и/или тип MIME этих данных. Тип предоставляемых данных обычно определяется действием намерения. Например, если действие —ACTION_EDIT, данные должны содержать URI документа, который нужно изменить.При создании намерения часто важно указать тип данных (MIME-тип) в дополнение к URI. Например, активность, способная отображать изображения, вероятно, не сможет воспроизвести аудиофайл, даже если форматы URI будут схожими. Указание MIME-типа данных помогает системе Android найти оптимальный компонент для обработки намерения. Однако иногда MIME-тип можно определить по URI, особенно если данные представляют собой URI
content::. URIcontent:указывает, что данные расположены на устройстве и контролируютсяContentProvider, что делает тип MIME данных видимым для системы.Чтобы задать только URI данных, вызовите
setData(). Чтобы задать только тип MIME, вызовитеsetType(). При необходимости можно явно задать оба типа с помощьюsetDataAndType().Внимание: Если вы хотите задать и URI, и MIME-тип, не вызывайте
setData()иsetType()поскольку они обнуляют значение друг друга. Всегда используйтеsetDataAndType()для задания и URI, и MIME-типа. - Категория
- Строка, содержащая дополнительную информацию о типе компонента, который должен обрабатывать намерение. В намерение можно добавить любое количество описаний категорий, но для большинства намерений категория не требуется. Вот некоторые распространённые категории:
-
CATEGORY_BROWSABLE - Целевая активность позволяет веб-браузеру запускать ее для отображения данных, на которые ссылается ссылка, например изображения или сообщения электронной почты.
-
CATEGORY_LAUNCHER - Действие является начальным действием задачи и отображается в панели запуска приложений системы.
Полный список категорий см. в описании класса
Intent.Вы можете указать категорию с помощью
addCategory(). -
Перечисленные выше свойства (имя компонента, действие, данные и категория) представляют собой определяющие характеристики намерения. Считывая эти свойства, система Android может определить, какой компонент приложения следует запустить. Однако намерение может содержать дополнительную информацию, которая не влияет на то, как оно преобразуется в компонент приложения. Намерение также может предоставлять следующую информацию:
- Дополнительно
- Пары «ключ-значение», содержащие дополнительную информацию, необходимую для выполнения запрошенного действия. Подобно тому, как некоторые действия используют определённые типы URI данных, некоторые действия также используют определённые дополнительные данные.
Вы можете добавлять дополнительные данные с помощью различных методов
putExtra(), каждый из которых принимает два параметра: имя ключа и значение. Вы также можете создать объектBundleсо всеми дополнительными данными, а затем вставить этотBundleвIntentс помощьюputExtras().Например, при создании намерения отправить электронное письмо с помощью
ACTION_SENDвы можете указать получателя с помощью ключаEXTRA_EMAILи указать тему с помощью ключаEXTRA_SUBJECT.Класс
Intentопределяет множество константEXTRA_*для стандартизированных типов данных. Если вам нужно объявить собственные дополнительные ключи (для намерений, которые получает ваше приложение), обязательно укажите имя пакета вашего приложения в качестве префикса, как показано в следующем примере:Котлин
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Ява
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Внимание : не используйте данные
ParcelableилиSerializableпри отправке намерения, которое, как вы ожидаете, получит другое приложение. Если приложение пытается получить доступ к данным в объектеBundle, но не имеет доступа к классу Parceled или serializable, система вызывает исключениеRuntimeException. - Флаги
- Флаги определяются в классе
Intentи служат метаданными для намерения. Флаги могут указывать системе Android, как запускать активность (например, к какой задаче она должна относиться) и как с ней обращаться после запуска (например, находится ли она в списке недавних активностей).Для получения дополнительной информации см. метод
setFlags().
Пример явного намерения
Явное намерение — это намерение, которое вы используете для запуска определённого компонента приложения, например, определённой активности или службы. Чтобы создать явное намерение, определите имя компонента для объекта Intent ; все остальные свойства намерения необязательны.
Например, если вы создали в своем приложении службу под названием DownloadService , предназначенную для загрузки файла из Интернета, вы можете запустить ее с помощью следующего кода:
Котлин
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse(fileUrl) } startService(downloadIntent)
Ява
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
Конструктор Intent(Context, Class) предоставляет приложению Context и компоненту объект Class . Таким образом, это намерение явно запускает класс DownloadService в приложении.
Дополнительную информацию о создании и запуске службы см. в руководстве «Службы» .
Пример неявного намерения
Неявное намерение определяет действие, которое может вызвать любое приложение на устройстве, способное выполнить это действие. Использование неявного намерения полезно, когда ваше приложение не может выполнить действие, но другие приложения, вероятно, могут, и вы хотите, чтобы пользователь мог выбрать, какое приложение использовать.
Например, если у вас есть контент, которым пользователь хочет поделиться с другими людьми, создайте намерение с действием ACTION_SEND и добавьте дополнительные элементы, указывающие, каким контентом нужно поделиться. При вызове startActivity() с этим намерением пользователь может выбрать приложение, через которое он хочет поделиться контентом.
Котлин
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Ява
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
При вызове startActivity() система проверяет все установленные приложения, чтобы определить, какие из них могут обработать этот тип намерения (намерение с действием ACTION_SEND , содержащее данные типа «text/plain»). Если есть только одно приложение, способное обработать намерение, оно немедленно открывается и получает это намерение. Если другие приложения не могут его обработать, ваше приложение может перехватить возникающее исключение ActivityNotFoundException . Если несколько действий принимают намерение, система отображает диалоговое окно, подобное показанному на рисунке 2, чтобы пользователь мог выбрать, какое приложение использовать.
Более подробная информация о запуске других приложений также приведена в руководстве по переключению пользователя в другое приложение .

Рисунок 2. Диалоговое окно выбора.
Принудительный выбор приложения
Если на ваше неявное намерение реагирует несколько приложений, пользователь может выбрать, какое из них использовать, и сделать его приложением по умолчанию для выполнения действия. Возможность выбора приложения по умолчанию полезна при выполнении действия, для которого пользователь, вероятно, захочет каждый раз использовать одно и то же приложение, например, при открытии веб-страницы (пользователи часто предпочитают использовать только один веб-браузер).
Однако, если на намерение могут реагировать несколько приложений, и пользователь может каждый раз использовать другое приложение, следует явно отображать диалоговое окно выбора. В этом диалоговом окне пользователю предлагается выбрать приложение для выполнения действия (пользователь не может выбрать приложение по умолчанию). Например, когда ваше приложение выполняет команду «Поделиться» с помощью действия ACTION_SEND , пользователи могут захотеть поделиться информацией через другое приложение в зависимости от текущей ситуации, поэтому всегда следует использовать диалоговое окно выбора, как показано на рисунке 2.
Чтобы отобразить окно выбора, создайте Intent с помощью createChooser() и передайте его методу startActivity() , как показано в следующем примере. В этом примере отображается диалоговое окно со списком приложений, которые отвечают на намерение, переданное методу createChooser() , и используется предоставленный текст в качестве заголовка диалогового окна.
Котлин
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Ява
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
Обнаружение небезопасных намеренных запусков
Ваше приложение может запускать намерения для навигации между компонентами внутри приложения или для выполнения действия от имени другого приложения. Для повышения безопасности платформы в Android 12 (уровень API 31) и более поздних версиях реализована функция отладки, которая предупреждает вас, если приложение выполняет небезопасный запуск намерения. Например, ваше приложение может выполнить небезопасный запуск вложенного намерения , которое передаётся как дополнительное в другое намерение.
Если ваше приложение выполняет оба следующих действия, система обнаруживает небезопасный запуск намерения и происходит нарушение StrictMode :
- Ваше приложение извлекает вложенное намерение из дополнений доставленного намерения.
- Ваше приложение немедленно запускает компонент приложения , используя это вложенное намерение, например, передавая намерение в
startActivity(),startService()илиbindService().
Более подробную информацию о том, как определить эту ситуацию и внести изменения в свое приложение, можно найти в публикации блога об Android Nesting Intents на Medium.
Проверка на наличие небезопасных намеренных запусков
Чтобы проверить наличие небезопасных запусков намерений в вашем приложении, вызовите detectUnsafeIntentLaunch() при настройке VmPolicy , как показано в следующем фрагменте кода. Если ваше приложение обнаруживает нарушение StrictMode, вы можете остановить его выполнение, чтобы защитить потенциально конфиденциальную информацию.
Котлин
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Ява
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
Используйте намерения более ответственно
Чтобы свести к минимуму вероятность небезопасного запуска намерения и нарушения StrictMode, следуйте этим рекомендациям.
Копируйте только необходимые дополнения из намерений и выполняйте необходимую очистку и валидацию. Ваше приложение может копировать дополнения из одного намерения в другое, используемое для запуска нового компонента. Это происходит, когда ваше приложение вызывает putExtras(Intent) или putExtras(Bundle) . Если ваше приложение выполняет одну из этих операций, копируйте только те дополнения, которые ожидает принимающий компонент. Если другое намерение (получающее копию) запускает компонент, который не экспортируется , очистьте и проверьте дополнения перед их копированием в намерение, запускающее этот компонент.
Не экспортируйте компоненты приложения без необходимости. Например, если вы планируете запустить компонент приложения с помощью внутреннего вложенного намерения, установите для атрибута android:exported этого компонента значение false .
Используйте PendingIntent вместо вложенного Intent. Таким образом, когда другое приложение распаковывает PendingIntent содержащего его Intent , оно может запустить PendingIntent используя идентификатор вашего приложения. Такая конфигурация позволяет другому приложению безопасно запускать любой компонент вашего приложения, включая неэкспортированные.
Диаграмма на рисунке 2 показывает, как система передает управление от вашего (клиентского) приложения другому (сервисному) приложению и обратно вашему приложению:
- Ваше приложение создаёт намерение, которое вызывает действие в другом приложении. В это намерение вы добавляете объект
PendingIntentв качестве дополнения. Это отложенное намерение вызывает компонент в вашем приложении; этот компонент не экспортируется. - Получив намерение вашего приложения, другое приложение извлекает вложенный объект
PendingIntent. - Другое приложение вызывает метод
send()для объектаPendingIntent. - После передачи управления обратно вашему приложению система вызывает ожидающее намерение, используя контекст вашего приложения.
Рисунок 2. Схема взаимодействия приложений при использовании вложенного ожидающего намерения.
Получение неявного намерения
Чтобы указать, какие неявные намерения может получать ваше приложение, объявите один или несколько фильтров намерений для каждого компонента приложения с помощью элемента <intent-filter> в файле манифеста . Каждый фильтр намерений определяет тип принимаемых намерений на основе действия, данных и категории намерения. Система передаёт неявное намерение компоненту приложения только в том случае, если оно может пройти через один из фильтров намерений.
Примечание: Явное намерение всегда доставляется своей цели, независимо от любых фильтров намерений, объявленных компонентом.
Компонент приложения должен объявлять отдельные фильтры для каждой уникальной задачи, которую он может выполнять. Например, одна активность в приложении галереи изображений может иметь два фильтра: один для просмотра изображения, а другой — для редактирования. При запуске активность проверяет Intent и решает, как себя вести на основе информации в Intent (например, отображать элементы управления редактором или нет).
Каждый фильтр намерений определяется элементом <intent-filter> в файле манифеста приложения, вложенным в соответствующий компонент приложения (например, элемент <activity> ).
В каждом компоненте приложения, включающем элемент <intent-filter> , явно задайте значение атрибута android:exported . Этот атрибут указывает, доступен ли компонент приложения другим приложениям. В некоторых ситуациях, например, для действий, фильтры намерений которых включают категорию LAUNCHER , полезно установить этот атрибут в true . В противном случае безопаснее установить этот атрибут в false .
Предупреждение: если действие, служба или приемник вещания в вашем приложении используют фильтры намерений и явно не задают значение android:exported , ваше приложение не может быть установлено на устройстве под управлением Android 12 или выше.
Внутри <intent-filter> вы можете указать тип принимаемых намерений, используя один или несколько из этих трех элементов:
-
<action> - Объявляет действие намерения принятым в атрибуте
name. Значение должно быть строковым значением действия, а не константой класса. -
<data> - Объявляет тип принимаемых данных, используя один или несколько атрибутов, которые указывают различные аспекты URI данных (
scheme,host,port,path) и тип MIME. -
<category> - Объявляет принятую категорию намерения в атрибуте
name. Значение должно быть строковым значением действия, а не константой класса.Примечание: Для получения неявных намерений необходимо включить категорию
CATEGORY_DEFAULTв фильтр намерений. МетодыstartActivity()иstartActivityForResult()обрабатывают все намерения так, как будто они объявляют категориюCATEGORY_DEFAULT. Если эта категория не объявлена в фильтре намерений, никакие неявные намерения не будут преобразованы в вашу активность.
Например, вот объявление действия с фильтром намерений для получения намерения ACTION_SEND , когда тип данных — текст:
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
Вы можете создать фильтр, включающий более одного экземпляра <action> , <data> или <category> . В этом случае необходимо убедиться, что компонент может обрабатывать любые комбинации этих элементов фильтра.
Если вы хотите обрабатывать несколько видов намерений, но только в определенных сочетаниях действий, данных и типов категорий, вам необходимо создать несколько фильтров намерений.
Неявное намерение проверяется на соответствие фильтру путём сравнения намерения с каждым из трёх элементов. Для передачи компоненту намерение должно пройти все три проверки. Если оно не соответствует хотя бы одной из них, система Android не доставит его компоненту. Однако, поскольку компонент может иметь несколько фильтров намерений, намерение, не прошедшее через один из фильтров компонента, может пройти через другой фильтр. Подробнее о том, как система разрешает намерения, см. в разделе ниже, посвящённом разрешению намерений .
Внимание: использование фильтра намерений не является безопасным способом предотвращения запуска ваших компонентов другими приложениями. Хотя фильтры намерений ограничивают компонент реагированием только на определённые виды неявных намерений, другое приложение потенциально может запустить ваш компонент, используя явное намерение, если разработчик определил имена компонентов. Если важно, чтобы только ваше приложение могло запускать один из ваших компонентов, не объявляйте фильтры намерений в манифесте. Вместо этого установите для exported компонента значение "false" .
Аналогично, чтобы избежать непреднамеренного запуска Service другого приложения, всегда используйте явное намерение для запуска собственной службы.
Примечание: Для всех действий необходимо объявить фильтры намерений в файле манифеста. Однако фильтры для приёмников широковещательных сообщений можно регистрировать динамически, вызвав метод registerReceiver() . Затем можно отменить регистрацию приёмника с помощью unregisterReceiver() . Это позволит вашему приложению прослушивать определённые широковещательные сообщения только в течение определённого периода времени, пока приложение работает.
Примеры фильтров
Чтобы продемонстрировать некоторые особенности поведения фильтра намерений, приведем пример из файла манифеста приложения для обмена сообщениями в социальных сетях:
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
Первая активность, MainActivity , является основной точкой входа приложения — активностью, которая открывается, когда пользователь первоначально запускает приложение с помощью значка запуска:
- Действие
ACTION_MAINуказывает, что это основная точка входа, и не ожидает никаких данных о намерениях. - Категория
CATEGORY_LAUNCHERуказывает, что значок этого действия должен быть помещен в системную панель запуска приложений. Если элемент<activity>не указывает значок с помощьюicon, система использует значок из элемента<application>.
Эти два действия должны быть объединены вместе, чтобы действие появилось в панели запуска приложений.
Второе действие, ShareActivity , предназначено для упрощения обмена текстовым и медиаконтентом. Хотя пользователи могут перейти к этому действию, перейдя к нему из MainActivity , они также могут перейти к ShareActivity непосредственно из другого приложения, которое выдаёт неявное намерение, соответствующее одному из двух фильтров намерений.
Примечание: тип MIME application/vnd.google.panorama360+jpg — это специальный тип данных, который определяет панорамные фотографии, с которыми можно работать с помощью API панорам Google .
Сопоставьте намерения с фильтрами намерений других приложений
Если другое приложение предназначено для Android 13 (уровень API 33) или выше, оно сможет обработать намерение вашего приложения только в том случае, если оно соответствует действиям и категориям элемента <intent-filter> в этом другом приложении. Если система не находит совпадений, она генерирует исключение ActivityNotFoundException . Отправляющее приложение должно обработать это исключение.
Аналогично, если вы обновляете приложение для Android 13 или более поздней версии, все намерения, исходящие от внешних приложений, доставляются экспортированному компоненту вашего приложения только в том случае, если это намерение соответствует действиям и категориям элемента <intent-filter> , объявленного вашим приложением. Это происходит независимо от целевой версии SDK отправляющего приложения.
В следующих случаях сопоставление намерений не применяется:
- Намерения, отправляемые компонентам, которые не объявляют никаких фильтров намерений.
- Намерения, возникающие в одном и том же приложении.
- Намерения, исходящие из системы, то есть намерения, отправляемые с «системного UID» (uid=1000). Системные приложения включают
system_serverи приложения, которые устанавливаютandroid:sharedUserIdв значениеandroid.uid.system. - Намерения, исходящие из корня.
Узнайте больше о сопоставлении намерений .
Использование ожидающего намерения
Объект PendingIntent — это обёртка вокруг объекта Intent . Основное назначение PendingIntent — предоставить стороннему приложению разрешение использовать содержащийся в нём Intent как если бы он выполнялся из собственного процесса вашего приложения.
Основные варианты использования отложенного намерения включают следующее:
- Объявление намерения, которое будет выполнено, когда пользователь выполнит действие с вашим уведомлением (
NotificationManagerсистемы Android выполняетIntent). - Объявление намерения, которое будет выполнено, когда пользователь выполняет действие с вашим виджетом приложения (приложение на главном экране выполняет
Intent). - Объявление намерения, которое будет выполнено в указанное время в будущем (
AlarmManagerсистемы Android выполняетIntent).
Так же, как каждый объект Intent предназначен для обработки определённым типом компонента приложения ( Activity , Service или BroadcastReceiver ), PendingIntent также должен создаваться с теми же соображениями. При использовании отложенного намерения приложение не выполняет его с помощью вызова, например, startActivity() . Вместо этого необходимо объявить предполагаемый тип компонента при создании PendingIntent , вызвав соответствующий метод-создателя:
-
PendingIntent.getActivity()дляIntent, который запускаетActivity. -
PendingIntent.getService()дляIntent, который запускаетService. -
PendingIntent.getBroadcast()дляIntent, который запускаетBroadcastReceiver.
Если ваше приложение не получает ожидающие намерения от других приложений, то приведенные выше методы создания PendingIntent , вероятно, единственные методы PendingIntent которые вам когда-либо понадобятся.
Каждый метод принимает текущий Context приложения, Intent которое вы хотите обернуть, и один или несколько флагов, которые указывают, как должно использоваться намерение (например, можно ли использовать намерение более одного раза).
Дополнительную информацию об использовании ожидающих намерений см. в документации по каждому из соответствующих вариантов использования, например, в руководствах по API уведомлений и виджетов приложений .
Укажите изменчивость
Если ваше приложение предназначено для Android 12 или более поздней версии, необходимо указать изменяемость каждого создаваемого вами объекта PendingIntent . Чтобы объявить объект PendingIntent изменяемым или неизменяемым, используйте флаг PendingIntent.FLAG_MUTABLE или PendingIntent.FLAG_IMMUTABLE соответственно.
Если ваше приложение попытается создать объект PendingIntent , не установив ни одного флага изменяемости, система выдаст исключение IllegalArgumentException , а в Logcat появится следующее сообщение:
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
Создавайте неизменяемые отложенные намерения, когда это возможно
В большинстве случаев ваше приложение должно создавать неизменяемые объекты PendingIntent , как показано в следующем фрагменте кода. Если объект PendingIntent неизменяем, другие приложения не смогут изменять намерение, чтобы скорректировать результат его вызова.
Котлин
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Ява
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
Однако в некоторых случаях использования вместо этого требуются изменяемые объекты PendingIntent :
- Поддержка действий прямого ответа в уведомлениях . Прямой ответ требует изменения данных клипа в объекте PendingIntent, связанном с ответом. Обычно это изменение запрашивается путем передачи
FILL_IN_CLIP_DATAв качестве флага методуfillIn(). - Связывание уведомлений с фреймворком Android Auto с использованием экземпляров
CarAppExtender. - Размещение обсуждений в пузырьках с помощью экземпляров
PendingIntent. Изменяемый объектPendingIntentпозволяет системе применять правильные флаги, такие какFLAG_ACTIVITY_MULTIPLE_TASKиFLAG_ACTIVITY_NEW_DOCUMENT. - Запрос информации о местоположении устройства с помощью вызова
requestLocationUpdates()или аналогичных API. Изменяемый объектPendingIntentпозволяет системе добавлять дополнительные намерения, представляющие события жизненного цикла местоположения. К таким событиям относятся изменение местоположения и доступность поставщика. - Планирование будильников с помощью
AlarmManager. Изменяемый объектPendingIntentпозволяет системе добавлять дополнительное значениеEXTRA_ALARM_COUNTк интенту. Это дополнительное значение представляет количество срабатываний повторяющегося будильника. Благодаря этому дополнительному значению интент может точно уведомлять приложение о том, срабатывал ли повторяющийся будильник несколько раз, например, когда устройство находилось в спящем режиме.
Если ваше приложение создаёт изменяемый объект PendingIntent , настоятельно рекомендуется использовать явное намерение и заполнить ComponentName . Таким образом, всякий раз, когда другое приложение вызывает PendingIntent и передаёт управление вашему приложению, в вашем приложении всегда запускается тот же компонент.
Используйте явные намерения в ожидаемых намерениях
Чтобы лучше определить, как другие приложения могут использовать ожидаемые намерения вашего приложения, всегда заключайте ожидаемое намерение в явное намерение . Чтобы следовать этой рекомендации, выполните следующие действия:
- Проверьте, что поля действия, пакета и компонента базового намерения установлены.
Используйте
FLAG_IMMUTABLE, добавленный в Android 6.0 (уровень API 23), для создания ожидающих намерений. Этот флаг запрещает приложениям, получающимPendingIntentзаполнять незаполненные свойства. ЕслиminSdkVersionвашего приложения равен22или ниже, вы можете обеспечить безопасность и совместимость одновременно, используя следующий код:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
Разрешение намерений
Когда система получает неявное намерение начать действие, она ищет наилучшее действие для этого намерения, сравнивая его с фильтрами намерений на основе трех аспектов:
- Действие.
- Данные (как URI, так и тип данных).
- Категория.
В следующих разделах описывается, как намерения сопоставляются с соответствующими компонентами согласно объявлению фильтра намерений в файле манифеста приложения.
Тест действия
Чтобы указать принятые действия намерения, фильтр намерений может объявить ноль или более элементов <action> , как показано в следующем примере:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
Чтобы пройти этот фильтр, действие, указанное в Intent должно соответствовать одному из действий, перечисленных в фильтре.
Если фильтр не содержит никаких действий, намерению не с чем сопоставляться, поэтому все намерения не проходят проверку. Однако, если Intent не указано действие, оно проходит проверку, если фильтр содержит хотя бы одно действие.
Тест категории
Чтобы указать принятые категории намерений, фильтр намерений может объявить ноль или более элементов <category> , как показано в следующем примере:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
Чтобы намерение прошло тест на категорию, каждая категория в Intent должна соответствовать категории в фильтре. Обратное условие необязательно — фильтр намерения может объявить больше категорий, чем указано в Intent и Intent всё равно будет успешно выполнено. Таким образом, намерение без категорий всегда проходит этот тест, независимо от того, какие категории объявлены в фильтре.
Примечание: Android автоматически применяет категорию CATEGORY_DEFAULT ко всем неявным намерениям, передаваемым в startActivity() и startActivityForResult() . Чтобы ваша активность получала неявные намерения, она должна включать категорию "android.intent.category.DEFAULT" в своих фильтрах намерений, как показано в предыдущем примере <intent-filter> .
Тест данных
Чтобы указать принятые данные намерения, фильтр намерений может объявить ноль или более элементов <data> , как показано в следующем примере:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
Каждый элемент <data> может определять структуру URI и тип данных (MIME-тип носителя). Каждая часть URI представляет собой отдельный атрибут: scheme , host , port и path :
<scheme>://<host>:<port>/<path>
В следующем примере показаны возможные значения этих атрибутов:
content://com.example.project:200/folder/subfolder/etc
В этом URI схема — content , хост — com.example.project , порт — 200 , а путь — folder/subfolder/etc .
Каждый из этих атрибутов является необязательным в элементе <data> , но существуют линейные зависимости:
- Если схема не указана, хост игнорируется.
- Если хост не указан, порт игнорируется.
- If both the scheme and host are not specified, the path is ignored.
When the URI in an intent is compared to a URI specification in a filter, it's compared only to the parts of the URI included in the filter. For example:
- If a filter specifies only a scheme, all URIs with that scheme match the filter.
- If a filter specifies a scheme and an authority but no path, all URIs with the same scheme and authority pass the filter, regardless of their paths.
- If a filter specifies a scheme, an authority, and a path, only URIs with the same scheme, authority, and path pass the filter.
Note: A path specification can contain a wildcard asterisk (*) to require only a partial match of the path name.
The data test compares both the URI and the MIME type in the intent to a URI and MIME type specified in the filter. The rules are as follows:
- An intent that contains neither a URI nor a MIME type passes the test only if the filter does not specify any URIs or MIME types.
- An intent that contains a URI but no MIME type (neither explicit nor inferable from the URI) passes the test only if its URI matches the filter's URI format and the filter likewise does not specify a MIME type.
- An intent that contains a MIME type but not a URI passes the test only if the filter lists the same MIME type and does not specify a URI format.
- An intent that contains both a URI and a MIME type (either explicit or inferable from the URI) passes the MIME type part of the test only if that type matches a type listed in the filter. It passes the URI part of the test either if its URI matches a URI in the filter or if it has a
content:orfile:URI and the filter does not specify a URI. In other words, a component is presumed to supportcontent:andfile:data if its filter lists only a MIME type.
Note: If an intent specifies a URI or MIME type, the data test will fail if there are no <data> elements in the <intent-filter> .
This last rule, rule (d), reflects the expectation that components are able to get local data from a file or content provider. Therefore, their filters can list just a data type and don't need to explicitly name the content: and file: schemes. The following example shows a typical case in which a <data> element tells Android that the component can get image data from a content provider and display it:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
Filters that specify a data type but not a URI are perhaps the most common because most available data is dispensed by content providers.
Another common configuration is a filter with a scheme and a data type. For example, a <data> element like the following tells Android that the component can retrieve video data from the network in order to perform the action:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
Сопоставление намерений
Intents are matched against intent filters not only to discover a target component to activate, but also to discover something about the set of components on the device. For example, the Home app populates the app launcher by finding all the activities with intent filters that specify the ACTION_MAIN action and CATEGORY_LAUNCHER category. A match is only successful if the actions and categories in the Intent match against the filter, as described in the documentation for the IntentFilter class.
Your application can use intent matching in a manner similar to what the Home app does. The PackageManager has a set of query...() methods that return all components that can accept a particular intent and a similar series of resolve...() methods that determine the best component to respond to an intent. For example, queryIntentActivities() returns a list of all activities that can perform the intent passed as an argument, and queryIntentServices() returns a similar list of services. Neither method activates the components; they just list the ones that can respond. There's a similar method, queryBroadcastReceivers() , for broadcast receivers.