繁体   English   中英

内部存储电子邮件

[英]Email from internal storage

在我的应用程序中,我将文件写入内部存储,如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。 忽略附件文件:// ...

我想您可能在Android Gmail客户端中发现了一个错误(或至少是不必要的限制)。 我能够解决它,但它对我来说太具体了,并且还需要更多工作才能实现:

First CommonsWare非常正确,需要使文件可读:

fos = openFileOutput(xmlFilename, MODE_WORLD_READABLE);

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

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

至少在我修改过的Gingerbread设备上,这是让我从私人存储到我自己的Gmail附件,并在收到时使用预览按钮查看内容。 但是我不觉得必须这样做才能使它工作,并且知道在其他版本的Gmail或其他电子邮件客户端或在其他地方安装外部存储的手机会发生什么情况。

我最近一直在努力解决这个问题,我想在支持库中使用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的模拟器上进行了测试。

Chris Stratton提出了很好的解决方法。 然而,它在许多设备上失败了。 你不应该硬编码/ mnt / sdcard路径。 你最好计算它:

String sdCard = Environment.getExternalStorageDirectory().getAbsolutePath();
Uri uri = Uri.fromFile(new File(sdCard + 
          new String(new char[sdCard.replaceAll("[^/]", "").length()])
                    .replace("\0", "/..") + getFilesDir() + "/" + xmlFilename));

考虑到这里的建议: http//developer.android.com/reference/android/content/Context.html#MODE_WORLD_READABLE ,因为API 17我们被鼓励使用ContentProviders等。感谢那个家伙和他的帖子http: //stephendnicholas.com/archives/974我们有一个解决方案:

public class CachedFileProvider extends ContentProvider {
public static final String AUTHORITY = "com.yourpackage.gmailattach.provider";
private UriMatcher uriMatcher;
@Override
public boolean onCreate() {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(AUTHORITY, "*", 1);
    return true;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    switch (uriMatcher.match(uri)) {
        case 1:// If it returns 1 - then it matches the Uri defined in onCreate
            String fileLocation = AppCore.context().getCacheDir() + File.separator +     uri.getLastPathSegment();
            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation),     ParcelFileDescriptor.MODE_READ_ONLY);
            return pfd;
        default:// Otherwise unrecognised Uri
            throw new FileNotFoundException("Unsupported uri: " + uri.toString());
    }
}
@Override public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { return     0; }
@Override public int delete(Uri uri, String s, String[] as) { return 0; }
@Override public Uri insert(Uri uri, ContentValues contentvalues) { return null; }
@Override public String getType(Uri uri) { return null; }
@Override public Cursor query(Uri uri, String[] projection, String s, String[] as1, String s1) {     return null; }
}

在内部缓存中创建文件:

    File tempDir = getContext().getCacheDir();
    File tempFile = File.createTempFile("your_file", ".txt", tempDir);
    fout = new FileOutputStream(tempFile);
    fout.write(bytes);
    fout.close();

设置意图:

...
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/" + tempFile.getName()));

并在AndroidManifest文件中注册Content provider:

<provider android:name="CachedFileProvider" android:authorities="com.yourpackage.gmailattach.provider"></provider>
File.setReadable(true, false);

为我工作。

如果要使用内部存储,请尝试使用确切的存储路径:

Uri uri = Uri.fromFile(new File(context.getFilesDir() + File.separator + xmlFilename));

或者另外继续在调试器中更改文件名,并在每个文件上调用“new File(blah).exists()”以快速查看文件的确切名称

它也可能是您设备特有的实际设备实施问题。 你尝试过使用其他设备/模拟器吗?

该错误是特定的:您应该使用外部存储中的文件来生成附件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM