Android意图选择器如何只显示电子邮件选项

27

我的应用程序集成了电子邮件功能,用户可以直接从应用中提交错误报告、反馈等。 我使用 application/octet-stream 作为 Intent 的 SetType。 当您尝试提交电子邮件时,会弹出内容选择器并显示来自 Evernote、Facebook、电子邮件等的各种选项。

我该如何让这个选择器仅显示电子邮件,以避免让用户看到与内容选择器类型不符的其他选项,从而混淆用户?

谢谢。


1
你是否按照这里所示的方式添加了所有的附加项:https://dev59.com/T3I95IYBdhLWcg3wsQFm#2197841? - Aleadam
是的,我确实做到了。它可以工作并发送电子邮件。我只是试图删除内容选择器显示的所有杂乱无章的东西。我只想显示“电子邮件”或与电子邮件相关的程序。我不确定为什么会出现所有这些其他选项,我猜测是因为它们可以处理应用程序/八位字节流类型。 - Neal
你可能会遇到message/rfc822相同的问题吗? - Jasoon
请看这个问题https://dev59.com/UGoy5IYBdhLWcg3wN7YX - dira
10个回答

41

要解决此问题,只需遵循官方文档即可。最重要的考虑因素是:

  1. 标志为ACTION_SENDTO,而不是ACTION_SEND

  2. 意图的setData方法,

    intent.setData(Uri.parse("mailto:")); // 仅电子邮件应用程序应处理此项

如果发送空的Extra,则结尾处的if()将无法工作,应用程序将无法启动电子邮件客户端。

这对我有用。根据Android文档,如果您想确保您的意图仅由电子邮件应用程序(而不是其他短信或社交应用程序)处理,则使用ACTION_SENDTO操作并包括"mailto:"数据方案。例如:

public void composeEmail(String[] addresses, String subject) {
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:")); // only email apps should handle this
    intent.putExtra(Intent.EXTRA_EMAIL, addresses);
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

https://developer.android.com/guide/components/intents-common.html#Email

https://developer.android.com/guide/components/intents-common.html#Email

很抱歉附件的问题。我不确定如何实现它。我猜这些功能只能通过意图分享文本。 - Pedro Varela

14

我假设您正在使用 ACTION_SEND Intent 操作,因为您没有详细说明您正在使用什么,但您同意了 @Aleadam 的评论。

我将 application/octet-stream 用作 Intent 的 SetType。

该句中没有限制事物只能用于电子邮件。

ACTION_SEND 是一个通用的 Intent 操作,可以由任何希望支持它的应用程序支持。你所要做的就是指示你要共享的数据和该数据的 MIME 类型-接下来,用户就可以从可用的活动中进行选择。

当 @Jasoon 指出时,你可以尝试使用 message/rfc822 作为 MIME 类型。然而,这并不表示"只提供电子邮件客户端"-它表示"提供任何支持 message/rfc822 数据"。这很可能包括一些不是电子邮件客户端的应用程序。

如果你特别想通过电子邮件发送某些东西,那么请将 JavaMail 集成到你的应用程序中,或者在你的 Web 服务器上编写一个电子邮件转发脚本并调用它。如果你使用 ACTION_SEND,那么你默认认为用户想要什么很重要,你希望用户能够通过用户选择的任何方式发送这样和这样的数据。


12

在实现“魔法链接”功能时,我遇到了一个问题,即为所有已安装的电子邮件应用程序创建选择器意图:

选择器意图截图

private void openEmailApp() {
  List<Intent> emailAppLauncherIntents = new ArrayList<>();

  //Intent that only email apps can handle:
  Intent emailAppIntent = new Intent(Intent.ACTION_SENDTO);
  emailAppIntent.setData(Uri.parse("mailto:"));
  emailAppIntent.putExtra(Intent.EXTRA_EMAIL, "");
  emailAppIntent.putExtra(Intent.EXTRA_SUBJECT, "");

  PackageManager packageManager = getPackageManager();

  //All installed apps that can handle email intent:
  List<ResolveInfo> emailApps = packageManager.queryIntentActivities(emailAppIntent, PackageManager.MATCH_ALL);

  for (ResolveInfo resolveInfo : emailApps) {
    String packageName = resolveInfo.activityInfo.packageName;
    Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
    emailAppLauncherIntents.add(launchIntent);
  }

  //Create chooser
  Intent chooserIntent = Intent.createChooser(new Intent(), "Select email app:");
  chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, emailAppLauncherIntents.toArray(new Parcelable[emailAppLauncherIntents.size()]));
  startActivity(chooserIntent);
}

