正如应用可以将数据发送到其他应用一样,它也可以从其他应用接收数据。考虑用户如何与您的应用互动,以及您希望从其他应用接收哪些数据类型。例如,社交网络应用可能希望从另一个应用接收文本内容,例如有趣的网址。
在使用 Compose Navigation 的应用中,接收其他应用发送的数据是一个三步流程:
在清单中声明
<intent-filter>:您仍必须在AndroidManifest.xml文件中为您的 activity 添加 intent filter。这会告知 Android 操作系统,您的应用能够接收特定操作(例如ACTION_SEND)和 MIME 类型(例如text/plain)。在 Compose Navigation 图中定义
navDeepLink:将与操作和 MIME 类型匹配的navDeepLink直接附加到应显示内容的可组合项目的地。NavController会自动拦截传入的 intent,并将用户直接路由到该界面。提取传入的数据载荷:在目标界面中,访问 intent extra(例如
EXTRA_TEXT或EXTRA_STREAM),以检索共享内容并更新界面状态。
直接分享目标是指应用内特定 activity 的深层链接。它们通常代表个人或群组,并且 Android Sharesheet 会显示它们。 例如,即时通讯应用可以为某个人提供直接分享目标,该目标会直接深层链接到与该人的对话。如需查看详细说明,请参阅提供直接 分享目标。
支持的 MIME 类型
理想情况下,应用必须能够接收尽可能多的 MIME 类型。
例如,专为发送文本、图片和视频而设计的即时通讯应用理想情况下应支持接收 text/*、image/* 和 video/*。以下是一些用于在 Android 中发送和接收数据的常见 MIME 类型。
| 接收器注册 | 发送器发送 |
|---|---|
text/* |
|
image/* |
|
video/* |
|
| 支持的文件扩展名 | application/pdf |
请参阅 IANA 官方 MIME 媒体类型注册表。
打造出色的分享目标
当用户点按与特定 activity 关联的分享目标时,请让他们在您的应用使用共享内容之前确认并修改该内容。这对于文本数据尤为重要。
在应用中接收数据
在使用 Compose 的应用中接收共享数据涉及在清单中声明 intent 过滤器、使用深层链接将传入的 intent 路由到正确的界面,以及从 intent 中提取载荷以更新界面。
更新您的清单
intent 过滤器会告知系统应用组件接受哪些 intent。与您在将数据发送到其他应用课程中构建具有 ACTION_SEND 操作的 intent 的方式类似,您可以创建 intent 过滤器来接收
具有此操作的 intent。您可以使用
<intent-filter> 元素在清单中定义 intent 过滤器。例如,如果您的应用处理接收文本内容,则包含一个或多个任何类型的图片的清单将类似于以下代码段:
<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>
当另一个应用尝试通过构建 intent
并将其传递给 startActivity() 来共享这些内容时,您的应用会在 Android Sharesheet 或 intent 解析器中列为选项
。如果用户选择您的应用,则会启动相应的 activity(在前面的示例中为 .ui.MyActivity)。然后,您需要在代码和界面中适当地处理内容。
在导航图中定义深层链接
在 Compose Navigation 中,将 navDeepLink 直接附加到应显示内容的可组合项目的地。当另一个应用共享与您的 intent 过滤器匹配的数据时,Compose Navigation 会将用户直接路由到此目的地:
composable( route = "incoming_share", deepLinks = listOf( navDeepLink { action = Intent.ACTION_SEND mimeType = "text/plain" }, navDeepLink { action = Intent.ACTION_SEND mimeType = "image/*" }, navDeepLink { action = Intent.ACTION_SEND_MULTIPLE mimeType = "image/*" } ) ) { SharesheetHandler() }
navDeepLink 会根据传入 intent 的操作和 MIME 类型进行匹配,以导航到正确的目标界面。到达该目的地后,您的处理程序会检查 intent 以确定收到了哪些载荷(例如单张图片与多张图片),并提取相应的 extra。
处理传入的内容
如需检索 Intent 传送的内容,请从可组合项中的 LocalActivity.current 读取当前
activity,然后检查 intent 以确定下一步操作。如果此 activity 可以从系统的其他部分(例如启动器)启动,请在检查 intent 时考虑到这一点。
请格外注意检查传入的数据:可能会设置错误的 MIME 类型,或者发送的图片可能非常大。使用协程(例如 Dispatchers.IO)而不是在主界面线程上异步处理二进制数据或繁重的 I/O 操作(例如解码大型图片或写入文件)。
@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 } }
从 intent extra(例如 EXTRA_STREAM)提取二进制数据或 URI 时,
请使用 IntentCompat.getParcelableExtra() 或
IntentCompat.getParcelableArrayListExtra()
(来自 AndroidX Core 库),如前面的 handleSendImage 和
handleSendMultipleImages 函数所示。Android 13(API 级别 33)废弃了未带参数的 Intent.getParcelableExtra(String) 方法,转而使用采用预期类别的类型安全方法。
在收到数据后更新界面可以像更新
状态以填充 TextField 一样简单,也可以像对图片应用过滤条件
一样复杂。接下来会发生什么情况取决于您的应用。
屏幕截图网址分享
拍摄屏幕截图时,您可以分享屏幕截图和任何关联的网址。
这可以提供更丰富的用户体验。接收网址时,请务必从 intent 中获取 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 Sharesheet 和 intent 解析器中由其 图标 和 标签 表示。这两者都在清单中定义。您可以设置 activity 或 intent 过滤器标签以提供更多上下文。
从 Android 10(API 级别 29)开始,Android Sharesheet 仅使用在清单的 application 标记中设置的图标。Android 会忽略在 intent-filter 和 activity 标记中设置的图标。
接收富媒体内容
虽然 ACTION_SEND intent 允许在 activity 或导航级别从 Android Sharesheet 和 intent 解析器接收数据,但应用也可以通过直接界面互动接收富媒体内容(例如图片、视频、音频文件和样式文本)。这些机制包括:
- 从剪贴板粘贴(触摸并按住菜单)
- 直接从软件键盘 (IME) 插入媒体,例如贴纸或 GIF
- 在多窗口模式或分屏模式下从另一个应用拖放内容
在基于 View 的界面中,Android 12(API 级别 31)和 AndroidX Core 1.7 引入了
统一的 OnReceiveContentListener API。此监听器将来自剪贴板、键盘和拖放操作的内容处理整合到单个回调中。如需详细了解如何在 View 中实现此功能,请参阅接收富媒体内容。
在 Jetpack Compose 中,您可以使用
Modifier.contentReceiver 修饰符或
拖放修饰符来处理接收插入到界面
组件(例如文本字段)中的富媒体内容。