向其他应用发送简单数据

Android 使用 Intent 及其关联的额外数据,让用户可以使用自己喜欢的应用快速轻松地共享信息。

Android 为用户提供了两种在应用之间共享数据的方法

  • Android 共享表单主要用于将内容发送到应用外部和/或直接发送给其他用户。例如,与朋友共享 URL。
  • Android Intent 解析器最适合将数据传递到定义良好的任务的下一阶段。例如,从您的应用打开 PDF 并让用户选择他们首选的查看器。

构建 Intent 时,您需要指定 Intent 要执行的操作。Android 使用操作 ACTION_SEND 将数据从一个活动发送到另一个活动,甚至跨越进程边界。您需要指定数据及其类型。系统会自动识别可以接收数据的兼容活动,并将其显示给用户。在 Intent 解析器的情况下,如果只有一个活动可以处理 Intent,则该活动会立即启动。

为什么要使用 Android 共享表单

我们强烈建议您使用 Android 共享表单,以便为您的用户在各个应用中创建一致性。不要显示您自己的共享目标列表或创建您自己的共享表单变体。

Android 共享表单允许用户与合适的人共享信息,并提供相关的应用建议,只需轻点一下即可。共享表单可以建议自定义解决方案无法使用的目标,并使用一致的排名。这是因为共享表单可以考虑有关应用和用户活动的信息,而这些信息只有系统才能获得。

Android 共享表单还为开发者提供了许多方便的功能。例如,您可以执行以下操作

使用 Android 共享表单

对于所有类型的共享,请创建一个 Intent 并将其操作设置为 Intent.ACTION_SEND。要显示 Android 共享表单,请调用 Intent.createChooser(),并将您的 Intent 对象传递给它。它会返回您的 Intent 的一个版本,该版本始终显示 Android 共享表单。

发送文本内容

Android 共享表单最直接和最常见的用法是从一个活动向另一个活动发送文本内容。例如,大多数浏览器可以将当前显示页面的 URL 作为文本与其他应用共享。这对于通过电子邮件或社交网络与朋友共享文章或网站很有用。以下是如何执行此操作的示例

Kotlin

val sendIntent: Intent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
    type = "text/plain"
}

val shareIntent = Intent.createChooser(sendIntent, null)
startActivity(shareIntent)

Java

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");

Intent shareIntent = Intent.createChooser(sendIntent, null);
startActivity(shareIntent);

可选地,您可以添加额外信息以包含更多内容,例如电子邮件收件人(EXTRA_EMAILEXTRA_CCEXTRA_BCC)、电子邮件主题(EXTRA_SUBJECT)等。

注意:某些电子邮件应用(例如 Gmail)期望 String[] 作为 EXTRA_EMAILEXTRA_CC 等额外信息。使用 putExtra(String, String[]) 将这些信息添加到您的 Intent 中。

发送二进制内容

使用 ACTION_SEND 操作共享二进制数据。设置适当的 MIME 类型,并将指向数据的 URI 放置在额外信息 EXTRA_STREAM 中,如下例所示。这通常用于共享图像,但可用于共享任何类型的二进制内容。

Kotlin

val shareIntent: Intent = Intent().apply {
    action = Intent.ACTION_SEND
    // Example: content://com.google.android.apps.photos.contentprovider/...
    putExtra(Intent.EXTRA_STREAM, uriToImage)
    type = "image/jpeg"
}
startActivity(Intent.createChooser(shareIntent, null))

Java

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
// Example: content://com.google.android.apps.photos.contentprovider/...
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, null));

接收应用需要权限才能访问 Uri 指向的数据。有两种推荐的方法可以做到这一点

  • 将数据存储在您自己的 ContentProvider 中,确保其他应用具有访问您的提供程序的正确权限。提供访问的首选机制是使用 基于 URI 的权限,它们是临时的,并且只授予接收应用访问权限。创建此类 ContentProvider 的一种简单方法是使用 FileProvider 辅助类。
  • 使用系统 MediaStoreMediaStore 主要用于视频、音频和图像 MIME 类型。但是,从 Android 3.0(API 级别 11)开始,它也可以存储非媒体类型。有关更多信息,请参阅 MediaStore.Files。可以使用 scanFile() 将文件插入 MediaStore,之后将适合共享的 content:// 样式 Uri 传递给提供的 onScanCompleted() 回调。请注意,一旦添加到系统 MediaStore 中,任何设备上的应用都可以访问该内容。

使用正确的 MIME 类型

为要发送的数据提供最具体的 MIME 类型。例如,在共享纯文本时使用 text/plain。以下是在 Android 中发送简单数据时的一些常见 MIME 类型

接收方注册 发送方发送
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 MIME 媒体类型的官方注册表。

Android 共享表单可能会显示内容预览,具体取决于提供的 MIME 类型。某些预览功能仅适用于特定类型。

共享多个内容