我也正在实现魔术链接功能,我只想展示选择器以显示所有电子邮件客户端,然后只查看收件箱。大多数提到的解决方案都是发送电子邮件。你的解决方案完美地适用于我的用例,谢谢! - user2622786
当我触发意图时,遇到了一个问题,没有获取到任何电子邮件启动器应用程序。我有Gmail应用和Outlook。 - Pravin Fofariya
在这里,PackageManager.MATCH_ALL 可能会误导。我认为这将禁用操作系统自动执行的任何结果过滤(可能是通过用户设置)。这可能不是您想要的。标准的 PackageManager.MATCH_DEFAULT_ONLY 在某些情况下可能更合适。 - Acadian_Ghost
我一直在寻找解决这个问题的方法,因为我看到的所有其他答案都只是打开Gmail。这个解决方案也适用于让Outlook显示。谢谢你,互联网上的朋友! - Poliziano

2

2

Kotlin答案

如果您需要仅显示电子邮件应用程序,然后您想要仅打开收件箱不是打开新的电子邮件撰写),则需要执行A和B:

A)由于{{link1:Android 11的软件包可见性更新}},请在Android 11中的AndroidManifest.xml文件中添加以下代码:

<queries>
    <intent>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
    </intent>
    <intent>
        <action android:name="android.intent.action.CHOOSER" />
    </intent>
</queries>

B) 使用以下函数显示电子邮件选择器:

// Show email app list.
fun showEmailAppList() {

    // Email app list.
    val emailAppLauncherIntents: MutableList<Intent?> = ArrayList()

    // Create intent which can handle only by email apps.
    val emailAppIntent = Intent(Intent.ACTION_SENDTO)
    emailAppIntent.data = Uri.parse("mailto:")

    // Find from all installed apps that can handle email intent and check version. 
    val emailApps = packageManager.queryIntentActivities(
        emailAppIntent,
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) 0 else PackageManager.MATCH_ALL
    )

    // Collect email apps and put in intent list.
    for (resolveInfo in emailApps) {
        val packageName = resolveInfo.activityInfo.packageName
        val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
        emailAppLauncherIntents.add(launchIntent)
    }

    // Create chooser with created intent list to show email apps of device.
    val chooserIntent = Intent.createChooser(Intent(), "OPEN EMAIL APP")
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, emailAppLauncherIntents.toTypedArray())
    startActivity(chooserIntent)
}

结果:

Show only email apps


在Android 12上,选择器不显示标题,且在选择器中不显示超过2个应用程序。这两个问题都被记录为“不修复”(意图行为):https://issuetracker.google.com/issues/134367295 - mtrakal

0

可以将意图选择器的选项限制为仅几个选项。 此问题的答案 中的代码是一个很好的例子。实质上,您需要创建一个 LabeledIntents 列表,提供给意图选择器,然后将其包含在列表中。请注意,此解决方案不是通过排除(某些应用程序被排除,而其余应用程序保留),而是您必须选择要显示哪些应用程序。希望能有所帮助!


0

它适用于所有设备。它只会显示电子邮件应用程序。

public static void shareViaMail(Activity activity, String title, String body, String filePath) {

    Uri URI = Uri.parse("file://" + filePath);
    final Intent emailIntent = new Intent(Intent.ACTION_VIEW);

    emailIntent.setData(Uri.parse("mailto:"));

    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{"contact@brightsociety.com"});

    if (URI != null) {
        emailIntent.putExtra(Intent.EXTRA_STREAM, URI);
    }
    try {
        activity.startActivity(emailIntent);
    } catch (Exception e) {
        ((BaseActivity) activity).showToast("Gmail App is not installed");
        e.printStackTrace();
    }
}

-1

经过大量的搜索和测试,我终于找到了一个完美的解决方案。感谢开源开发者cketti分享他/她简洁而整洁的解决方案。

String mailto = "mailto:bob@example.org" +
    "?cc=" + "alice@example.com" +
    "&subject=" + Uri.encode(subject) +
    "&body=" + Uri.encode(bodyText);

Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse(mailto));

try {
  startActivity(emailIntent);
} catch (ActivityNotFoundException e) {
  //TODO: Handle case where no email app is available
}

这是他/她的代码片段链接:this


-1

解决方案非常简单:

Intent testIntent = new Intent(Intent.ACTION_VIEW);  
Uri data = Uri.parse("mailto:?subject=" + "blah blah subject" + "&body=" + "blah blah body" + "&to=" + "sendme@me.com");  
testIntent.setData(data);  
startActivity(testIntent);  

请参见:http://www.gaanza.com/blog/email-client-intent-android/


-1

它可以在所有设备上运行。它只会显示电子邮件应用程序。

public static void shareViaMail(Activity activity, String title, String body, String filePath) {
        Uri URI = Uri.parse("file://" + filePath);
        final Intent emailIntent = new Intent(Intent.ACTION_VIEW);
        emailIntent.setData(Uri.parse("mailto:"));
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{"xyz@gmail.com"});
        /*if you want to attach something*/
        if (URI != null) {
            emailIntent.putExtra(Intent.EXTRA_STREAM, URI);
        }
        try {
            activity.startActivity(emailIntent);
        } catch (Exception e) {
            ((BaseActivity) activity).showToast("Gmail App is not installed");
            e.printStackTrace();
        }
}

这个代码可以在选择器中显示电子邮件应用程序,但它没有将附件添加到邮件中。 - Chintak Patel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接