将 (new Intent(Intent.ACTION_SENDTO)).setData(Uri.parse("mailto:") 传递给 intent.setSelector() 在选择器列表中显示自己的应用程序

Passing (new Intent(Intent.ACTION_SENDTO)).setData(Uri.parse("mailto:") to intent.setSelector() shows own app in selector list

基于this post,我正在打开一个电子邮件客户端发送多个附件,代码如下:

Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
emailSelectorIntent.setData(Uri.parse("mailto:"));

Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.putExtra(Intent.EXTRA_EMAIL, addresses);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);

ArrayList<Uri> uriList = new ArrayList<>();
uriList.add(FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", fileA));
uriList.add(FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", fileB));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, uriList);

intent.setSelector(emailSelectorIntent);

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

请注意,如上面链接 post 中所述,我需要两个 Intents 才能发送附件(并将选择器限制为仅电子邮件客户端)... emailSelectorIntentintent,前者通过 intent.setSelector(emailSelectorIntent).

传递给后者

为了打开选择器,我的清单中还需要以下内容:

<intent-filter>
    <action android:name="android.intent.action.SENDTO" />
    <data android:scheme="mailto" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

But when the selector opens, not only do I get email clients showing (e.g. gmail) I am also getting my own app in the list... which is not capable of sending emails.

建议 不要 android.intent.action.SENDTO 放在清单中,但如果我删除它,则选择器根本不再打开。如果放回去,选择器会打开,但会使用我自己的应用程序作为电子邮件客户端的选项(它不是)。

那么在这种情况下如何避免我自己的应用出现在选择器列表中?

请注意,我的 targetSdk32 以防相关,它可能是相关的(请参阅@CommonsWare here 的评论)。

我有点困惑,<intent-filter> 改变了一切。无论如何,您真的不希望出现这种情况,因为它会导致其他应用将 ACTION_SENDTO 请求路由到您不希望的应用。

without android.intent.action.SENDTO in the Manifest, startActivity() is never called because the test intent.resolveActivity(getPackageManager()) != null fails

那是由于 package visibility rules。您的选择是添加 <queries> 表示您需要查看谁都支持您的 Intent,或者将 resolveActivity() 调用替换为 try/catch:

try {
    startActivity(intent);
} catch (Exception e) {
    // whatever you want to do to gracefully degrade in case there is no suitable activity to start
}

not sure how this will work on older versions of Android?

<queries> 将在旧版本的 Android 上被忽略,但包可见性在旧版本的 Android 上不是问题。我个人更喜欢try/catch,因为它处理的场景更多。

(一如既往)非常务实且内容丰富。我想我也更喜欢那里提出的 try/catch 解决方案,并将采用它。但是,保留 resolveActivity() 检查并在 Manifest 的顶层添加 <queries> 项目的替代方案也有效,如下所示:

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