内部存储电子邮件

Mr *_*son 21 java email android

在我的应用程序中,我将文件写入内部存储,如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.."));
Run Code Online (Sandbox Code Playgroud)

错误是

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

Chr*_*ton 24

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

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

fos = openFileOutput(xmlFilename, MODE_WORLD_READABLE);
Run Code Online (Sandbox Code Playgroud)

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

Uri uri = Uri.fromFile(new File("/mnt/sdcard/../.."+getFilesDir()+"/"+xmlFilename));
Run Code Online (Sandbox Code Playgroud)

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


小智 11

我最近一直在努力解决这个问题,我想在支持库中使用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>
    ...
Run Code Online (Sandbox Code Playgroud)

元数据应该指示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>
Run Code Online (Sandbox Code Playgroud)

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

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

Uri contentUri = FileProvider.getUriForFile(context, "com.yourdomain.yourapp.fileprovider", file);
Run Code Online (Sandbox Code Playgroud)

来自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();
    }
Run Code Online (Sandbox Code Playgroud)

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

并且您不需要将文件设置为MODE_WORLD_READABLE,现在不推荐使用此模式,使其成为MODE_PRIVATE,内容提供程序会为其他应用程序可访问的同一文件创建新URL.

我应该注意,我只在使用Gmail的模拟器上进行了测试.


Dmi*_*hin 7

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));
Run Code Online (Sandbox Code Playgroud)


far*_*.be 5

考虑到这里的建议: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; }
}
Run Code Online (Sandbox Code Playgroud)

在内部缓存中创建文件:

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

设置意图:

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

并在AndroidManifest文件中注册Content provider:

<provider android:name="CachedFileProvider" android:authorities="com.yourpackage.gmailattach.provider"></provider>
Run Code Online (Sandbox Code Playgroud)


Rob*_*bin 5

File.setReadable(true, false);
Run Code Online (Sandbox Code Playgroud)

为我工作.


Vla*_*nov 1

该错误非常具体:您应该使用外部存储中的文件来制作附件。

  • 或者将“MODE_PRIVATE”更改为“MODE_WORLD_READABLE”。由于您没有编写电子邮件程序,因此它无法读取您的私人文件。 (3认同)
  • @Mr Jackson:“一部没有外部存储的手机,因为手机有 32GB 内置存储”——您的设备有外部存储。“外部存储”并不意味着“SD 卡”,它意味着“可从主机 PC 访问”。“File() 构造函数不处理权限”——如果您遵循我之前评论的第一句话中的非常简单的说明(“或将`MODE_PRIVATE`更改为`MODE_WORLD_READABLE`”),则不必这样做。 (2认同)
  • 甚至尝试 get Uri uri = Uri.fromFile(FileStreamPath(xmlFilename)) 但仍然不好。 (2认同)