Как отправлять данные в другие приложения

В Android используются намерения и связанные с ними дополнительные данные, чтобы пользователи могли быстро делиться информацией с помощью любимых приложений.

В Android есть два способа обмена данными между приложениями:

  • Системный интерфейс Android Sharesheet предназначен в первую очередь для отправки контента за пределы приложения и/или напрямую другому пользователю. Например, вы можете поделиться URL с другом.
  • Разрешитель намерений Android лучше всего подходит для передачи данных на следующий этап четко определенной задачи. Например, вы можете открыть PDF-файл из своего приложения и позволить пользователям выбрать предпочитаемое средство просмотра.

При создании намерения вы указываете действие, которое оно должно выполнить. Android использует действие ACTION_SEND для передачи данных из одного действия в другое, даже если они выполняются в разных процессах. Вам нужно указать данные и их тип. Система автоматически определяет совместимые действия, которые могут получать данные, и показывает их пользователю. Если только одно приложение может обработать намерение, оно запускается немедленно.

Преимущества использования меню "Поделиться" в Android

Рисунок 1. Меню "Поделиться" на устройстве Android.

Мы настоятельно рекомендуем использовать системный интерфейс Android для обмена данными, чтобы обеспечить единообразие для пользователей в разных приложениях. Не показывайте собственный список целевых приложений для обмена и не создавайте собственные варианты панели "Поделиться".

Панель "Поделиться" в Android позволяет пользователям отправлять информацию нужным людям, получая при этом рекомендуемые приложения, – и все это одним нажатием. Панель "Поделиться" может предлагать цели, недоступные для специальных решений, и использует последовательную систему ранжирования. Это связано с тем, что при выборе приложений для панели "Поделиться" учитывается информация о действиях в приложениях и действиях пользователей, которая доступна только системе.

В Android Sharesheet также есть много полезных функций для разработчиков. Например, вы можете:

Как использовать окно "Поделиться" в Android

Для всех типов обмена создайте намерение и задайте для него действие Intent.ACTION_SEND. Чтобы показать окно "Поделиться" на устройстве Android, вызовите метод Intent.createChooser() и передайте ему объект Intent. Он возвращает версию вашего намерения, которая всегда показывает окно "Поделиться" в Android.

Отправка текстового контента

Самый простой и распространенный способ использования таблицы обмена Android – передача текстового контента из одного действия в другое. Например, большинство браузеров могут передавать URL текущей страницы в другое приложение в виде текста. Это удобно, если вы хотите поделиться статьей или сайтом с друзьями по электронной почте или в социальной сети. Вот пример того, как это можно сделать:

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/*
  • text/plain
  • text/rtf
  • text/html
  • text/json
`image/*`
  • image/jpg
  • image/png
  • image/gif
video/*
  • video/mp4
  • video/3gp
Поддерживаемые расширения файлов application/pdf

Подробная информация о 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>. Подробнее о том, как предоставить доступ к файлам… Убедитесь, что у функции "Поделиться" есть разрешение на чтение изображений, которые вы хотите использовать в качестве значков. Дополнительную информацию можно найти по адресу 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)
}

Предварительный просмотр выглядит примерно так:

Рисунок 2. Предпросмотр текстового контента в меню "Поделиться" на устройстве Android.

Как добавить в окно отправки специальные действия

Рисунок 3. Специальные действия в меню "Поделиться" на устройствах Android.

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

Чтобы добавить собственные действия в меню "Поделиться" на устройстве Android, сначала создайте ChooserAction с помощью ChooserAction.Builder. Вы можете указать PendingIntent в качестве действия, которое будет выполняться при нажатии на значок. Создайте массив, содержащий все ваши специальные действия, и укажите его как EXTRA_CHOOSER_CUSTOM_ACTIONS для функции "Поделиться" 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 можно указать до двух объектов ChooserTarget, которые будут показываться перед ярлыками для отправки и целевыми объектами, загруженными из ChooserTargetServices. Вы также можете указать до двух интентов, связанных с действиями, которые перечислены до рекомендуемых приложений:

Рисунок 4. Собственные цели в меню "Поделиться" на устройствах Android.

Добавьте Intent.EXTRA_CHOOSER_TARGETS и 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 и ChooserTarget уменьшает количество вариантов, предложенных системой. Мы не рекомендуем добавлять собственные целевые значения. Примером подходящего использования тега Intent.EXTRA_INITIAL_INTENTS является добавление дополнительных действий, которые пользователи могут выполнять с общим контентом. Например, пользователь делится изображениями, и Intent.EXTRA_INITIAL_INTENTS используется, чтобы вместо этого отправить ссылку. Распространенный пример использования Intent.EXTRA_CHOOSER_TARGETS – указание людей или устройств, которые предоставляет ваше приложение.

Как исключить определенные целевые значения по компонентам

Вы можете исключить определенные цели, указав 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 Sharesheet можно получить эту информацию, указав 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

Рисунок 5. ACTION_SENDОпределитель намерений
.

Разрешитель намерений Android лучше всего использовать при отправке данных в другое приложение в рамках четко определенного рабочего процесса.

Чтобы использовать средство разрешения намерений 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)
}

Подробнее…

Подробнее об отправке данных…