В Android есть два способа обмена данными между приложениями:
- Панель "Поделиться" в Android в основном предназначена для отправки контента за пределы приложения или напрямую другому пользователю. Например, вы можете поделиться URL с другом.
- Разрешитель намерений Android лучше всего подходит для передачи данных на следующий этап четко определенной задачи. Например, если пользователь открывает PDF-файл из вашего приложения, он может выбрать средство просмотра.
Преимущества панели "Поделиться"
Используйте панель "Поделиться" в Android, чтобы обеспечить единообразие для пользователей в разных приложениях. Не показывайте собственный список получателей и не создавайте собственные варианты панели "Поделиться".
Панель "Поделиться" в Android позволяет пользователям отправлять информацию нужным людям, используя подходящие приложения, всего одним нажатием. Панель "Поделиться" может предлагать цели, недоступные для специальных решений, и использует последовательную систему ранжирования. Это связано с тем, что при выборе приложений для панели "Поделиться" учитывается информация о действиях в приложениях и действиях пользователей, которая доступна только системе.
Кроме того, в ней есть много полезных функций для разработчиков. Например, вы можете:
- Как узнать, когда и куда пользователи отправляют контент
- Как добавить таргетинг со специальными настройками и таргетинг на приложения
- Как показывать предварительный просмотр форматированного текста в Android 10 (уровень API 29) и более поздних версиях
- Как исключить целевые значения, соответствующие определенным названиям компонентов
Как использовать окно "Поделиться" в Android
Для всех типов обмена данными создайте намерение и задайте для него действие Intent.ACTION_SEND.
Чтобы показать окно "Поделиться" на устройстве Android, вызовите метод Intent.createChooser() и передайте ему объект Intent.
Он возвращает версию вашего намерения, которая всегда показывает панель "Поделиться".
Отправка текстового контента
Самый простой и распространенный способ использования таблицы обмена Android – передача текстового контента из одного действия в другое. Например, большинство браузеров могут передавать URL-адрес текущей страницы в виде текста в другое приложение. Это удобно, если вы хотите поделиться статьей или сайтом с друзьями по электронной почте или в социальной сети. В Jetpack Compose получите текущий контекст с помощью LocalContext.current и вызовите context.startActivity().
Вот пример того, как это сделать:
fun shareText(context: Context) { val sendIntent: Intent = Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "This is my text to send.") type = "text/plain" } val shareIntent = Intent.createChooser(sendIntent, null) context.startActivity(shareIntent) }
При необходимости вы можете добавить дополнительные параметры, чтобы включить больше информации, например получателей электронной почты (EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC) или тему письма (EXTRA_SUBJECT).
Примечание. Некоторые почтовые приложения, например Gmail, ожидают String[] для дополнительных параметров, таких как EXTRA_EMAIL и EXTRA_CC. Чтобы добавить их в намерение, используйте putExtra(String, String[]).
Как отправлять двоичный контент
Передавайте двоичные данные с помощью действия ACTION_SEND.
Установите соответствующий MIME-тип и поместите URI в дополнительный параметр EXTRA_STREAM, как показано в примере ниже.
Обычно это используется для обмена изображениями, но может использоваться для обмена любым типом двоичного контента.
fun shareBinaryContent(context: Context) { val shareIntent: Intent = Intent().apply { action = ACTION_SEND // Example: content://com.google.android.apps.photos.contentprovider/... val imageUri: Uri = Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1") putExtra(Intent.EXTRA_STREAM, imageUri) type = "image/jpeg" } context.startActivity(Intent.createChooser(shareIntent, null)) }
Приложению-получателю требуется разрешение на доступ к данным, на которые указывает Uri. Это можно сделать двумя способами:
- Храните данные в собственном
ContentProvider, убедившись, что у других приложений есть разрешение на доступ к вашему поставщику. Предпочтительный механизм предоставления доступа – использование разрешений для отдельных URI, которые являются временными и предоставляют доступ только принимающему приложению. Чтобы создать такой объектContentProvider, используйте вспомогательный классFileProvider. - Используйте системный
MediaStore.MediaStoreв основном используется для MIME-типов видео, аудио и изображений. Однако начиная с Android 3.0 (уровень API 11) в нем также могут храниться файлы других типов. Дополнительную информацию можно найти по адресуMediaStore.Files. Файлы можно вставлять вMediaStoreс помощьюscanFile(). После этогоUriв стилеcontent://, подходящий для предоставления доступа, передается в предоставленный обратный вызовonScanCompleted(). Обратите внимание, что после добавления в системуMediaStoreконтент будет доступен любому приложению на устройстве.
Используйте правильный MIME-тип
Укажите наиболее подходящий MIME-тип для отправляемых данных. Например, используйте text/plain, чтобы поделиться обычным текстом. Вот несколько распространенных MIME-типов, используемых при отправке данных в Android:
| Получатели регистрируются для | Отправители отправляют |
|---|---|
text/* |
|
image/* |
|
video/* |
|
| Поддерживаемые расширения файлов | application/pdf |
Чтобы определить MIME-тип динамически во время выполнения, а не задавать его в коде, используйте следующие методы:
- Для URI
content://(например, предоставляемыхFileProviderилиMediaStore) вызовитеContentResolver.getType(). - Для расширений имени файла вызовите
MimeTypeMap.getSingleton().getMimeTypeFromExtension(). - Если вы используете Storage Access Framework, то также можете запросить
DocumentFile.getType().
Если вы не можете определить конкретный MIME-тип, используйте application/octet-stream для общих двоичных данных или */* в крайнем случае.
Подробная информация о MIME-типах приведена в официальном реестре медиатипов MIME на сайте IANA.
В зависимости от указанного MIME-типа в меню "Поделиться" Android может показываться предпросмотр контента. Некоторые предварительные версии функций доступны только для определенных типов.
Как поделиться несколькими файлами
Чтобы поделиться несколькими фрагментами контента, используйте действие ACTION_SEND_MULTIPLE вместе со списком URI, указывающих на контент. MIME-тип зависит от того, какой контент вы отправляете. Например, если вы делитесь тремя изображениями в формате JPEG, используйте тип "image/jpg". Если вы хотите, чтобы действие обрабатывало изображения любого типа, используйте "image/*". Хотя вы можете передавать данные разных типов, мы не рекомендуем этого делать, поскольку получателю может быть непонятно, что именно ему отправлено. Если вам нужно отправить несколько типов, используйте "*/*". Приложение-получатель должно проанализировать и обработать ваши данные. Рассмотрим пример.
fun shareMultiple(context: Context) { val imageUris: ArrayList<Uri> = arrayListOf( Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1"), Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/2") ) val shareIntent = Intent().apply { action = Intent.ACTION_SEND_MULTIPLE putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris) type = "image/*" } context.startActivity(Intent.createChooser(shareIntent, null)) }
Убедитесь, что предоставленные объекты Uri указывают на данные, к которым у приложения-получателя есть доступ.
Добавление расширенного контента в предварительный просмотр текста
Начиная с Android 10 (уровня API 29) на панели "Поделиться" показывается предварительный просмотр текста. Иногда текст, которым делятся пользователи, бывает трудно понять. Представьте, что вам нужно поделиться сложным URL, например https://www.google.com/search?ei=2rRVXcLkJajM0PEPoLy7oA4. Более подробный предварительный просмотр поможет пользователям понять, что именно будет передано.
Если вы хотите показать текст, то можете добавить заголовок, значок или и то, и другое. Добавьте описание к объекту Intent.EXTRA_TITLE перед вызовом Intent.createChooser() и добавьте подходящий значок, используя ClipData.
Примечание. URI контента изображения предоставляется из FileProvider, обычно из настроенного <cache-path>.
Подробнее о предоставлении доступа к файлам… Убедитесь, что у Sharesheet есть разрешение на чтение изображения, которое вы хотите использовать в качестве значка. Дополнительную информацию вы найдете здесь: Intent.FLAG_GRANT_READ_URI_PERMISSION.
Рассмотрим пример.
fun richContentToTextPreviewShares(context: Context) { val share = Intent.createChooser( Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/") // (Optional) Here you're setting the title of the content putExtra(Intent.EXTRA_TITLE, "Introducing content previews") // (Optional) Here you're passing a content URI to an image to be displayed data = Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/A123456789") flags = Intent.FLAG_GRANT_READ_URI_PERMISSION }, null ) context.startActivity(share) }
Предварительный просмотр выглядит примерно так:
Как добавить собственные действия в меню "Поделиться"
В Android 14 (уровень API 34) и более поздних версиях приложения могут добавлять в системный интерфейс обмена данными собственные действия.
Настраиваемые действия показываются в виде небольших значков в верхней части панели "Поделиться". Приложения могут указывать любой объект Intent в качестве действия, которое выполняется при нажатии на значок.
Чтобы добавить собственные действия в меню "Поделиться" на устройстве Android, сначала создайте ChooserAction с помощью ChooserAction.Builder.
Вы можете указать PendingIntent в качестве действия, которое будет выполняться при нажатии на значок. Создайте массив, содержащий все ваши настраиваемые действия, и укажите его как EXTRA_CHOOSER_CUSTOM_ACTIONS объекта share Intent.
fun sharesheetCustomActions(context: Context, previewText: String) { val sendIntent = Intent(ACTION_SEND) .setType("text/plain") .putExtra(Intent.EXTRA_TEXT, previewText) val shareIntent = Intent.createChooser(sendIntent, null) val customActions = arrayOf( ChooserAction.Builder( Icon.createWithResource(context, R.drawable.ic_logo), "Custom", PendingIntent.getBroadcast( context, 1, Intent(Intent.ACTION_VIEW), PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT ) ).build() ) shareIntent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, customActions) context.startActivity(shareIntent) }
Добавьте собственные цели
Панель "Поделиться" в Android позволяет указать до двух намерений для действий, которые будут показаны перед рекомендуемыми приложениями. Для этого используется Intent.EXTRA_INITIAL_INTENTS.
Для получателей Direct Share (например, чатов или контактов) публикуйте динамические ярлыки, используя вместо этого ShortcutManagerCompat (см. Как предоставить получателей Direct Share):
Добавьте Intent.EXTRA_INITIAL_INTENTS в намерение поделиться после вызова Intent.createChooser():
val sendIntent = Intent(ACTION_SEND).apply { type = "text/plain" putExtra(Intent.EXTRA_TEXT, previewText) } val customIntent = Intent().apply { component = ComponentName(context.packageName, "${context.packageName}.CustomActivity") } val shareIntent = Intent.createChooser(sendIntent, null).apply { putExtra( Intent.EXTRA_INITIAL_INTENTS, arrayOf(customIntent) ) } context.startActivity(shareIntent)
Используйте эту функцию с осторожностью. Каждый добавленный вами пользовательский Intent
уменьшает количество, предложенное системой. В целом, избегайте добавления пользовательских целей. Обычно Intent.EXTRA_INITIAL_INTENTS добавляют, чтобы предоставить пользователям дополнительные действия с контентом, которым они делятся. Например, пользователь делится изображениями, и Intent.EXTRA_INITIAL_INTENTS используется, чтобы вместо этого отправить ссылку.
Как исключить определенные цели по компоненту
Вы можете исключить определенные цели, указав Intent.EXTRA_EXCLUDE_COMPONENTS.
Удаляйте только те цели, которые вы можете контролировать. Например, если пользователь хочет поделиться контентом из вашего приложения, то, скорее всего, он хочет отправить его в другое приложение. В этом случае можно скрыть цели для обмена контентом в вашем приложении.
Добавьте Intent.EXTRA_EXCLUDE_COMPONENTS в намерение после вызова Intent.createChooser():
fun excludeSpecificTargets(context: Context) { val share = Intent.createChooser(Intent(ACTION_SEND), null).apply { // Only use for components you have control over val excludedComponentNames = arrayOf(ComponentName("com.example.android", "ExampleClass")) putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames) } context.startActivity(share) }
Как поделиться информацией
Вы можете узнать, когда пользователи делятся контентом и какие цели они выбирают. Панель "Поделиться" в Android позволяет получить эту информацию, предоставляя ComponentName целей, которые выбирают пользователи, с помощью IntentSender.
Сначала создайте PendingIntent для BroadcastReceiver и укажите его IntentSender в Intent.createChooser():
fun infoAboutSharing(context: Context, requestCode: Int) { var share = Intent(ACTION_SEND) // ... val pi = PendingIntent.getBroadcast( context, requestCode, Intent(context, ShareBroadcastReceiver::class.java), PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) share = Intent.createChooser(share, null, pi.intentSender) context.startActivity(share) }
Получите обратный вызов в MyBroadcastReceiver и посмотрите в Intent.EXTRA_CHOOSER_RESULT:
override fun onReceive(context: Context?, intent: Intent) { val TAG = ShareBroadcastReceiver::class.simpleName val chooserResult: ChooserResult? = IntentCompat.getParcelableExtra( intent, Intent.EXTRA_CHOOSER_RESULT, ChooserResult::class.java, ) chooserResult?.let { Log.i(TAG, "Share callback: isShortcut: ${it.isShortcut}, type: ${typeToString(it.type)}, componentName: ${it.selectedComponent}", ) } ?: Log.i(TAG, "chooserResult is null") }
Подробную информацию можно найти в примере ответа.
Как использовать средство разрешения намерений Android
ACTION_SENDОпределитель намеренийСредство выбора намерений Android лучше всего использовать при отправке данных в другое приложение в рамках четко определенного рабочего процесса.
Чтобы использовать средство разрешения намерений Android, создайте намерение и добавьте дополнительные параметры, как при вызове панели "Поделиться". Однако не вызывайте Intent.createChooser().
Если установлено несколько приложений с фильтрами, которые соответствуют ACTION_SEND и типу MIME, система покажет диалоговое окно разрешения намерений, в котором пользователь сможет выбрать, куда отправить контент. Если совпадение будет найдено только с одним приложением, оно будет запущено.
Вот пример того, как использовать средство разрешения намерений Android для отправки текста:
fun intentResolver(context: Context) { val sendIntent: Intent = Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "This is my text to send.") type = "text/plain" } context.startActivity(sendIntent) }
Подробнее…
Подробнее об отправке данных см. в разделе Интенты и фильтры интентов.