要共享多个内容,请使用 ACTION_SEND_MULTIPLE 操作以及指向内容的 URI 列表。MIME 类型根据您共享的内容组合而有所不同。例如,如果您共享三张 JPEG 图像,则使用类型 "image/jpg"。对于图像类型的混合,请使用 "image/*" 以匹配处理任何类型图像的活动。虽然可以共享多种类型,但我们强烈建议不要这样做,因为接收方不清楚要发送什么。如果必须发送多种类型,请使用 "*/*"。接收应用负责解析和处理您的数据。这是一个示例

Kotlin

val imageUris: ArrayList<Uri> = arrayListOf(
        // Add your image URIs here
        imageUri1,
        imageUri2
)

val shareIntent = Intent().apply {
    action = Intent.ACTION_SEND_MULTIPLE
    putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris)
    type = "image/*"
}
startActivity(Intent.createChooser(shareIntent, null))

Java

ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri1); // Add your image URIs here
imageUris.add(imageUri2);

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent, null));

确保提供的 Uri 对象指向接收应用可以访问的数据。

向文本预览添加丰富内容

从 Android 10(API 级别 29)开始,Android 共享表单会显示正在共享的文本的预览。在某些情况下,正在共享的文本可能难以理解。考虑共享一个复杂的 URL,例如 https://www.google.com/search?ei=2rRVXcLkJajM0PEPoLy7oA4。更丰富的预览可以向您的用户保证正在共享的内容。

如果您正在预览文本,可以设置标题、缩略图图像或两者。在调用 Intent.createChooser() 之前,将描述添加到 Intent.EXTRA_TITLE,并使用 ClipData 添加相关的缩略图。

注意:图像内容 URI 来自 FileProvider,通常来自已配置的 <cache-path>。有关更多信息,请参阅 共享文件。请务必授予共享表单读取任何您想用作缩略图的图像的权限。有关更多信息,请参阅 Intent.FLAG_GRANT_READ_URI_PERMISSION

这是一个示例

Kotlin

 val share = Intent.createChooser(Intent().apply {
      action = Intent.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 = contentUri
      flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
  }, null)
  startActivity(share)

Java

Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/");

// (Optional) Here you're setting the title of the content
sendIntent.putExtra(Intent.EXTRA_TITLE, "Introducing content previews");

// (Optional) Here you're passing a content URI to an image to be displayed
sendIntent.setData(contentUri);
sendIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// Show the Sharesheet
startActivity(Intent.createChooser(sendIntent, null));

预览看起来像这样

向共享表单添加自定义操作

Android 共享表单上自定义操作的屏幕截图。

在 Android 14(API 级别 34)及更高版本中,应用可以向 Android 共享表单添加自定义操作。自定义操作以 Android 共享表单顶部的较小操作图标的形式显示,应用可以指定任何 Intent 作为单击图标时调用的操作。

要向 Android 共享表单添加自定义操作,首先使用 ChooserAction.Builder 创建一个 ChooserAction。您可以指定一个 PendingIntent 作为单击图标时调用的操作。创建一个包含所有自定义操作的数组,并将其指定为共享 IntentEXTRA_CHOOSER_CUSTOM_ACTIONS

Kotlin

val sendIntent = Intent(Intent.ACTION_SEND)
    .setType("text/plain")
    .putExtra(Intent.EXTRA_TEXT, text)
val shareIntent = Intent.createChooser(sendIntent, null)
val customActions = arrayOf(
    ChooserAction.Builder(
        Icon.createWithResource(context, R.drawable.ic_custom_action),
        "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)

Java

Intent sendIntent = new Intent(Intent.ACTION_SEND)
        .setType("text.plain")
        .putExtra(Intent.EXTRA_TEXT, text);
Intent shareIntent = Intent.createChooser(sendIntent, null);
ChooserAction[] actions = new ChooserAction[]{
        new ChooserAction.Builder(
                Icon.createWithResource(context, R.drawable.ic_custom_action),
                "Custom",
                PendingIntent.getBroadcast(
                        context,
                        1,
                        new Intent(Intent.ACTION_VIEW),
                        PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT
                )
        ).build()
};
shareIntent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, actions);
context.startActivity(shareIntent);

添加自定义目标

Android 共享表单允许您指定最多两个 ChooserTarget 对象,这些对象在共享快捷方式和从 ChooserTargetServices 加载的目标之前显示。您还可以指定最多两个指向活动的 Intent,这些活动在应用建议之前列出

在调用 Intent.createChooser() *之后*,将 Intent.EXTRA_CHOOSER_TARGETSIntent.EXTRA_INITIAL_INTENTS 添加到您的共享 Intent 中。

Kotlin

val share = Intent.createChooser(myShareIntent, null).apply {
    putExtra(Intent.EXTRA_CHOOSER_TARGETS, myChooserTargetArray)
    putExtra(Intent.EXTRA_INITIAL_INTENTS, myInitialIntentArray)
}

Java

Intent shareIntent = Intent.createChooser(sendIntent, null);
share.putExtra(Intent.EXTRA_CHOOSER_TARGETS, myChooserTargetArray);
share.putExtra(Intent.EXTRA_INITIAL_INTENTS, myInitialIntentArray);

谨慎使用此功能。您添加的每个自定义 IntentChooserTarget 都会减少系统建议的数量。我们通常不建议添加自定义目标。添加 Intent.EXTRA_INITIAL_INTENTS 的一个常见适当示例是为用户提供可以在共享内容上执行的其他操作。例如,用户共享图像,而 Intent.EXTRA_INITIAL_INTENTS 用于让他们改为发送链接。添加 Intent.EXTRA_CHOOSER_TARGETS 的一个常见适当示例是显示您的应用提供的相关人员或设备。

按组件排除特定目标

您可以通过提供 Intent.EXTRA_EXCLUDE_COMPONENTS 来排除特定目标。仅当要删除您控制的目标时才执行此操作。一个常见的用例是在用户从您的应用内部共享时隐藏您的应用的共享目标,因为他们的意图可能是共享到您的应用之外。

在调用 Intent.createChooser() 后,将 Intent.EXTRA_EXCLUDE_COMPONENTS 添加到您的 Intent 中。

Kotlin

  val share = Intent.createChooser(Intent(), null).apply {
    // Only use for components you have control over
    val excludedComponentNames = arrayOf(ComponentName("com.example.android", "ExampleClass"))
    putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames)
  }

