Как получать данные из других приложений

Приложение может не только отправлять данные другим приложениям, но и получать их от них. Подумайте, как пользователи взаимодействуют с вашим приложением и какие типы данных вы хотите получать из других приложений. Например, приложение социальной сети может быть заинтересовано в получении текстового контента, такого как интересный веб-URL, из другого приложения.

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

  1. Объявите <intent-filter> в манифесте. Вам по-прежнему нужно добавить фильтр intent в действие в файле AndroidManifest.xml. Это сообщает ОС Android, что ваше приложение способно получать определенные действия (например, ACTION_SEND) и MIME-типы (например, text/plain).

  2. Определите navDeepLink в графе Navigation Compose. Прикрепите navDeepLink, соответствующий действию и MIME-типу, непосредственно к composable-функции назначения, в которой должен отображаться контент. NavController автоматически перехватывает входящий интент и направляет пользователя прямо на этот экран.

  3. Извлеките полезную нагрузку входящих данных. На целевом экране получите доступ к дополнительным данным intent (например, EXTRA_TEXT или EXTRA_STREAM), чтобы извлечь общий контент и обновить состояние пользовательского интерфейса.

Цели прямой отправки – это ссылки на контент, связанные с определенным действием в приложении. Обычно они представляют собой пользователя или группу и показываются на панели "Поделиться". Например, приложение для обмена сообщениями может предоставить целевой объект Direct Share для пользователя, который напрямую связывает с чатом с этим пользователем. Подробные инструкции приведены в разделе Как предоставить цели для функции "Прямой доступ к функциям приложения".

Поддерживаемые MIME-типы

