将简单的数据发送给其他应用

Android 通过 intent 及其关联的 extra 让用户可以使用他们喜爱的应用快速轻松地分享信息。

Android 为用户提供了两种在应用之间分享数据的方式:

  • Android Sharesheet 主要用于将内容发送到应用外部和/或直接发送给其他用户。例如,将网址分享给朋友。
  • Android intent 解析器最适合将数据传递到明确定义的任务的下一个阶段。例如,从应用中打开 PDF,并让用户挑选他们首选的查看器。

构造 intent 时,您必须指定希望该 intent 执行的操作。Android 使用 ACTION_SEND 操作将数据从一个 Activity 发送到另一个 Activity,甚至跨进程界限发送数据。您需要指定数据及其类型。系统会自动识别可以接收数据的兼容 Activity 并将其显示给用户。对于 intent 解析器,如果只有一个 Activity 可以处理相应 intent,该 Activity 将立即启动。

为什么应使用 Android Sharesheet

我们强烈建议您使用 Android Sharesheet 在各个应用之间为您的用户打造一致的体验。应用不应显示它们自己的分享目标列表或创建它们自己的 Sharesheet 变体。

借助 Android Sharesheet,用户只需点按一下,即可根据相关的应用推荐,与合适的人员分享信息。Sharesheet 可以推荐自定义解决方案不可用的目标,并且提供一致的排名。这是因为,Sharesheet 可以考虑到只有系统了解的应用和用户 Activity 的相关信息。

Android Sharesheet 还为开发者提供了许多方便的功能。例如,您可以:

使用 Android Sharesheet

对于所有类型的分享,创建一个 intent 并将其操作设为 Intent.ACTION_SEND。为了显示 Android Sharesheet,您需要调用 Intent.createChooser(),并向其传递您的 Intent 对象。它会返回您的 intent 的一个版本,该版本将始终显示 Android Sharesheet。

发送文本内容

Android Sharesheet 最直接也是最常见的用法是将文本内容从一个 Activity 发送到另一个 Activity。例如,大多数浏览器都可以将当前显示的网页的网址以文本形式与另一个应用分享。这对于通过电子邮件或社交网络与朋友分享文章或网站很有用。下面举例说明如何执行此操作:

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 以包含更多信息,如电子邮件收件人(EXTRA_EMAILEXTRA_CCEXTRA_BCC)、电子邮件主题 (EXTRA_SUBJECT),等等。

注意:某些电子邮件应用(如 Gmail)要求以 String[] 的形式表示诸如 EXTRA_EMAILEXTRA_CC 之类的 extra,请使用 putExtra(String, String[]) 将此类 extra 添加到您的 intent 中。

发送二进制内容

您可以使用 ACTION_SEND 操作分享二进制数据。应设置适当的 MIME 类型,并在 extra EXTRA_STREAM 中添加数据的 URI。这通常用于分享图片,但可以用于分享任何类型的二进制内容:

Kotlin

    val shareIntent: Intent = Intent().apply {
        action = Intent.ACTION_SEND
        putExtra(Intent.EXTRA_STREAM, uriToImage)
        type = "image/jpeg"
    }
    startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
    

Java

    Intent shareIntent = new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
    shareIntent.setType("image/jpeg");
    startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));
    

接收应用需要具备相应的权限才能访问 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/plaintext/rtftext/htmltext/json,接收方应注册 text/*
  • image/jpgimage/pngimage/gif,接收方应注册 image/*
  • video/mp4video/3gp,接收方应注册 video/*
  • application/pdf,接收方应注册支持的文件扩展名
  • 您可以使用 MIME 类型 */*,但强烈建议您不要这样做,因为它仅与能够处理通用数据流的 Activity 匹配。

Android Sharesheet 可能会根据提供的 MIME 类型显示内容预览。某些预览功能仅适用于特定类型。

请参阅 MIME 媒体类型的 IANA 官方注册表。

分享多份内容

要分享多份内容,请将 ACTION_SEND_MULTIPLE 操作与指向该内容的一系列 URI 一起使用。MIME 类型因您所分享的混合内容而有所不同。例如,如果您分享三张 JPEG 图片,则类型仍为 "image/jpg"。但如果分享混合类型的图片,则类型应为 "image/*",以与处理任何类型的图片的 Activity 匹配。虽然可以分享混合类型的内容,但强烈建议您不要这样做,因为接收方不清楚对方想要发送什么。如果需要发送多种类型的内容,请使用 "*/*"。由接收应用解析和处理数据。示例如下:

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, "Share images to.."))
    

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, "Share images to.."));
    

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

向文本预览添加丰富的内容

从 Android 10(API 级别 29)开始,Android Sharesheet 可以显示分享的文本的预览。在某些情况下,分享的文本可能难以理解。假设分享一个复杂的网址,比如 https://www.google.com/search?ei=2rRVXcLkJajM0PEPoLy7oA4。更丰富的预览可以让用户放心,让他们明白分享的是什么。

如果要预览文本,您可以设置标题和/或缩略图。在调用 Intent.createChooser() 之前,先添加 Intent.EXTRA_TITLE 的说明。通过 ClipData 添加相关的缩略图。

注意:图片内容 URI 应该通过 FileProvider(通常来自配置的 <cache-path>)提供。请参阅分享文件。确保授予 Sharesheet 正确的权限,让其能够读取要用作缩略图的任何图片。请参阅 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 we're setting the title of the content
          putExtra(Intent.EXTRA_TITLE, "Introducing content previews")

          // (Optional) Here we're passing a content URI to an image to be displayed
          setClipData(contentUri);
          setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      }, null)
      startActivity(share)
    

Java

    Intent sendIntent = new Intent(Intent.ACTION_SEND);
    sendIntent.putExtra(Intent.EXTRA_TEXT, "Hello!");

    // (Optional) Here we're setting the title of the content
    sendIntent.putExtra(Intent.EXTRA_TITLE, "Send message");

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

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

预览如下所示:

添加自定义目标

通过 Android Sharesheet,您可以指定有限数量的 ChooserTarget 对象,在分享快捷方式和通过 ChooserTargetServices 加载的 ChooserTarget 之前显示。此外,您还可以指定有限数量的 intent,它们指向在应用推荐之前列出的 Activity。

在调用 Intent.createChooser() 之后,向您的分享 intent 添加 Intent.EXTRA_CHOOSER_TARGETSIntent.EXTRA_INITIAL_INTENTS

Kotlin

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

Java

    val share = Intent.createChooser(myShareIntent, 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 添加 Intent.EXTRA_EXCLUDE_COMPONENTS

Kotlin

    val share = Intent.createChooser(myShareIntent, null).apply {
      // Only use components you have control over
      share.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, myComponentArray)
    }
    

Java

    share = Intent.createChooser(myShareIntent, null);
    // Only use components you have control over
    share.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, myComponentArray);
    

获取有关分享的信息

了解用户何时分享以及他们选择了什么目标可能很有用。为此,Android Sharesheet 通过 IntentSender 提供用户点击的目标的 ComponentName

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

Kotlin

    var share = new Intent(Intent.ACTION_SEND);
    ...
    val pi = PendingIntent.getBroadcast(myContext, requestCode, Intent(myContext, MyBroadcastReceiver.class),
    Intent.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),
                    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 intent 解析器

ACTION_SEND intent 解析器的屏幕截图。

在明确定义的任务流中将数据发送到另一个应用时,使用 Android intent 解析器最为合适。

要使用 Android intent 解析器,请创建一个 intent 并添加 extra,就像调用 Android Sharesheet 时执行的操作一样。不过,请勿调用 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 过滤器