Java

  Intent shareIntent = Intent.createChooser(new Intent(), null);
  // Only use for components you have control over
  ComponentName[] excludedComponentNames = {
          new ComponentName("com.example.android", "ExampleClass")
  };
  shareIntent.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames);

获取有关共享的信息

了解用户何时共享以及他们选择了什么目标可能很有用。Android 共享表单允许您通过使用 IntentSender 提供用户选择的目标的 ComponentName 来获取此信息。

首先为 BroadcastReceiver 创建一个 PendingIntent,并在 Intent.createChooser() 中提供其 IntentSender

Kotlin

var share = Intent(Intent.ACTION_SEND)
// ...
val pi = PendingIntent.getBroadcast(
    myContext, requestCode,
    Intent(myContext, MyBroadcastReceiver::class.java),
    PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
share = Intent.createChooser(share, null, pi.intentSender)

Java

Intent share = new Intent(ACTION_SEND);
...
PendingIntent pi = PendingIntent.getBroadcast(myContext, requestCode,
        new Intent(myContext, MyBroadcastReceiver.class),
        PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
share = Intent.createChooser(share, null, pi.getIntentSender());

MyBroadcastReceiver 中接收回调,并在 Intent.EXTRA_CHOSEN_COMPONENT 中查找

Kotlin

override fun onReceive(context: Context, intent: Intent) {
  ...
  val clickedComponent : ComponentName = intent.getParcelableExtra(EXTRA_CHOSEN_COMPONENT);
}

Java

@Override public void onReceive(Context context, Intent intent) {
  ...
  ComponentName clickedComponent = intent.getParcelableExtra(EXTRA_CHOSEN_COMPONENT);
}

向共享表单添加自定义操作

在 Android 14(API 级别 34)及更高版本中,应用可以向 Android 共享表单添加自定义操作。使用 ChooserAction.Builder 创建一个 ChooserAction。您可以指定一个 PendingIntent 作为单击图标时调用的操作。创建一个包含所有自定义操作的数组,并将其指定为共享 IntentEXTRA_CHOOSER_CUSTOM_ACTIONS

Kotlin

val sendIntent = Intent(Intent.ACTION_SEND)
    .setType("text/plain")
    .putExtra(Intent.EXTRA_TEXT, text)
val shareIntent = Intent.createChooser(sendIntent, null)
val customActions = arrayOf(
    ChooserAction.Builder(
        Icon.createWithResource(context, R.drawable.ic_custom_action),
        "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)

Java

Intent sendIntent = new Intent(Intent.ACTION_SEND)
        .setType("text.plain")
        .putExtra(Intent.EXTRA_TEXT, text);
Intent shareIntent = Intent.createChooser(sendIntent, null);
ChooserAction[] actions = new ChooserAction[]{
        new ChooserAction.Builder(
                Icon.createWithResource(context, R.drawable.ic_custom_action),
                "Custom",
                PendingIntent.getBroadcast(
                        context,
                        1,
                        new Intent(Intent.ACTION_VIEW),
                        PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT
                )
        ).build()
};
shareIntent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, actions);
context.startActivity(shareIntent);

使用 Android Intent 解析器

ACTION_SEND Intent 解析器的屏幕截图。

Android Intent 解析器最适合在将数据发送到另一个应用作为定义良好的任务流程的一部分时使用。

要使用 Android Intent 解析器,请创建一个 Intent 并添加额外信息,就像调用 Android 共享表单一样。但是,*不要*调用 Intent.createChooser()

如果有多个已安装的应用的过滤器与 ACTION_SEND 和 MIME 类型匹配,则系统会显示一个称为*Intent 解析器*的歧义对话框,允许用户选择一个共享目标。如果只有一个应用匹配,则会运行该应用。

以下是如何使用 Android Intent 解析器发送文本的示例

Kotlin

val sendIntent: Intent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
    type = "text/plain"
}
startActivity(sendIntent)

Java

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(sendIntent);

了解更多

有关发送数据的更多信息,请参阅 Intent 和 Intent 过滤器。