В этом документе представлено несколько распространенных вариантов использования, в которых приложение взаимодействует с другие приложения. В каждом разделе рассказывается, как обеспечить работу функций приложения при ограниченной видимости пакетов. Это необходимо учитывать, если ваше приложение предназначено для Android 11 (уровень API 30) или более поздней версии.
Если приложение, предназначенное для Android 11 или более поздней версии, использует намерение для запуска действия в другом приложении, самый простой способ – вызвать намерение и обработать исключение ActivityNotFoundException, если приложение недоступно.
Если в вашем приложении есть элементы, которые зависят от того, будет ли вызов startActivity() успешным (например, элементы интерфейса), добавьте элемент в элемент <queries> манифеста приложения. Обычно это элемент <intent>.
Открыть URL
В этом разделе описаны различные способы открытия URL в приложении, предназначенном для Android 11 или более поздней версии.
Открывать URL в браузере или другом приложении
Чтобы открыть URL, используйте намерение, содержащее действие ACTION_VIEW, как описано в руководстве по загрузке веб-URL. После вызова startActivity() с использованием этого намерения произойдет одно из следующих событий:
- Веб-страница откроется в браузере.
- URL открывается в приложении, которое поддерживает его в качестве ссылки на контент.
- Появится диалоговое окно, в котором пользователь сможет выбрать приложение для открытия URL.
Ошибка
ActivityNotFoundExceptionвозникает, если на устройстве не установлено приложение, которое может открыть URL. (Это необычно.)Рекомендуем настроить приложение так, чтобы оно перехватывало и обрабатывало ошибку
ActivityNotFoundException, если она возникает.
Поскольку метод startActivity() не требует видимости пакета для запуска действия другого приложения, вам не нужно добавлять элемент <queries> в манифест приложения или вносить изменения в существующий элемент <queries>. Это относится как к явным, так и к неявным намерениям, которые открывают URL.
Проверьте, доступен ли браузер
В некоторых случаях перед попыткой открыть URL-адрес приложение может проверить, доступен ли на устройстве хотя бы один браузер или является ли определенный браузер браузером по умолчанию. В таких случаях добавьте в манифест элемент <intent> как часть элемента <queries>:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent>
Если вы вызываете queryIntentActivities() и передаете веб-намерение в качестве аргумента, возвращаемый список в некоторых случаях включает доступные браузеры. В списке не будет браузеров, если пользователь настроил открытие URL в другом приложении по умолчанию.
Открывать URL в специальных вкладках
Специальные вкладки позволяют настраивать внешний вид браузера. Вы можете открыть URL в пользовательской вкладке, не добавляя и не изменяя элемент <queries> в манифесте приложения.
Однако вы можете проверить, есть ли на устройстве браузер, поддерживающий настраиваемые вкладки, или выбрать определенный браузер для запуска с настраиваемыми вкладками с помощью CustomTabsClient.getPackageName().
В таких случаях добавьте в манифест элемент <intent> как часть элемента <queries>:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.support.customtabs.action.CustomTabsService" /> </intent>
Разрешить приложениям, не являющимся браузерами, обрабатывать URL
Даже если ваше приложение может открывать URL-адреса с помощью пользовательских вкладок, рекомендуется по возможности разрешить открывать URL-адреса приложению, не являющемуся браузером. Чтобы реализовать эту возможность в своем приложении, попробуйте вызвать startActivity(), используя намерение, которое устанавливает флаг намерения FLAG_ACTIVITY_REQUIRE_NON_BROWSER. Если система выдает ошибку ActivityNotFoundException, приложение может открыть URL в специальной вкладке.
Если намерение включает этот флаг, вызов startActivity() приводит к возникновению ошибки ActivityNotFoundException при любом из следующих условий:
- Вызов напрямую запустил бы приложение браузера.
- В результате вызова пользователю было бы показано диалоговое окно для устранения неоднозначности, в котором в качестве вариантов предлагались бы только браузеры.
В приведенном ниже фрагменте кода показано, как обновить логику, чтобы использовать флаг намерения FLAG_ACTIVITY_REQUIRE_NON_BROWSER.
Kotlin
try { val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { // The URL should either launch directly in a non-browser app (if it's // the default) or in the disambiguation dialog. addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER } startActivity(intent) } catch (e: ActivityNotFoundException) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url) }
Java
try { Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); // The URL should either launch directly in a non-browser app (if it's the // default) or in the disambiguation dialog. intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER); startActivity(intent); } catch (ActivityNotFoundException e) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url); }
Как избежать появления диалогового окна для уточнения
Если вы хотите, чтобы при открытии URL не появлялось диалоговое окно выбора приложения, а URL обрабатывался в вашем приложении, используйте намерение с флагом FLAG_ACTIVITY_REQUIRE_DEFAULT.
Если намерение содержит этот флаг, вызов startActivity() приводит к возникновению ошибки ActivityNotFoundException, когда вызов должен был показать пользователю диалоговое окно устранения неоднозначности.
Если намерение содержит и этот флаг, и флаг FLAG_ACTIVITY_REQUIRE_NON_BROWSER, вызов startActivity() приведет к возникновению ошибки ActivityNotFoundException при любом из следующих условий:
- Вызов запустил бы приложение браузера напрямую.
- Вызов показал бы пользователю диалоговое окно для уточнения.
В следующем фрагменте кода показано, как использовать флаги FLAG_ACTIVITY_REQUIRE_NON_BROWSER и FLAG_ACTIVITY_REQUIRE_DEFAULT вместе:
Kotlin
val url = URL_TO_LOAD try { // For this intent to be invoked, the system must directly launch a // non-browser app. val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or FLAG_ACTIVITY_REQUIRE_DEFAULT } startActivity(intent) } catch (e: ActivityNotFoundException) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url) }
Java
String url = URL_TO_LOAD; try { // For this intent to be invoked, the system must directly launch a // non-browser app. Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER | FLAG_ACTIVITY_REQUIRE_DEFAULT); startActivity(intent); } catch (ActivityNotFoundException e) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url); }
Открытие файла
Если ваше приложение работает с файлами или прикрепленными файлами, например проверяет, может ли устройство открыть определенный файл, обычно проще всего попробовать запустить действие, которое может обработать этот файл. Для этого используйте намерение, которое включает действие ACTION_VIEW и URI, представляющий определенный файл. Если на устройстве нет подходящего приложения, ваше приложение может перехватить ActivityNotFoundException. В логике обработки исключений можно либо показать ошибку, либо попробовать обработать файл самостоятельно.
Если вашему приложению нужно заранее знать, может ли другое приложение открыть определенный файл, включите элемент <intent> в приведенный ниже фрагмент кода как часть элемента <queries> в манифесте. Укажите тип файла, если он известен во время компиляции.
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". --> <data android:mimeType="application/pdf" /> </intent>
Затем вы можете проверить, доступно ли приложение, вызвав метод resolveActivity() с вашим намерением.
Предоставить доступ к URI
Примечание. Объявлять разрешения на доступ к URI, как описано в этом разделе, необходимо для приложений, предназначенных для Android 11 (уровень API 30) или более поздней версии. Мы рекомендуем делать это для всех приложений, независимо от целевой версии SDK и того, экспортируют ли они своих поставщиков контента.
Чтобы приложения, предназначенные для Android 11 или более поздней версии, могли получить доступ к URI контента, в намерении приложения необходимо объявить разрешения на доступ к URI, установив один или оба следующих флага намерения: FLAG_GRANT_READ_URI_PERMISSION и FLAG_GRANT_WRITE_URI_PERMISSION.
На устройствах с Android 11 и более поздними версиями разрешения на доступ к URI предоставляют приложению, получающему намерение, следующие возможности:
- Чтение или запись данных, которые представляет URI контента, в зависимости от разрешений URI.
- Получите доступ к приложению, содержащему поставщика контента, который соответствует URI authority. Приложение, содержащее поставщика контента, может отличаться от приложения, отправляющего намерение.
В следующем фрагменте кода показано, как добавить флаг намерения для разрешений URI, чтобы другое приложение, предназначенное для Android 11 или более поздней версии, могло просматривать данные в URI контента:
Kotlin
val shareIntent = Intent(Intent.ACTION_VIEW).apply { flags = Intent.FLAG_GRANT_READ_URI_PERMISSION data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP }
Java
Intent shareIntent = new Intent(Intent.ACTION_VIEW); shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);
Подключиться к сервисам
Если приложению нужно взаимодействовать с сервисом, который не виден автоматически, вы можете объявить соответствующее действие intent в элементе <queries>. В разделах ниже приведены примеры для часто используемых сервисов.
Подключитесь к системе синтеза речи
Если ваше приложение взаимодействует с системой синтеза речи (TTS), добавьте в манифест элемент <intent>, который будет частью элемента <queries>:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.TTS_SERVICE" /> </intent>
Подключитесь к сервису распознавания речи
Если ваше приложение взаимодействует с сервисом распознавания речи, добавьте в манифест элемент <intent> как часть элемента <queries>:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.speech.RecognitionService" /> </intent>
Подключение к сервисам браузера мультимедиа
Если ваше приложение является клиентским приложением для просмотра медиаконтента, включите следующий элемент <intent> в элемент <queries> в манифесте:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.media.browse.MediaBrowserService" /> </intent>
Предоставление специальных функций
Если вашему приложению нужно выполнять настраиваемые действия или показывать настраиваемую информацию на основе взаимодействий с другими приложениями, вы можете представить это настраиваемое поведение с помощью подписей фильтров интентов как части элемента <queries> в манифесте. В следующих разделах приведены подробные инструкции для нескольких распространенных сценариев.
Запрос приложений для обмена SMS
Если вашему приложению нужна информация о приложениях для обмена SMS, установленных на устройстве, например чтобы проверить, какое из них используется по умолчанию, добавьте элемент <intent> в элемент <queries> в манифесте:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto" android:host="*" /> </intent>
Как создать собственное меню "Поделиться"
По возможности используйте системное меню "Поделиться". Также можно добавить элемент <intent> в элемент <queries> в манифесте:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SEND" /> <!-- Replace with the MIME type that your app works with, if needed. --> <data android:mimeType="image/jpeg" /> </intent>
В остальном процесс создания листа обмена контентом в логике приложения, например вызов queryIntentActivities(), не изменился по сравнению с версиями Android, предшествующими Android 11.
Показывать специальные действия с выделенным текстом
Когда пользователи выделяют текст в вашем приложении, на панели инструментов появляются доступные действия. Если на этой панели инструментов показываются настраиваемые действия из других приложений, добавьте в манифест элемент <intent> в качестве дочернего элемента <queries>:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent>
Показать строки со специальными данными для контакта
Приложения могут добавлять собственные строки данных в поставщик контактов. Чтобы приложение для работы с контактами могло показывать эти пользовательские данные, оно должно уметь:
- Прочитайте файл
contacts.xmlиз других приложений. - Загрузите значок, соответствующий специальному MIME-типу.
Если ваше приложение является приложением "Контакты", включите следующие элементы <intent> в качестве части элемента <queries> в манифесте:
<!-- Place inside the <queries> element. --> <!-- Lets the app read the contacts.xml file from other apps. --> <intent> <action android:name="android.accounts.AccountAuthenticator" /> </intent> <!-- Lets the app load an icon corresponding to the custom MIME type. --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="content" android:host="com.android.contacts" android:mimeType="vnd.android.cursor.item/*" /> </intent>