来自内部存储的电子邮件

2022-09-02 00:26:05

在我的应用程序上,我将一个文件写入内部存储,如Android开发人员所涵盖的那样。然后,我希望通过电子邮件将我写入的内部存储中的文件。这是我的代码和我得到的错误,任何帮助将不胜感激。

FileOutputStream fos = openFileOutput(xmlFilename, MODE_PRIVATE);
fos.write(xml.getBytes());
fos.close();
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("text/plain");
...
Uri uri = Uri.fromFile(new File(xmlFilename));
intent.putExtra(android.content.Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "Send eMail.."));

错误是

file:// 附件路径必须指向 file://mnt/sdcard。忽略依恋 file://...


答案 1

我想您可能已经在Android Gmail客户端中发现了一个错误(或至少是不必要的限制)。我能够解决它,但它给我的印象是过于特定于实现,并且需要更多的工作才能实现可移植性:

First CommonsWare关于需要使文件世界可读是非常正确的:

fos = openFileOutput(xmlFilename, MODE_WORLD_READABLE);

接下来,我们需要解决 Gmail 对 /mnt/sdcard(或特定于实现的等效项?)路径的坚持:

Uri uri = Uri.fromFile(new File("/mnt/sdcard/../.."+getFilesDir()+"/"+xmlFilename));

至少在我修改过的姜饼设备上,这让我从私人存储中Gmail一个附件给自己,并在收到时使用预览按钮查看内容。但是,对于必须这样做才能使其正常工作,我并不觉得很“好”,谁知道另一个版本的Gmail或其他电子邮件客户端或在其他地方安装外部存储的手机会发生什么。


答案 2

我最近一直在努力解决这个问题,我想分享我从支持库中使用FileProvider找到的解决方案。它是内容提供商的扩展,无需解决即可很好地解决此问题,并且没有太多的工作。

如链接中所述,要激活内容提供程序:在清单中,请写下:

<application
    ....
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.youdomain.yourapp.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    ...

元数据应该指示 res/xml 文件夹中的 xml 文件(我将其命名为file_paths.xml):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path path="" name="document"/>
</paths>

当您使用内部文件文件夹时,路径为空,但是如果对于更一般的位置(我们现在谈论的是内部存储路径),则应使用其他路径。您编写的名称将用于内容提供商提供给文件的 URL。

现在,您只需使用以下命令即可生成一个新的,世界可读的URL:

Uri contentUri = FileProvider.getUriForFile(context, "com.yourdomain.yourapp.fileprovider", file);

来自 res/xml/file_paths.xml 元数据中路径的任何文件。

现在只需使用:

    Intent mailIntent = new Intent(Intent.ACTION_SEND);
    mailIntent.setType("message/rfc822");
    mailIntent.putExtra(Intent.EXTRA_EMAIL, recipients);

    mailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
    mailIntent.putExtra(Intent.EXTRA_TEXT, body);
    mailIntent.putExtra(Intent.EXTRA_STREAM, contentUri);

    try {
        startActivity(Intent.createChooser(mailIntent, "Send email.."));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(this, R.string.Message_No_Email_Service, Toast.LENGTH_SHORT).show();
    }

您不需要授予权限,当您将URL附加到文件时,会自动执行此操作。

并且您不需要使您的文件MODE_WORLD_READABLE,此模式现已弃用,使其MODE_PRIVATE,内容提供商为其他应用程序可访问的同一文件创建新的URL。

我应该注意,我只是在带有Gmail的模拟器上测试了它。


推荐