2011-05-20 76 views
21

在我的应用程序上,我向android developer的内部存储器写入文件。然后,我希望通过电子邮件将我写入内部存储器的文件发送给我。这里是我的代码和我得到的错误,任何帮助将不胜感激。来自内部存储器的电子邮件

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..")); 

和错误是

文件://附件路径必须指向文件:// MNT/SD卡。忽略附件文件:// ...

回答

1

错误足够具体:您应该使用external storage中的文件来创建附件。

+3

或者将'MODE_PRIVATE'改为'MODE_WORLD_READABLE'。由于您没有编写电子邮件程序,因此无法读取您的私人文件。 – CommonsWare 2011-05-20 13:53:42

+0

感谢您的回答。我可以阅读,但我开发的应用程序没有外部存储的手机,因为手机有32GB的内置存储。 – 2011-05-20 13:58:08

+0

然后使用@CommonsWare评论:MODE_WORLD_READABLE可以保存你。 – 2011-05-20 13:59:13

24

我想你可能在Android Gmail客户端发现了一个错误(至少是不必要的限制)。我能解决它,但它给我的印象太实现特定的,并且需要多一点的工作是便携式:

首先CommonsWare是非常正确的约需要使文件全局可读:

fos = openFileOutput(xmlFilename, MODE_WORLD_READABLE); 

接下来,我们需要解决Gmail的上的/ mnt/SD卡坚持路径(或执行特定等价?):

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

至少我修改的姜饼设备上,这让我的Gmail附件从私人存储到我自己,以及当我收到它时,使用预览按钮查看内容。但是我不觉得这么做会使它工作,以及谁知道其他版本的Gmail或其他电子邮件客户端或将电话挂载到其他地方的电话会发生什么。

+0

伟大的解决方法。解决了我的问题。谢谢。 – user1139880 2012-04-01 22:27:34

+0

请记住,这是直接克服一个特定目标程序的作者方面奇怪的期望的黑客行为。今天,我们应该考虑查看内容提供者和其他类似的方法,这些答案在风格上更具有特征性的“Android”,并且希望在实用性方面更为普遍。 – 2015-05-29 15:08:07

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)); 
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; } 
} 

不是建立在内部缓存文件:

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文件登记内容提供商:

<provider android:name="CachedFileProvider" android:authorities="com.yourpackage.gmailattach.provider"></provider> 
+1

不要忘记向提供者添加'android:grantUriPermissions =“true”'。 – 2014-10-17 00:32:00

+1

工作很好,谢谢! – ToddH 2014-10-20 19:54:32

1

如果你打算使用内部存储,尝试使用的确切存储路径:

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

或附加不断变化的文件名,然后在每个文件上直接调用“new File(blah).exists()”以快速查看文件的确切名称。

它也可能是一个特定于您的设备的实际设备实现问题。你有没有尝试过使用其他设备/模拟器?

5
File.setReadable(true, false); 

为我工作。

+0

只要将创建URI的File对象设置为可读,我就可以使用Gmail通过FileProvider从内部存储设备发送文件 – joates 2014-08-01 13:53:22

+0

使用Gmail为我工作,但与Android上的其他邮件应用程序(如邮箱)无关。我认为下面far.be的内容提供商解决方案是最“正确”的方法。 – ToddH 2014-10-20 19:41:11

+0

内容提供者确实是Android架构中用于公开私有文件的*预期*解决方案。 – 2015-05-29 14:56:23

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> 
    ... 

元数据应说明在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> 

的路径是空的,当你使用内部文件的文件夹,但如果更多的大致位置(我们现在谈论的内部存储路径),你应该使用其他路径。您编写的名称将用于内容提供商提供给该文件的网址。从RES/XML/file_paths.xml元数据的路径

Uri contentUri = FileProvider.getUriForFile(context, "com.yourdomain.yourapp.fileprovider", file); 
上的任何文件

,现在,你可以简单地通过生成一个新的,世界可读的URL。

,现在只需使用:

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的模拟器上测试过它。

+1

似乎很好地工作。我见过的最令人头痛的解决方案是迄今为止我遇到的这个(真正烦人的)问题。 – 2016-05-07 19:44:24

相关问题