В идеале приложение должно поддерживать как можно больше MIME-типов. Например, мессенджер, предназначенный для отправки текста, изображений и видео, в идеале должен поддерживать получение text/*, image/* и video/*. Ниже приведены некоторые распространенные 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-типов IANA.

Как создавать хорошие цели для Direct Share

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

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

Чтобы получать переданные данные в приложении, использующем Compose, нужно объявить фильтры интентов в манифесте, направить входящие интенты на нужный экран с помощью ссылок на контент и извлечь полезную нагрузку из интента, чтобы обновить интерфейс.

Как обновить манифест

Фильтры интентов сообщают системе, какие интенты принимает компонент приложения. Подобно тому, как вы создавали интент с действием ACTION_SEND на уроке Отправка данных в другие приложения, вы создаете фильтры интентов для получения интентов с этим действием. Фильтр интентов определяется в манифесте с помощью элемента <intent-filter>. Например, если ваше приложение обрабатывает текстовый контент, манифест, включающий одно или несколько изображений любого типа, будет выглядеть следующим образом:

<activity android:name=".ui.MyActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

Когда другое приложение пытается поделиться любым из этих объектов, создавая намерение и передавая его в startActivity(), ваше приложение указывается в качестве варианта на панели "Поделиться" или в средстве разрешения намерений. Если пользователь выберет ваше приложение, запустится соответствующее действие (.ui.MyActivity в примере выше). Вам нужно будет самостоятельно обработать контент в коде и интерфейсе.

В Compose Navigation прикрепите navDeepLink непосредственно к composable-функции назначения, в которой должен отображаться контент. Когда другое приложение передает данные, соответствующие вашему фильтру интентов, Compose Navigation направляет пользователя непосредственно к этому пункту назначения:

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

Обработка входящего контента

Чтобы получить контент, доставленный с помощью Intent, прочитайте текущее действие из LocalActivity.current в composable-функции, а затем изучите намерение, чтобы определить, что делать дальше. Если это действие можно запустить из других частей системы (например, из панели запуска), учитывайте это при анализе намерения.

Внимательно проверяйте входящие данные: может быть задан неверный MIME-тип или отправляемое изображение может быть слишком большим. Обрабатывайте двоичные данные или выполняйте операции ввода-вывода (например, декодирование больших изображений или запись файлов) асинхронно с помощью сопрограмм (например, Dispatchers.IO), а не в основном потоке интерфейса.

@Composable
fun SharesheetHandler() {
    val activity = LocalActivity.current
    val intent = activity?.intent

    when (intent?.action) {
        Intent.ACTION_SEND -> {
            if (intent.type == "text/plain") {
                handleSendText(intent) // Handle text being sent
            } else if (intent.type?.startsWith("image/") == true) {
                handleSendImage(intent) // Handle single image being sent
            }
        }

        Intent.ACTION_SEND_MULTIPLE -> {
            if (intent.type?.startsWith("image/") == true) {
                handleSendMultipleImages(intent) // Handle multiple images being sent
            }
        }

        else -> {
            // Handle other intents, such as being started from the home screen
        }
    }
}

private fun handleSendText(intent: Intent) {
    intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
        // Update UI state with the shared text
    }
}

private fun handleSendImage(intent: Intent) {
    val imageUri = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUri?.let {
        // Update UI state with the shared image
    }
}

private fun handleSendMultipleImages(intent: Intent) {
    val imageUris =
        IntentCompat.getParcelableArrayListExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUris?.let {
        // Update UI state with the shared images
    }
}

При извлечении двоичных данных или URI из дополнительных данных намерения (например, EXTRA_STREAM) используйте IntentCompat.getParcelableExtra() или IntentCompat.getParcelableArrayListExtra() из библиотеки AndroidX Core, как показано в функциях handleSendImage и handleSendMultipleImages выше. В Android 13 (уровень API 33) метод Intent.getParcelableExtra(String) без параметров заменен типобезопасными методами, которые принимают ожидаемый тип класса.

Обновление интерфейса после получения данных может быть простым, например обновление состояния для заполнения TextField, или сложным, например применение фильтра к изображению. Дальнейшие действия зависят от вашего приложения.

Как поделиться URL скриншота

Вы можете поделиться скриншотом и связанным с ним URL. Это повышает удобство для пользователей. При получении URL убедитесь, что поле EXTRA_TEXT извлечено из намерения, как показано в следующем примере:

IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java).let {
    // Handle the EXTRA_TEXT as well
    val extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)
    // Update UI state with the shared image and the EXTRA_TEXT if available
}

Сделайте так, чтобы пользователи узнавали ваше приложение

Приложение представлено значком и ярлыком на панели "Поделиться" и в средстве выбора намерений. Оба этих параметра определены в манифесте. Чтобы предоставить больше контекста, можно задать ярлыки фильтров действий или намерений.

В Android 10 (уровень API 29) панель "Поделиться" использует только значки, заданные в манифесте в теге application. Android игнорирует значки, заданные в тегах intent-filter и activity.

Получение расширенного контента

Намерения ACTION_SEND позволяют получать данные из панели "Поделиться" и средства разрешения намерений на уровне действия или навигации. Кроме того, приложения могут получать расширенные сведения (например, изображения, видео, аудиофайлы и форматированный текст) через прямое взаимодействие с интерфейсом. К ним относятся:

  • Вставка из буфера обмена (меню, которое появляется при нажатии и удерживании)
  • Вставка медиаконтента, например стикеров или GIF-файлов, непосредственно с виртуальной клавиатуры (редактора метода ввода).
  • перетаскивание контента из другого приложения в режиме разделения экрана или многооконном режиме;

В интерфейсах на основе представлений в Android 12 (уровень API 31) и AndroidX Core 1.7 представлен унифицированный API OnReceiveContentListener. Этот прослушиватель объединяет обработку контента из буфера обмена, клавиатуры и перетаскивания в один обратный вызов. Подробные инструкции по реализации этой функции в представлениях приведены в статье Как получать расширенный контент.

В Jetpack Compose вы можете обрабатывать получение расширенного контента, вставленного в компоненты пользовательского интерфейса (например, текстовые поля), с помощью модификатора Modifier.contentReceiver или модификаторов перетаскивания.