Выполнение распространенных сценариев использования при ограниченной видимости пакета.

В этом документе представлены несколько распространенных сценариев использования, в которых приложение взаимодействует с другими приложениями. В каждом разделе даются рекомендации по реализации функциональности приложения при ограниченной видимости пакетов, что необходимо учитывать, если ваше приложение ориентировано на Android 11 (уровень API 30) или выше.

Когда приложение, ориентированное на Android 11 или более поздние версии, использует Intent для запуска Activity в другом приложении, наиболее простой подход — вызвать Intent и обработать исключение ActivityNotFoundException , если ни одно приложение недоступно.

Если часть вашего приложения зависит от того, сможет ли вызов startActivity() завершиться успешно, например, для отображения пользовательского интерфейса, добавьте элемент в элемент <queries> манифеста вашего приложения. Обычно это элемент <intent> .

Открыть URL-адреса

В этом разделе описаны различные способы открытия URL-адресов в приложении, предназначенном для Android 11 и выше.

Открывайте URL-адреса в браузере или другом приложении.

Для открытия URL-адреса используйте интент, содержащий действие ACTION_VIEW , как описано в руководстве по загрузке веб-адреса . После вызова startActivity() с помощью этого интента произойдет одно из следующих событий:

  • URL-адрес открывается в веб-браузере.
  • URL-адрес открывается в приложении, которое поддерживает этот 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 :

Котлин

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 вместе:

Котлин

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 предоставляют приложению, получающему Intent, следующие возможности:

  • В зависимости от заданных прав доступа к URI, данные, представленные в этом URI, могут быть использованы для чтения или записи.
  • Получите представление о приложении, содержащем поставщика контента, соответствующего URI-авторитету. Приложение, содержащее поставщика контента, может отличаться от приложения, отправляющего намерение.

Приведенный ниже фрагмент кода демонстрирует, как добавить флаг запроса разрешений URI, чтобы другое приложение, ориентированное на Android 11 или выше, могло просматривать данные в URI содержимого:

Котлин

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-приложений, установленных на устройстве, например, чтобы проверить, какое приложение является обработчиком 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>

Отображение пользовательских строк данных для контакта

Приложения могут добавлять пользовательские строки данных в поставщик контактов. Для отображения этих пользовательских данных приложением контактов необходимо иметь возможность выполнять следующие действия:

  1. Прочитайте файл contacts.xml из других приложений.
  2. Загрузите значок, соответствующий пользовательскому 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>